書いて覚えるSwift入門

第39回 史上最も地味なWWDC?

この記事を読むのに必要な時間:およそ 3.5 分

WWDC 2018総括

というわけで前回予告どおり,WWDC 2018を本記事で振り返るわけですが,いやあ,地味なWWDCでしたね。新規ハードウェアの発表ゼロ,次期macOSであるMojaveの一番のウリはDark Mode写真1)⁠そしてSwift 5は今年ではなく来年。しかし地味なだけに,派手さに隠れて目立たなかったSwiftの問題を地味に片付けていったのは筆者としてはむしろ好感が持てました。

写真1 macOS Mojaveプレビュー

写真1 macOS Mojaveプレビュー

というわけで⁠not much⁠でも⁠not insignificant⁠What's New in Swiftを一緒に振り返りましょう。

Swift 5は2019年前半

まず重要なのは,Swift 5は今年には来ないことが正式に発表されたこと。次のXcodeであるXcode 10に搭載されるのはSwift 4.2です。これはSwift 5でABI(Application Binary Interface)がフリーズされ,以後は過去のモジュールをコンパイルし直さなくても新しいSwiftでリンクすることが決定されたからで間違いありません。

Cの完全上位互換言語として登場したC++がなぜCを置き換えられなかったかと言えば,ABIが未決定で,Cで書いたライブラリのようにC++で書いたライブラリを再利用しにくかったからというのが理由の筆頭ではないでしょうか。ABIが未決定でもコンパイルしなおせばいいだけの話ですが,それが許せるのは無尽蔵のCPU資源と時間を持っている人だけでしょう。GUI環境のコンパイルなんてまる1日かかりますし。

というわけでSwift 5以降はソースではなくコンパイル済みのライブラリやフレームワークやモジュールを使えるようになるのですが,だとしたらABIの仕様決定で失敗するとのちのちまでたたることを意味します。今年ではなく来年まで準備期間を置くというのは極めて納得のいくところです。

そういうこともあって,⁠What's New in Swift」のwhat's new はwhat was newという印象さえありましたが,あらためて見てみると「え? Swiftってこんなことが今までできなかったの?」という発見がかなりあり,もっと枯れないとABIフリーズできないよなという思いを新たにしました。

enumの自動列挙

その筆頭がこちら。enumはenumerationつまり列挙型ですが,今までは全列挙するための手段が用意されていませんでした。

enum DayOfTheWeek {
    case sun, mon, tue, wed, thu, fri, sat
}
for day in DayOfTheWeek {
    // error: type 'DayOfTheWeek.Type' does not
    // conform to protocol 'Sequence'
}

こうした場合は,そのためのメソッドを手で追加してやる必要がありました。しかし見てのとおりこのコードはDRYではありません。

enum DayOfTheWeek {
    case sun, mon, tue, wed, thu, fri, sat
    static var allCases:[DayOfTheWeek] {
        return [sun, mon, tue, wed, thu, fri, sat]
}
}
for day in DayOfTheWeek.allCases {
     今度はOKだが…… 
}

これを全自動でやろうというのがSE-0194で,Swift 4.2より実装されました。

enum DayOfTheWeek : CaseIterable {
    case sun, mon, tue, wed, thu, fri, sat
}
for day in DayOfTheWeek.allCases {
     これでよし 
}

CaseIterableというプロトコル準拠を宣言する必要があるのは,EquatableHashableと同様です。すべてのenumが列挙可能ではないことは,Swiftのenumが単なる列挙型を超えた,Cのunion(共用体)としても用いられていることからも明らかで,プロトコル準拠宣言で「普通の」列挙可能なenumであることをコンパイル時に保証できるわけです。

ターゲット環境ごとの条件付きコンパイル

たとえばシミュレータ用と本番環境用でコードを切り替えたいとします。今までは#ifでそれを切り替える方法がなかったので,os()cpu()を使ってしかたなく次のようにしていました。

 #if (os(iOS) ¦¦ os(watchOS) ¦¦ os(tvOS))
  && (cpu(i386) ¦¦ cpu(x86_64))
