https://youtu.be/jgINm3JdP6o
今回からは再び本流に戻って The Swift Programming Language の The Basics の続きを眺めていきます。そんなセクションの始まりの辺りの About Swift 的な内容をおさらいしていっていますけれど、今日は「高度な型の導入」と「型安全」の紹介的なところを見てみることにしますね。よろしくお願いします。
—————————————————————————————————————— 熊谷さんのやさしい Swift 勉強会 #83
00:00 開始 00:11 構造体をパラメーターに渡したときはコピーされる? 00:45 C 言語の関数に Swift の構造体は渡せる? 01:03 objc_sync_enter と objc_sync_exit 03:41 Any に構造体を渡していいのか 05:23 最適化を気にしてみる 06:08 Any と AnyObject 07:06 id を Any で扱う 07:36 透過的に言語間の相互運用を行う仕様 09:27 API が求める Any に渡す値 10:59 __SwiftValue 13:27 ObjectIdentifier 17:05 Objective-C ブリッジ 20:33 Objective-C リテラル 22:42 タイマーで繰り返しテストするアイデア 23:47 実行環境に応じた Any 表現 27:55 Any 表現 30:35 Objective-C Interoperability 31:35 AnyObject に構造体を入れる 33:10 構造体のアドレスが同値になるケース 34:19 ObjectIdentifier の存在意義 35:41 文化を超えて相互運用することの難しさ 36:24 ObjectIdentfier と厳密等価比較の類似性 36:58 BridgeObjectiveC.swift 41:30 __SwiftValue が作られるタイミング 42:32 レイヤーをまたがなければ維持される可能性 43:44 NSRecursiveLock 45:53 排他制御とロックフリー 48:51 談笑タイム 49:52 AnyObject が描く世界 55:36 値型のラップが実装された PR 57:10 次回の展望 ——————————————————————————————————————
Transcription & Summarize : 熊谷さんのやさしい Swift 勉強会 #83
さっそく質問があります。Structをメソッドのパラメーターに渡したとき、コピーオンライトを除いて、自分で作ったStructとかをメソッドにパラメーターとして渡したとき、そのStructは値コピーされてアドレスが変わりますか?
最適化を考えると同じアドレスのままの場合もありますが、原則としてはアドレスは変わることになります。
次に、C言語の関数にSwiftのStructを渡すのは問題ないでしょうか?
C言語の関数に渡すということは、最初にCの型に変換しますね。例えば、Swiftのインターフェースがあって、内部実装がC言語のメソッド、具体的にはObject-Sync-Enter
とExit
の関数にSwiftのStructを渡したときに、変な挙動が発生することがあります。現在、その原因を調査中です。
確かに、Object-Sync-Enter
にStructを渡すこと自体には問題はありません。ただ、Object-Sync-Exit
のときにエラーが発生する場合があります。そのエラーの原因がStructを渡していることにあるのか、内部実装の問題なのかは現状分かりません。
また、2つ前のロックの挙動に関してですが、Structに対する書き込みが発生したときに基本的にロックが走らないことがあります。パラメーターで渡したときに値がコピーされ、オブジェクトが変わってしまうことで、再度同じオブジェクトに対してロックをかけようとしても、それが異なるオブジェクトとなるため、ロックがそのまま進行してしまう場合も考えられます。
デバッグビルドでは試されていますか?リリースビルドでの挙動にも興味があります。さらに補足すると、構造体は読み取り専用(let
)で扱った場合、書き換えが起こらないため、同じメモリを使うような最適化が行われる可能性があります。こうなると、クラスと同じ挙動が起きる場合があります。
Anyの周りの話ですが、昔はクラスと値型を表現するための型が異なっていました。AnyとAnyObjectという型があって、Object-Sync-Enter
は本来クラスを想定していたと思われます。その後、インターフェースがAnyObjectからAnyに変更されました。この変更により、Swift側の構造体を渡すことができるようになりました。
つまり、命令型として「何でも受け入れる」プラットフォームがObjective-C側にあり、そのレイヤーを跨いで値が自然に渡せる動きを作り上げたのです。たとえば、CのボイドポインターとSwiftのAnyが同等の型になっていて、相手のプラットフォームがそれをサポートしている場合、Anyとして渡して戻すことができるのです。
ここで重要なのは、呼び出し元の責任で、インターフェースはAnyだけど参照型を渡すように設計されていることです。SwiftとObjective-Cの世界ではSwiftのStructのようなものは存在しないため想定外となります。 これが起きるのはiOS15からなんですよ。iOS15から、ただオブジェクティブCエンターの振る舞いが変わったのか、別にWebKitの問題だったりするけど、それが波及するっていう想像が全くない。iOS15からここに、このオブジェクティブCエンター周りの挙動を書くかどうかでWebViewの挙動が変わってしまうっていう、すごく不思議な話です。
なるほど。もしかするとSwiftのほうでエニーに何かしらを渡したときに、オブジェクティブCのほうでも一応インスタンスとして持っておかないといけない状況になるので、多分値型を渡したときにオブジェクティブC側ではラップするんですよ。なんだっけ、SwiftValue
みたいな型があったような気がするんですけど、_SwiftValue
みたいな。それはオブジェクティブCブリッジでオブジェクティブC側でどんな型になってるかっていうのを表示すれば出てくるんですけど、そうするとプロジェクト作んないとダメか。
せっかくなので、時間がいい感じになってきましたが、脱線していきますね。後ろ戻っても全然大丈夫ですけど。では行きますよ、コメントくれたアプリンさんどうぞ。
_SwiftValue
か。一時的にオブジェクトが配置済んだものがこの_SwiftValue
。安定のメモリアドレスがないっていうのは開放される場合があるんですかね、どこまで言っていいんだろうけど。内部で吉野やってくれるっていう意味ですかね、ラップするタイミングとかを。多分ですけど、実際に実際には何もない、とにかく_SwiftValue
の確認方法。このあたりをせっかくなので補足しとくと、Swiftプロジェクトでここはオブジェクト作って、それでビューを取るね、インターフェースを用意してあげて...
間違えた、Swift言語にしちゃった。えーと、なんかコメントくれてる。トラクトとクラスを作って、トラクトのインスタンスを入れて、クラスのインスタンスを入れて、そっかそっか、スケジュールトゥタイマー。それに読んであげて、そうかじゃなかった、わかったつもりで違った。
オブジェクトアイデンティファイヤーでエニーオブジェクトにキャストして、それで随時タイマーでリクエスト読んで変わるかを見るんだ、きっと。これは多分エニーオブジェクトにキャストするときにラップするんですかね、きっとね。そうどうですけどね。間違えた、また間違えた。多分こうだ。それも試すの1個面白いですね。そっかそっか、オブジェクトアイデンティファイヤーで見ちゃえば結構すぐに確認できるんだ、Swiftネイティブでも。なるほど。
オブジェクティブCの場合、インターフェーラピリティでチェックする場合、oid doSomething
で効果、IDかな?エニーにキャストしてほしいときはね、それでオブジェクトを取って、ちゃんとプリントだっけ、NSログだね。それでパーセントアップでオブジェクトの型が欲しいのか、型が欲しいとすると覚えてない。ログだっけ?ちょっとずつインターフェース定義だからこうしてセミコロン打って、それでインプリメンテーションの方でこうしてあげて、それでこれをSwiftから読んであげればいいんですよね。だからこのときにインポート、テストSwiftだっけ。
ブリッジにまず書かないといけないね、ブリッジングヘッダはこれか。#import "Foo.h"
、これでいいんでしたっけ。で、ここでテスト...これでインタロペラビリティできてなかったかな?忘れてしまった、やってみよう。
let object = Foo()
よけてる感じ、それでオブジェクトのdoSomething
でエニーか、だからバリューとして例えばInt
型とかを入れてあげて、これを読んであげるとどうなのかな。ビルドエラーだ、まだ全然ダメか。なんか出てる?おもしろいな、オブジェクティブC結構好きで楽しんでますけど。一人で楽しんでますが、そうかNSNumber
になっちゃうか、Int
型だとオブジェクティブCブリッジ通すんでこれはダメだ。
トラクトMyValue
とか、こういうの作んないとダメ。Value
にしよう、これでValue
でしょ、シンと。これで実行してあげると、SwiftValue
に。なるほどですね。 これに対してのメモリアドレスで制御しているから、おかしいっちゃおかしいですよね。動くっちゃ動くんです。ラップしてスイフトバリューがクラスになっているんですか?おそらくそうでしょう。試す方法ってあるのかな。オブジェクティブCとのインターオペラビリティが Any
をラップして、向こうの環境に合わせた表現になっていると思います。多分クラスですよね。クラスになってますね。
なるほど、クラスでラップしてあげて、新しいクラスでラップしているだけ。多分、このラップのタイミングがさっきコメントで教えてもらった通りで、スケジュールでクロージャが呼ばれる。この中で As AnyObject
としてキャストしてオブジェクトアイデンティファイアを取ると、多分変わるというコードだと思います。アドレスがね。アドレスというかアイデンティファイア。適当にポイントするのではなく、クラスの名前じゃなかったかな、クラスのインターフェースを指す識別子ですよね。ここでも試してみればいいんだ。バリューに対してアドレスを取りたくて、アドレスバーじゃないとアドレスなんか探せないけど、これできないなと思ったら、この方法があるんですね。
ここが同じだったら、同じってことなんですよね。オブジェクトアイデンティファイアの値が同じであれば。それで、アドレスの出力になるのか。なるほど、そうなんだ。そうですね、そういうことらしいです。ありがとうございます。ちょっとすみません、勉強時間をありがとうございます。多分、みんなにとっても役に立つ日が来るはずです。オブジェクトで行きたくないなって、本当に行きたくない。そうですか、個人的にはちょっとやりたいんですけど、やっぱり @""
とかクラジェットもやりたくないですよね。なぜでしょうか、大体の人が嫌いですよね。@
とか。
慣れているんですけど、インターフェースが上手ですよね。あまり書きたくない。そうですね、まあ。でもアクセサーコントロールでやるべきで、このインターフェースで分けるっていうのが昔は当たり前でしたからね。C言語の時代には、他にもさっきのエラーの指摘が個人的にはとても楽しくてしょうがなくて、これよくできてるじゃないですか。1だと int
型でしょ、@1
だと NSNumber
でしょ、Aだとキャラクターでしょ、それで @A
だとっていう風に、こっちはCの世界ですよってね、こっちはObjective-Cの世界ですよっていう、すごい明確な分かれ方になってるんですよ。
@true
なんてあったかな、どうだろうとかね。こういう発想が、でもさすがに無いですね。期待して書いたんですけど、どうなんだろう。これはただのプラグマの色が違っただけでラップはしなかったですね。@1
を NSNumber
で取ったら boolValue
で取れば true
とか、そういう話ですね。そうかもしれない。こんな風にオブジェクトのときには @
マークをつけるっていう、こういう発想がとても好きです。書き方はC本来のリテラルと一致するっていうね、そういうところが好きですね。@
マークが指摘されるたびに、ちょっと面白く思い出されます。
こういうコメントがさらさらっと出てくるってことは、既に試されてるっていうことですね。すごいですよね。あと、このスケジュールドタイマーとかを使って繰り返しテストをするクロージャーを使って、なんかこういうところも面白い発想ですね。自分は頭の中で for
ループぐらいしか思い浮かばないけど、こういう使い方は面白い。いろいろとテストの仕方の幅が広がりそうです。
ここでタイマー、スケジュールドタイマーを使ってますけど、NSなんたらを使えば1回Objective-Cのレイヤーに飛ばせますからね。そうやって Any
を渡してあげるってことを今プロジェクトでいろいろやってましたけど、こういう工夫一つでSwiftネイティブなプレイグラウンドの中でObjective-Cに1回飛ばすってこと、簡単にできそうですね。 なるほど。まあ、とりあえず、今日のというか、今お話しいただいたテーマのエニー(Any
)のところ、とても面白いですね。おさらいを軽くしておくと、エニーにはクラスだろうと構造体だろうと何でも渡せるという大事な特徴があります。それで、エニーは何でもいいのかというと、逆にエニーオブジェクトにも構造体が入るんですよね。
それはそれとして置いておいて、とにかくエニー系は何でもいい。そして、それぞれの文化に合わせたインスタンスを渡す責任は、呼び出し側にあるというところですね。だから、用意されたAPIはそのレイヤー、例えばObjective-Cで用意されたAPIならObjective-Cの世界しか知らないし、C言語で用意されたAPIならCの世界しか知らない。その中で、何でも受け取れるエニーの役割を果たすためには、その用途が分からない場合でも目的に合った形で使う必要があります。
例えば、昔のNSNotificationCenter
やNSNotification
にあるuserInfo
のような情報は負荷情報であって、Objective-Cレイヤーでは扱わず、単純にSwiftネイティブで作る場合はSwiftネイティブでしか扱わない。そういったところでは構造体を渡しても何の支障もないわけです。
たとえばNSNotification
のuserInfo
がディクショナリを取る際、Dictionary<String, Any>
となると、これがクラスしか渡せないとなると使いにくい。エニーであれば、インテージャーなど何でも渡せます。こうして、呼び出し元と呼び出し先のAny
をちゃんとブリッジすることによって、インターフェースの設計次第でデータが壊れることなく全ての値を渡すことができる。
もし、Any
として想定している部分に渡すものがObjective-Cレイヤーで使うAPIの場合、ちゃんと互換性のあるものを渡す必要があります。これはAPIを使う側が気を使って、相手の文化に合わせてあげる必要がありますね。
この思想はObjective-Cブリッジやインターフェースの仕組みに限らず、Swiftで何かしらの関数がAny
型を要求していた場合、中での利用法によって渡すものが変わることと同じです。例えば、JSONデコーダーでJSONDecoder
を使う場合、Any
を受け取るものはJSONオブジェクトを渡さないといけない。
今回の話のAPIもそうですが、その他のAPIでもAny
を受け取る場合は、身構えて適切な値を渡す必要があります。特にAny
やAnyObject
を使う場合は、呼び出し元がAPI要件に注意して値を渡すべきです。このあたりのブリッジの仕方は調べてみると頭がこんがらがるかもしれませんが、面白いところです。
以上がまとめです。もしさらに詳細を知りたい場合は、確かどこかに情報が出ていたと思うので、調べてみると良いと思います。興味深いテーマですね。 興味ある人はね、すみません。ブリッジのやつ、何て言ってましたっけ?ブリッジのインターフェースアビリティ。Objective-CとSwiftの相互運用のAPI自動変換は「Objective-Cインターフェースアビリティ」です。ときどきしゃべってる「Objective-Cブリッジ」っていうのは、NSNumberとInt
が振り替えられるよとか、そういうお話です。
今お話ししてた「AnyObjectがAnyになる」っていうのは何だったかな。そういうプロポーザルが多分出てるはずで、「AnyObject」と「Any」、そんなあたりのキーワードで調べれば何か出てくるんじゃないですかね、多分。
で、あともう一個関連しそうな話題として、AnyObjectに構造体を入れられるよね。どうだったかな。これがいらない…。ビルドをして、ビルドフィールダメか…。あ、できましたね。そっかそっか、今メイディキャストをしないといけないんだ。これで変換が起きてるって感じなんですかね。そうですね。
ただこれはObjective-Cブリッジかどうかはちょっと微妙で、単にアンダースコア2つのSwiftValueにラップするっていうね、そういったインターオペラビリティをやってる。そういった単なるキャストの規模をする。それをObjective-Cブリッジっていうのかな?そのあたりはちょっと分かんないけど、少なくともAnyObjectは外からいじれないので、言語組込みで何かやってるとは思います。
こういうふうに構造体もオブジェクトに、AnyObjectにラップできるよっていうのも途中からできた文化で、これがAnyとAnyObjectのフィームレスな連携なんですかね。このあたりはね、申し訳ないですけど…。スケジュールタイマーのやつ1個したら僕が貼ったようなログが出てきます。たまに一致してるんですよね、1秒ごとなので。これなんで一致してるんですかね、再利用されてるんですかね。全部違うんだったら意味は分かるんですけど、都度ちゃんとSwiftValueにラップしてるんだったら分かるんですけど。
連続してするときがたまにあって、どうだろう。たまたまメモリーが空いてただけじゃないですか?そういうことですね。そっちの可能性が高い。キャッシュとかそんなのしなさそうで、空いてるところに…。メモリーの場所としてはGCとか、めちゃくちゃかな…。そうですね、そうすると多分ヒープ領域がたまたま空いてるところを…。入演算なのかな、何かの演算が確保してくるんでしょう。ユニークアイデンティファイアになってますけど、そうするとメモリー開放したらユニークじゃなくなることもあったりして、ちょっとあまりよろしくないんですよね。
実行期間中において実行期間でずっと一意っていうのは確かに無理そうなので、今生存してるオブジェクトの中では一意です、みたいな意味なんですかね。ユニークじゃないって、ライフタイムって書いてありますね、インフランスの存在期間中の100人のみ有効なユニーク。このユニークIDはっていう注釈があるので、開放された場合にはもちろん同じアドレスに入ることがあるって読めそうですね。若干誤解を招く言葉ですね、このオブジェクトアイデンティファイア。読んで誰だとわからなかった。そんな使い方するなよっていう意味もあるかもしれないですけど、名前が良くない気もしますけどね。それ以外いけないにしてもね。
暗黙のラップが罠ですね。そのインスタンスの開放がまた別だって、バリューとは別だよっていう仕様は分かりづらいですけど、納得感はありますね。振り返っちゃうのはインスタンス。インターオペラビリティ側、文化を飛び越えるっていうほうの難しさかな。それがいろんなところに波及しちゃってるっていうところですかね。
ちなみにさっきのオブジェクトアイデンティファイアがどういうところで使われるかっていうのは、23行目みたいなね。この中で使われてるかはわからないですけど、そういったのと同じ価値観のもの。そういうものですよね。
今教えてもらったコードは BridgingAnyObjectToObjectiveC
。こういうコードで用意されてるのね。UnsafeBitCast
とか出てきてるな。Any
クラスだったら、オプショナルも…。オプショナル渡した場合にはアンラップ不可能ってオプショナル関係ですか?そう見えそうね。force unwrap
ですかね、アンラップ。ふんふんふん、なるほど。
guard
使ってフラグで判定するの、これなんでそうインターしないんだろうか…。うん、そうそう。そのね、謎コードといえば…。謎コードといえば、最適化とかなんですかね。何だろうね。他にも817行目だって、!= nil
判定出るけど、これだってSwiftコードですよね。 「ブリッジオブレシードットスイフト」だから、ここではオプショナルバインディングを使えばいいだけなのに、「ノットイコールnil判定」は最適化の可能性もあります。Type of Sourceを別にメモリに取る必要はないですからね。そうなれば、is
で判定すればよいわけですよね。何か理由があるのかもしれませんが、それが分からないと困りますね。
こういう価値観はどこからくるのでしょうね。やはり読みやすさを重視しているのでしょうか、それともネイティブっぽくないと感じるのでしょうか。間違っているわけではないのですが、言語仕様としてis
やas?
などの仕様を入れ込みたくないという意見もあります。そういった仕様にバグがあると問題になるため、原始的なやり方しか採用しないという方針なのでしょうか。
Swiftではオプショナルバインディングを使っていますね。is
とas?
はほとんど同じ動きをし、互換性があるかどうか確認してから変数に代入するかどうかの違いです。したがって、is
のほうが効率は良いかもしれません。これをPull Request (PR)で提案したら、教えてくれるのでしょうか。ペースに書いたら怒られるかもしれませんね。
オープンソースのプロジェクトでは、たまに意外と下手なコードが見られることもあります。例えば、794行目に組み込み関数のようなものがありますが、これには特別な意味があるのでしょうか。組み込み関数なので応用できないなどの事情があるのかもしれません。
as
とis
の話が少し引っかかりますが、内部のリストを見ればより明確になります。Anyクラス
でキャストしているから許容できる場合もありますが、Anyオブジェクト
へのキャストは変換の際に問題が生じることがあります。
例えば、型変換の度にMakeSwiftValue
が呼ばれてインスタンスが作成されるとします。これはObjective-Cとの互換性を保つためのものです。SwiftとObjective-Cのレイヤーを跨ぐ際に、再度ラップが生じる可能性があります。
リクエスト
というメソッドをObjective-C側で実装し、それをSwiftに渡す場合、Objective-C側でリカーシブルな呼び出しが行われているうちはアドレスは変わりません。ただし、処理をネイティブに渡す必要がある場合は、コールバックブロックを渡して、カスタム処理をSwiftネイティブで実行させるAPIを設計することも考えられます。
NSリカーシブルロックに関しても、セルフが渡されないという問題があります。NSロックのリカーシブル版であるNSリカーシブルロックについても似たような懐かしい問題を再確認しました。
このように、コーディングにおける細かい最適化やAPI設計の話は非常に興味深いですね。 NSRecursiveLockは、自身を再入できるロックのことです。他のスレッドにはロックをかけるけれども、自分自身には再入できるという特性があります。これには特定の状況下でしか使えない用途もありますが、それを許容するのがNSRecursiveLockです。
ですが、この特性をうまく使う場合、リカーシブな中だけロックするのか、外もロックするのかなど、ちょっと思い出せないこともあります。正直、私はNSRecursiveLockの正確な動作をよく覚えていません。しかし、スレッドがロックされるかどうかは、使用するスレッドの特性にも依ります。つまり、大人のスレッド(メインスレッドなど)ではロックが必要ですが、ドイツスレッド(バックグラウンドスレッドなど)ではロックしない方がいい場合もあります。
Appleの公式サイトにも記載があるようです。このあたりは誤って使うと危険です。基本的にロックは避けたいものです。制御するような設計を避ける方が良いという意見もあります。歴代のNSRecursiveLockを使用していた頃は、マルチスレッドの混沌をどうみ整列させるかに非常に悩みました。
一方で、Dispatch Queueを利用してキーを統一するアプローチや、ロックフリーの方法論もあります。ロックフリーな設計の方が、パフォーマンスも向上します。ですが、ロックフリーの考え方は難しく、コードも複雑になることがあります。このため、Dispatch Queueを活用して一つのキューにリクエストを投げることで競合を避けるのが良い方法の一つです。これは、UIコントロールをメインスレッドに統一する方法と同様の価値観です。
今回最初に挙げたコードがどういったロックを想定しているのかにもよりますが、インターロックが不要な設計の方が良いです。特に、先ほどお話に出た問題は、クラスを渡すべきところに値型を渡してしまったことが原因です。このため、ロック自体が問題ではないのです。
また、AnyObjectとのブリッジによって難しい部分もあります。エミュレータを使う際には特に注意が必要です。15行目でブリッジされるかどうかに関して、Swift内部での動作とObjective-Cとのブリッジを意識する必要があります。具体的には、Swiftの中でバリュー型として保持される場合にどうなるのかを実際に確認してみると良いでしょう。
これで全体の説明ですが、何か質問や補足があればぜひお伝えください。 なるほど、AnyObjectにキャストした時点でブリッジが走るということですね。ここは同じ場所なんですかね、この関数なんですかね?「Bridge Anything to Objective-C」、「Objective-C to Objective-C」ではないじゃんって、AnyObject型がObjective-Cを想定した型という意味で、なるほど、納得できますね。すでにこの場面でブリッジしちゃうという考え方ですけどね。
AnyObject自体がObjective-Cの世界のものということですかね?そうですね、15行目でね。Type Aliasな理由はそれなんですかね、AnyObject自体がType Aliasですよね。つまり、Swiftの世界にはないということですね。そうですね、別の文化が持っている定義をインポートするという価値観かもしれないですね。確かに、すごい納得感ありますね。
内部でネイティブなインスタンスを持っているので、逆の振り替えもあり得ますね。ただ、ここは「?」になってしまいますけどね。逆の「To Swift」的な、そうです、そうです、AnyObjectはObjective-C文化のインスタンスだから、Swift文化にその中に入っているものが一致するとは限らない。要は、しっかりとValue型が入っているとは限らないので、どうしてもas?
ね、安定と取り出しが必要という感じですね。SwiftネイティブのAny
からInt
型へ取り出すのと同じ発想ですね。とにかく広いところから狭いところへ取り出す、本当に読み出されているかどうかは分からないけど、「まあ、そうだろう」という感覚ですね。
調べたければここのソースコードにprint
を入れ込んで、Swiftコンパイラーを作って動かせば良いと思いますよ。実際にここではなく他のところでMake Swift Value
を読んでたっていいわけですしね。大事なところは__SwiftValue
でラップしているというところも知っておくと良いかもしれませんが、コード検索すると、Make Swift Value
を読み出しているのはそこしかないですね。なるほど、今後増えるかもしれませんね、分からないので。とりあえずネイティブのものを良しなにラップして、値を維持しながらObjective-Cレイヤーに渡しているというところまで押さえておけばいいでしょうね。とりあえず、クラスでね。
さて、いい時間になりましたね。ちなみにこれが実装されたプルリクを買ってきました。ありがとうございます。リラックス用のなんですね。プレディカルタイトルがリラックスと。はいはい、なるほど、もともとはどんなレイヤーであってもシームレスに渡せるようにしようという話だったので、もしかするとObjective-Cランタイム以外も想定して、すべてのランタイムにおいてAnyはAnyだよという価値観だったかもしれないですね。他のレイヤーと言えばC言語のレイヤーしか思い浮かばないですが、Java Virtual Machineだったりするとまた変わるでしょうしね。ガーベージコレクションの管理とかも入ってきますし。
そういう様々なもので、相手先がObjective-CランタイムだからAnyObjectにしようとか、JavaだからAny何とかにしようとか、そういう話ではなく、Anyという考え方が実装のベースなのかもしれません 多分ね。
はい、じゃあいい時間になったので、今日はこれぐらいにしておきましょうね。次回は高度な話に入っていこうと思っていますが、このあたりはまた次回にやりましょうかね。Anyみたいなものが含まれていなかったですけど、今のお話も絡めていくと、Anyもかなり高度な型ですね。AnyObjectか、でもAnyもそうですね、色々と応用力が高いというか、求められるところがありますが。型安全も考慮したときに、いかに型安全じゃない型と上手くやり取りしていくかという話に繋がりますね。
全然別の文化でも、うまくブリッジするための仕組みとしてAnyがあるという考えを持つと、なかなか奥深くて面白い文化ですね。まとまらない話になりますが、Anyひとつ取っても、色々と調べると面白いので、興味が湧いたら、今日話したところをおさらいしてみて、新たな発見があるかもしれないので、ぜひ興味が湧いたら見てみてください。
はい、では、いい時間になったので、今日はこれぐらいにしておきましょうね。また次回、「ザベーシックス」を見ていきますので、よろしくお願いします。お疲れ様でした。ありがとうございました。