WWDC 2018総括
というわけで前回予告どおり、

というわけで
Swift 5は2019年前半
まず重要なのは、
Cの完全上位互換言語として登場したC++がなぜCを置き換えられなかったかと言えば、
というわけでSwift 5以降はソースではなくコンパイル済みのライブラリやフレームワークやモジュールを使えるようになるのですが、
そういうこともあって、
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'
}
こうした場合は、
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で、
enum DayOfTheWeek : CaseIterable {
case sun, mon, tue, wed, thu, fri, sat
}
for day in DayOfTheWeek.allCases {
これでよし
}
CaseIterable
というプロトコル準拠を宣言する必要があるのは、Equatable
やHashable
と同様です。すべてのenum
が列挙可能ではないことは、enum
が単なる列挙型を超えた、enum
であることをコンパイル時に保証できるわけです。
ターゲット環境ごとの条件付きコンパイル
たとえばシミュレータ用と本番環境用でコードを切り替えたいとします。今までは#ifでそれを切り替える方法がなかったので、os()
とcpu()
を使ってしかたなく次のようにしていました。
#if (os(iOS) ¦¦ os(watchOS) ¦¦ os(tvOS))
&& (cpu(i386) ¦¦ cpu(x86_64))
print("Simulator")
#else
print("Device")#endif
SE-0190でhasTargetEnvironment()
が導入されたことにより、
#if hasTargetEnvironment(simulator)
print("Simulator")
#else
print("Device")
# endif
Hashableプロトコルの刷新
SE-0185がSwift 4.Equatable
とHashable
の自動生成がすでに使えるようになっています。ストアドプロパティすべてがEquatable
やHashable
に準拠している型なら、Equatable
やHashable
を付けるだけで……、
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
はできます。筆者は現在Hashable
はSwiftに自動生成してもらっています。ではNaN
などの扱いをどうしているかというと、FloatingPoint
プロトコルでは.isEqual()
というメソッドの実装を必須にしたうえでそちらで対応しているわけです。
このように自動生成が可能な場合でも手動で実装すればそちらが優先で使われるのですが、Hashable
はその代表格です。たとえば、
struct City {
let name: String
let state: String
let population: Int
}
という形があったとします。この場合population
はハッシュ値生成には不要なので、name
とstate
のハッシュ値を何らかの形で合成して.hashValue
を生成すればよさそうに見えます。Swift 4.
var hashValue: Int {
return name.hashValue ^ state.hashValue}
しかしこれはあまり良いやり方だとは言えません。衝突を起こす例は簡単に作れますname
とstate
の値を入れ替えただけでそうなる)。つまりhashdosに対して脆弱ということで、
そこでSE-0206が提案したのは、Hashable
には.hash()
というメソッドが追加され、Hashable
にする場合にもそれを使えということになりました。
func hash(into hasher: inout Hasher) {
name.hash(into: &hasher)
state.hash(into: &hasher)}
見てのとおり、
ランダム値生成機能を標準装備へ
これまでSwiftはランダム値を生成する機能は標準では持たず、import
してきました。こんな感じです。
#if os(iOS) ¦¦ os(tvOS) ¦¦ os(watchOS) ¦¦
os(macOS)
return Int(arc4random())
#else
return random() // or Int(rand())
#endif
ここにもHashable
同様、
let randomIntFrom0To10 = Int.random(in: 0 ..< 10)
let randomDouble = Double.random(in:0.0 ..< 1.0)
たいへんわかりやすい。もっと早くそうすべきだったと筆者は率直に感じています。
IUOの撤廃
SE-0054で提唱されていたIUO++
演算子の廃止同様にこの決定を支持します。ただし完全廃止ではなく、
func f() -> Int! { return 42 }
let i:Int = f() f()! でない点に留意
のようなケースは残るようです。筆者としては完全廃止でない点がちょっと残念です。演算子としての!
、
public prefix func !(v:Optional) {
return value ?? fatalError()
}
さえあれば、
排他的メモリアクセスの強制
次はたいへん行儀の悪いコードの例です。
extension Int {
mutating func assignResultOf(_ f: ()->Int) {
self = f()
}
}
var x = 0
x.assignResultOf { x + 1 } // NO!
print(x)
何が行儀が悪いかというと、
このようなコードは実行させる前に止めろというのがSE-0176の主旨で、
たとえば、1
と表示されますが、
Simultaneous accesses to 0x1094e3000, but
modification requires exclusive access
つまりより精細な解析が可能な場合は、
「徐々に」
var a = [0,1,2,3]
a.forEach {
print($0)
a.removeLast()
}
print(a)
ただしSE-0176はこれもブラックリストに入れており、
次回予告
というわけで次回からは前回予告どおり、
本誌最新号をチェック!
Software Design 2022年9月号
2022年8月18日発売
B5判/
定価1,342円
- 第1特集
MySQL アプリ開発者の必修5科目
不意なトラブルに困らないためのRDB基礎知識 - 第2特集
「知りたい」 「使いたい」 「発信したい」 をかなえる
OSSソースコードリーディングのススメ - 特別企画
企業のシステムを支えるOSとエコシステムの全貌
[特別企画] Red Hat Enterprise Linux 9最新ガイド - 短期連載
今さら聞けないSSH
[前編] リモートログインとコマンドの実行 - 短期連載
MySQLで学ぶ文字コード
[最終回] 文字コードのハマりどころTips集 - 短期連載
新生「Ansible」 徹底解説
[4] Playbookの実行環境 (基礎編)