it-swarm-ja.com

コンパイラがifステートメントの条件が内部で正しいと想定しないのはなぜですか?

まず最初に:タイトルを申し訳ありませんが、次の質問の意味を1つのフレーズでより適切に定式化する方法がわかりませんでした。

次のSwiftコードを書いている間:

if errorData.isMemberOfClass(UIAlertController) {
    self.presentViewController(errorData, animated: true, completion: nil)
} else {
    /* Some other code */
}

私の個人的なプロジェクトでは、コンパイラーから次のエラーが発生しました。

'AnyObject' is not convertible to 'UIAlertController'; did you mean to use 'as!' to force downcast?

コードを次のように変更しないと、コンパイラーはそれ以上使用できなくなります。

if errorData.isMemberOfClass(UIAlertController) {
    self.presentViewController(errorData as! UIAlertController, animated: true, completion: nil)
} else {
    /* Some other code */
}

しかし、これはわかりません。プログラムにif statementを使用してerrorData(正確にはクラスAnyObject)のクラスをチェックさせると、なぜそうなるのでしょうか。 if内にあるはずのクラスのタイプに対して、強制的にダウンキャストを強制しますか?言い換えると、コンパイラは、ステートメント内でerrorDataがUIAlertControllerであることをすでに認識していませんか?代わりに、プログラムがelse部分で続行されなかった場合、errorDataはクラスIntまたはStringである可能性もあります。

2
Aluminum

はい、コンパイラーcould直前にテストされたため、変数が期待される型であるという事実を推測します。実際、これはデータフロー分析のコードに追加する次の最も簡単なものです。

ただし、コンパイラは決してプログラムについてできるだけ多くのことを推測することができます。このコンストラクトの型のような(あなたにとって)完全に明白なプロパティでさえ、明示的にプログラムする必要があります。コンパイラーの作成者がタスクにどれだけの労力を費やしても、人間の使用には明らかであるように見えるが、コンパイラーにはまったく明らかではない状態が常に存在します。 (人間の知覚が適応的に機能するため、問題はさらに複雑になります。コンパイラをよりスマートにすると、ユーザーはよりスマートなことを期待し始めます。昨年はかなり進んでいたと思われていた推論が今では日常的になり、新しい問題は「コンパイラは簡単に認識できます」。)

したがって、理論的に可能なことと、(コンパイラの作成者の意見では)実行する価値があることとの間の現在の境界を観察しているだけです。悲しいことはありません。数年以内に彼らはこの論理を追加するでしょう、そしてそれまでにあなたは他の不合理な何かを見つけるでしょう!

10
Kilian Foth

これにはいくつかの異なる可能な答えがあります。

答えの1は、isMemberOfClassが他のメソッドと同じメソッドであるということです。コンパイラーは、このメソッドが何をしているのか、そしてコードが何を意味するのか全くわかりません。サブクラスでオーバーライドされることもあります。このメソッドはSwiftの一部ではなく、Objective-C標準ライブラリの一部です。

答え2は、コンパイラが知っていることです。これにより、より効率的なコードが生成される可能性がありますが、言語のセマンティクスはSwiftは、参照の静的型に存在するメソッドのみを呼び出すことができると言います。コンパイラーが言語セマンティクスに違反することは許可されていません。この情報は、最適化、より適切なエラーメッセージの生成など、さまざまな目的で使用される場合がありますが、言語仕様を実行するために使用されることはありません禁止します。

回答番号3は、活字ケースまたはタイプガード構造を持つ言語がありあり、Kotlinのスマートキャストについてはすでに言及されているということです。ただし、Kotlinのif (errorData is UIAlertController)の場合、is構造は型テスト用の言語組み込み構造であるため、コンパイラそれが何を意味するか、isMemberOfClassは他のメソッドと同じように単なるメソッドですが、コンパイラにとって特別な意味はありません。したがって、このような機能をSwiftに追加できますが、おそらくメソッドではなく、言語に組み込まれたタイプテスト(is)を使用します(オプションのif letと同様)。

私は実際にはSwiftを知りませんが、次のようなことができると思います。

if let errorData = errorData as? UIAlertController {
    self.presentViewController(errorData, animated: true, completion: nil)
} else {
    /* Some other code */
}

これを短縮するためにシンタックスシュガーを導入する方法はいくつかあると想像できますが、それほど多くはありません。

4
Jörg W Mittag

言語は明確に定義されている必要があります。コンパイラの巧妙さによっては、コードが有効かどうかはひどいことです。これにより、あるコンパイラで実行され、別のコンパイラでは実行されないコードが生成されます。

Javaには、使用する前に各変数を定義する必要があるという要件がありましたが、それは上記の問題につながるため、実際には要件ではありませんでした。したがって、要件はそれぞれ変数は、非常に明確に定義されたアルゴリズムによって認識できる方法で、使用する前に定義する必要があります。許可されていないより賢いコンパイラを作成すること他のコンパイラが認識しなかったことを認識しました。

したがって、言語設計者は、そのような推論を行うことができ、行う必要がある場合、ルールを正確に考え出す必要があり、それは非常に困難です。

一方、この言語には、「iflet」を使用してこのコードを記述する非常に簡単な方法があります。

1
gnasher729