https://youtu.be/gh73EEzhUe0
今回は The Basics
の 型安全と型推論
について眺めていきます。Swift の主要なコンセプトとも言える機能で、表側からも内側からも言語を精密に支える巨大なものになりますけれど、ここではその概要的なところを見ていくことになりそうです。どうぞよろしくお願いしますね。
————————————————————————————————— 熊谷さんのやさしい Swift 勉強会 #114
00:00 開始 00:51 Swift のコンセプト 01:49 型安全 02:33 昔からの言語に型安全という言葉を当てる違和感 03:38 型安全と型システム 05:32 未定義の動作 07:46 デリファレンス 09:30 型安全性とは 11:47 言語による型安全のサポート 13:36 コンパイル時にエラーを検出 15:42 整数範囲の静的チェック 16:51 独自の型でコンパイル時にオーバーフローチェックは可能? 19:17 リテラルで初期化した値を用いた条件分岐 24:32 警告とエラー 27:37 型チェックと型推論 29:30 型推論 36:31 型の存在が消えるわけではない —————————————————————————————————
Transcription & Summarize : 熊谷さんのやさしい Swift 勉強会 #114
今日は、セクションの新しいパートに入っていきます。「ザ・ベーシックス」という難しくない内容ですから、適当なところでやってみますね。まず、Swiftの大事な特徴について話しましょう。Swiftが登場したときに掲げられたのは主に三つで、「ファスト」「セーフ」「モダン」と「インタラクティブ」でした。最初は四つと言われていましたが、途中で三つに変わったことがあります。この話も以前の勉強会で触れましたので、過去の動画を見ていただければと思います。
さて、Swiftが出た当初から注目されていたのが「セーフ」です。これがSwiftの大事な特徴で、プログラムの安全性を確保するために重要な要素です。Swiftが登場した約10年前、そのころの他の言語、たとえばC言語もセーフな部分がありましたが、Swiftはさらに強力です。C++もセーフに関して言えば、ある程度参考になりますが、パターンデザインの言語というわけではありません。Swiftとは少し違いますね。
「セーフ」とは、プログラムの安全性を確保するため未定義の状態に陥らないようにすることです。CやC++では、ヌルポインタの参照やバッファオーバーランクなど、未定義の動作を引き起こす可能性があります。これに対して、Swiftではそういった未定義の状態を防止するための仕組みがしっかりしています。
さらに、プログラマーがエラーを見つけた場合には、即座にプログラムを止める、または判断を仰ぐといった機能もあります。これにより、安全性が高く保たれているわけです。たとえば、参照する(リファレンス)という概念も重要で、オブジェクトを参照する際の仕組みが安全性を保つ鍵となります。
クラスやオブジェクトがあり、それぞれのオブジェクトがインスタンスを参照することをリファレンスといいます。この時、ヌルポイントなどがあるとリファレンス時にエラーが発生する可能性がありますが、Swiftはこの部分の安全性を高める設計になっています。
その結果、「型システム」という概念が浮上してきます。型システムはプログラミング言語が型を利用して安全性を保つための仕組みであり、C言語のような古い言語から存在していますが、Swiftの型システムは特に強力ですね。そして、安全性(安全なプログラム)は常に重要視されています。
ここで、「カタシステム」と「パターンデザイン」についても触れておきましょう。カタシステムは数の構成要素に型を適用して安全性を高めるもので、パターンデザインは設計パターンのことを指します。たとえば、メモリアンゼン(メモリの安全性)という言葉もありますが、これはCやC++でヌルポイント参照を防止したりすることに関連しています。
ということで、「セーフ」は未定義の状態を許さないことで、またエラーが発生した場合には即座に対処することで保たれています。これがSwiftの特徴であり、プログラマーが安心して開発できる環境を提供する要因です。
さて、ここまでの理論を踏まえつつ、具体的なコードや実践的な使い方についても次回以降のセッションで触れていきますので、引き続きお付き合いください。 まず「ターンゼン」は、型を明確に用意して、それが不正に利用されないようにする仕組みのことを指しています。かつてはこうした型システムを強く押し出しているプログラミング言語は少なかったですが、現在では新しく登場する言語の多くがこの型システムを取り入れています。最近の言語や教材でも、型システムが重要なテーマとして扱われています。
例えば、Googleが開発した「Go言語」も、型システムをしっかりと取り入れており、それによってより効率的にプログラムを記述できるようになります。また、型システムが主流になっていることから、現在では「型システム」と聞けば、多くの人が理解できる状況になっています。
具体的な例を挙げると、文字列(String)が要求されるところに間違って整数(Int)を渡さないようにする、といったことが型システムによって実現されています。昔からこうした型システムの話はありましたが、現在の言語ではより重要な部分として組み込まれています。
コンパイル時に型チェックが行われ、間違った型が使用されているとエラーとして検出されるのも大きな特徴です。これは、静的型付けのプログラミング言語において、エラーを早期に発見し修正できるという利点があります。Swiftもその一例です。
一方で、Objective-Cのような言語では、静的型チェックはコンパイラーレベルで行いますが、実行時にエラーを検出する柔軟性もあります。しかし、その場合、コードを実行してみないと見つからないエラーが発生する可能性があり、デバッグが難しくなることがあります。
このように、コンパイル時にエラーを網羅的に発見できる静的型付けのシステムは、開発効率とコードの安全性を高める大きなメリットがあります。この点が、Swiftなどの現代的なプログラミング言語が採用している重要な文脈となっています。 なので、その辺りをSwiftではとても大事にしていて、できる限りコンパイラーが見つけていく、コンパイル時に見つけていくというアプローチが取られています。この辺りの話をするときに、何回も話したくなるのがSwiftの特徴でもあります。
今、Playgroundで試していたのですが、コンパイルタイムとランタイムが分かりにくいと思います。例えば、int型の整数に200
のようなint型の範囲を超える値を入れようとするとオーバーフローになります。通常、このオーバーフローエラーはランタイムで見つかるのが普通ですが、Swiftではコンパイルタイムに検出されることがあります。これを初めて知ったときに、非常に感動しました。なぜなら、エラーを代入時ではなく、ランタイムに持ち込まないというのはすごいことだからです。
このように判定制御が図られていて、判定の方法について考えると、どのように判定されているのかという疑問が湧きます。特別に言語が組み込んでいるのか、それとも自分で定義した形でできるのか、いずれにせよコンパイル時のエラーチェックが非常に強力です。
具体的な例を挙げてみると、BinaryInteger
やNumeric
プロトコルを実装することで、任意の範囲チェックをコンパイル時に行うことができます。これを利用して、オーバーフローチェックをコンパイルタイムに行う仕組みを実装できますが、実際に試してみないと分からない部分もありますので、個人的に勉強会が終わった後に試してみようと思います。
なんにせよ、コンパイルタイムにオーバーフローチェックができるというのは非常に強力です。他にもコンパイル時にチェックできることがいくつかあったと思いますが、少し忘れてしまいました。また思い出したらお伝えします。
以上、Swiftのコンパイル時エラーチェックの強力さについての話でした。 Swiftのプログラムでスイッチ文で「フラグ」に対して定数を用いてフォルスを設定する場合、以前は警告が出ていた気がしますが、現在は出なくなったようです。Playground上で試してみても、フォルスの定数には行けませんという警告が出ません。コンパイルタイムで警告が出るかどうかを確認したいのですが、現状では出ていないようです。
スイッチ文に関連して、以前は「スルー」を使うことで警告が出ていたのですが、現在はそれも出なくなっているようです。イフ文やスイッチ文で試してみても、昔は出ていた警告が自分の環境では全く出ていないことに困惑しています。
自分の環境では警告が出なくなっている可能性があるので、後で環境を見直してみる必要があるかもしれません。現在使用しているXcodeのバージョンは13.3.1なので、多くの人と同じ環境だと思いますが、警告が出ていないのは環境の問題かもしれません。
過去には警告が出ていたことを確認していますが、現在は警告が出ない状況です。Swiftでは、コードの安全性を高めるために早期にエラーや警告を検出できるようになっている点が素晴らしいです。シンプルなプログラムでは警告がちゃんと出ることもあります。このように早めにエラーを見つけられる仕組みが、開発者としても安心できます。
一般的に、エラーと警告の区別は明確にされており、エラーは処理を止める必要がありますが、警告は注意が必要であるものの進行は可能です。この区別があることで、開発者は適切に対応することができます。エラーメッセージや警告メッセージが出るかどうかは、環境の設定やバージョンによっても異なることがありますので、都度確認すると良いでしょう。
関数内で複数のコード行がある場合、その中で特定の警告やエラーが出ることがあり、それを見逃さずに対応することが大切です。このような感覚は経験を積むことで身についていくものですので、積極的にコードを書き、警告やエラーメッセージに対して敏感になるよう心がけることが重要です。 とりあえず、21行目まで実行したいとき、そのようなタイミングでデジタルで実行すると、これはエラーではなくて22行目がエラーではなくて警告として表示されます。これは、実行されないよと教えてくれるのです。そして、これがエラーだと思って試したいときは、コメントアウトしてあげないといけなくなってしまいます。そういう場面で便利なのが、警告にしておくサービスがいろんなところで提供されているようです。ちょっとうまく進められない気がするので、あとで調べてちゃんと紹介しますね。
Swiftでは、エラーや警告を可能な限り早く見つけて修正できるようになっています。これにより、コードの安全性が確保されるのです。Swiftを実際に見てみるとわかるのですが、初期のリテラルのチェックもしっかりしています。そういった意味でも、Swiftの型チェックが非常にしっかりと働いており、トレンドと言っても過言ではないくらい優秀なシステムになっています。
Swiftでは、型チェックと型推論が機能として備わっています。型安全とは少し違う話かもしれませんが、Swiftのプログラムを書く上で非常に重要なポイントです。異なる型の値を扱う際にエラーを回避するためには、暗黙的な型変換に気を付ける必要があります。たとえば、フロート型とダブル型の値を暗黙的に変換すると、フロート型に変換される際に情報が失われる可能性があります。このように、型チェックを行わないとエラーが発生することがあります。
しかし、全ての変数に対して型を明示的に指定しなければならないわけではありません。型推論によって、自動的に適切な型が導かれます。たとえば、「x」はダブル型、「y」はフロート型と明記しない場合でも、前後の文脈から判断されます。これはプログラムを書く際の手間を省くための機能です。
具体的には、暗黙的な型変換を避けるために、変数の型を明示することが求められる場面もありますが、型推論が機能している限り、全ての変数に型を指定する必要はありません。これにより、プログラムを書く際の負担が軽減されるのです。
このように、Swiftの型推論機能は非常に強力であり、コードの安全性や可読性を高めるために役立っています。 型推論は、コンパイル時にコードに書かれた値を調べることで、コンパイラが特定の型を自動的に推測する機能です。これにより、他のプログラミング言語と比べて非常に少ない型宣言で済むという利点があります。実際、Swiftは型推論のおかげで、プログラミング初心者でも簡単に学びやすい言語と言えるでしょう。
例えば、以下のようなコードがあります。
let pi = 3.14
この場合、Double
型を明示的に宣言していないにもかかわらず、コンパイラの型推論機能によりpi
はDouble
型として認識されます。これが型推論の大きなメリットであり、プログラマーが少ない型宣言でコードを書ける理由です。
また、変数や定数は明示的に型が宣言されているケースもありますが、これはほとんどプログラマー自身のために行われています。例えば、
let radius: Float = 5.0
のように明示的に型を宣言することで、コードの可読性が向上し、誤った型変換を避けることができます。例えば、Double
の値をFloat
に誤って変換してしまうと、再びDouble
に戻す際に丸め誤差が生じることがあります。このような問題を防ぐために、明示的に型を宣言することがプログラマーの役に立つのです。
型システムは非常に重要であり、一部のプログラミング言語においてはわずらわしく感じられることもありますが、Swiftでは型推論を活用することで、軽量かつ直感的なコードを書くことができます。このように、型推論は効率的で安全性の高いプログラムを書くのに役立ちます。
以上のように、Swiftにおける型推論の重要性とその利点について理解を深めました。次回は、具体的な例を交えながら型推論のメリットについてさらに詳しくお話ししたいと思います。今日はここまでにしましょう。お疲れ様でした。ありがとうございました。