print("Simulator")
#else
    print("Device")#endif

SE-0190hasTargetEnvironment()が導入されたことにより,それが次のように自然と書けるようになります。すでにSwift 4.1で実装されています。

#if hasTargetEnvironment(simulator)
    print("Simulator")
#else
    print("Device")
# endif

Hashableプロトコルの刷新

SE-0185がSwift 4.1で実装されたことで,EquatableHashableの自動生成がすでに使えるようになっています。ストアドプロパティすべてがEquatableHashableに準拠している型なら,型宣言のところでEquatableHashableを付けるだけで……,

enum DayOfTheWeek : Int, Hashable {
    case sun, mon, tue, wed, thu, fri, sat

}

==(_:_)や.hashValueを実装しなくても使えるようになります。

let officeHour:[DayOfTheWeek:ClosedRange<Int>] = [
    .mon : (900...1700),
    .tue : (900...1600),
    .wed : (900...1500),
    .thu : (900...1400),
    .fri : (900...1300),
]

DayOfTheWeek(rawValue:0) == .sun

注意点としては,自動生成はextensionではダメで型宣言の時点で行わないといけないのと,Hashableを付けた場合には自動的にEquatableになる点です。実は後者の点は型によっては問題になります。たとえばFloatingPoint浮動小数点型には中身が同じでも==で比較したらfalseが返るnanという値がありますが,しかしこの場合でも自動Hashableはできます。筆者は現在swift-bignumという任意精度浮動小数点モジュールを開発しているのですが,ここでもHashableはSwiftに自動生成してもらっています。ではNaNなどの扱いをどうしているかというと,FloatingPointプロトコルでは.isEqual()というメソッドの実装を必須にしたうえでそちらで対応しているわけです。

このように自動生成が可能な場合でも手動で実装すればそちらが優先で使われるのですが,安易にオレ実装してほしくない場合も実はあります。Hashableはその代表格です。たとえば,

struct City {
    let name: String
    let state: String
    let population: Int
}

という形があったとします。この場合populationはハッシュ値生成には不要なので,namestateのハッシュ値を何らかの形で合成して.hashValueを生成すればよさそうに見えます。Swift 4.1以前では,次のようなコードをよく見かけました。

var hashValue: Int {
  return name.hashValue ^ state.hashValue}

しかしこれはあまり良いやり方だとは言えません。衝突を起こす例は簡単に作れます(この場合namestateの値を入れ替えただけでそうなる)⁠つまりhashdosに対して脆弱ということで,iOSアプリならとにかく,Webサーバなどではたいへん困る。

そこでSE-0206が提案したのは,標準のハッシュ合成関数を用意して,手動で実装する場合にもそれを使うようにしようというものでした。Swift 4.2からはHashableには.hash()というメソッドが追加され,手動でHashableにする場合にもそれを使えということになりました。

func hash(into hasher: inout Hasher) {
  name.hash(into: &hasher)
  state.hash(into: &hasher)}

見てのとおり,これでアルゴリズムをSwift任せにしたうえでカスタマイズすることも可能となります。

著者プロフィール

小飼弾(こがいだん)

1969年生まれ,東京都出身。元ライブドア取締役の肩書きよりも,最近はPokemon GOのガチトレーナーのほうが有名になりつつある……かもしれない永遠のエンジニアオヤジ。

活躍の場はIT業界だけでなく,サブカルからアカデミックまで多方面にわたり,ネットからの情報発信は気の向くまま毎日毎秒! https://twitter.com/dankogai,ニコニコチャンネルは,http://ch.nicovideo.jp/dankogai,blogはhttp://blog.livedoor.jp/dankogai/

当社刊行書籍は『小飼弾のアルファギークに逢ってきた』『小飼弾のコードなエッセイ』など。他にも著書多数。

コメント

コメントの記入