読者です 読者をやめる 読者になる 読者になる

euphonictechnologies’s diary

Haskell超初心者の日記です。OCamlが好きです。

follow us in feedly

Swift - また言語仕様が変わっていやがる 2015春

You have been warned! Swiftは開発途上の言語です

f:id:euphonictechnologies:20150410000839p:plain

というわけで、またSwiftの言語仕様がガラリと変わりまして、さっぱりビルドを通りません。ぱっと見ると17個ものビルドエラー。なーんかC->C++->Ocamlあがりの私としては言語仕様というのはバックワーズコンパチブルでなんぼやというところなのですが、Swiftはそうではないようです。未来の開発者がクリーンな言語仕様で働けるようにがしがし後方互換性を殺すというのはまあ、いいのかも。

ですが、私はいましこしこビルドエラーを直さないといけないので、晒しておこうと思います。

変わったところ as of 9 Apr 2015

オーバーフロー演算子のうち(&%)がなくなったっぽい

まあ、当たり前なんですが、&%がなくなりました。オーバーフローモジュロというのは意味わからないからだと思いますが、直交性のない演算子の組み合わせですね。残念です、ていうかそういう直交性にかける演算子体系というのはダサいです。参考:blog.euphonictech.com

NSSetでごまかしていた部分がSwiftジェネリクスになっている

これは言語仕様ではなくてAPI変更ですね。具体的には旧来は

    override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
        <#code#>
    }

だったのが

    override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
        <#code#>
    }

と、Setの形で渡されるようになりました。

ダウンキャストがasからas!

これも納得できる変更ではあります。基本的に危険な(実行時に失敗する可能性がある演算子や命令)は!をつけるというのがSwift全体のルール、コンベンションです。ダウンキャストは当然実行時の型がincompatibleなとき失敗するので!がつくのが自然です。まあこれはいいかな。auto-fixが出るのでポチポチクリックしましょう。auto-fix一覧にして一発で適用とかできるようにならないのかな…。うちの会社のIDEには少なくとも僕の入社時からある機能なのに。

あとasas!sに変更しようとするauto-fixを書いた人は、お願いなので死んでもらえないでしょうか。

f:id:euphonictechnologies:20150409233726p:plain

assertionFailureでreturnを省略できなくなっているっぽい

f:id:euphonictechnologies:20150409233815p:plain

ちょうど図のようにその行に達した場合はfailしてアプリケーションを強制終了してもよい場合、assertionFailureを書くことでパフォーマンス上の恩恵を受けられます(参考:Safx: SwiftでassertとpreconditionとfatalErrorをうまく使い分ける)。

どういうことかというと、絶対に起こらない、と想定されることがあります。例えばダウンキャスト直前にキャスト元とキャスト先の間にクラス階層の親子関係が成り立たない、などです。それが起こる場合は設計ミスです。データベースの接続やファイルが書き込めないなどは「当然起こる」エラーなので、これは種類が違います。当然そのような例外にはtry-catchで対処しなければなりませんが、キャスト元とキャスト前が違うなんていうのは基本的には決定的に発生するプログラミングミスなので、デバッグ時にはチェックが必要ですが、リリース時には必要なかったりします。そのような場合、リリース時には自動的に消えてなくなってくれるassertionFailure等があると、リリース時にはifの分岐が発生せず速くて素敵です。分岐命令は書くだけで決定的にパフォーマンスを劣化させるので、どうしてもスピードセンシティブな部分には書きたくないからです。

なので、絶対発生しない分岐命令の先に上の図のようにassertionFailureを書いてreturnを省略できていたのですが(Swiftのコンパイラはフロー解析をしてちゃんとその場所にreturnがいらないのをわかっていたようです)、今回のアップグレードで必要になった模様です。

修正はfatalErrorに変えることです。基本的にSwift開発陣の考えでは、例えば実装されてない関数なんかはfatalErrorを返すべきだと最初から思っていたようで、今回のアップグレードでassertionFailureの間違った使い方はできないようにされてしまったようです。

その他にもswitch-caseのデフォルトにassertionFailureを書いてそれぞれのケースで変数を初期化している場合なども同様にassertionFailureでフローを止めることができなくなっているので、同様にfatalErrorに変えてフロー解析を成功させてあげましょう。

NSString is not implicitly convertible to 'String'!!

なんてこったい!NSStringとStringは明示的キャストでないといけないと。これはいけない。CocoaAPIにべったりなくせにNSStringとStringを暗黙キャストしないのは…、どうかなって思います。アップル様の言うことです。仕方ないのでauto-fixでas Stringをつけていきましょう。

NSDictionary と [NSObject: AnyObject]もキャストが必要に

Cocoa APIからの分離を図っているようです…。素直にauto-fixしていきましょう。

まとめ

私が遭遇したのはこんな感じのビルドエラーでした。これらを直せば新しいコンパイラの新しい最適化の恩恵に預かることができるはずです。苦行ですが、ひとつひとつロボットみたいに直してこのトンチンカンな言語と末永く付き合っていきましょう。

つづき

blog.euphonictech.com