Swift
iOSDC

iOSDC 2018のトークが募集開始されたので、昨年僕が応募したトーク5本を振り返る

iOSDC 2018 のトークが募集開始されました!

実は、僕はまだ iOSDC 2017 参加者の宿題「iwillblog」を果たせていません🙇ずっと気がかりではあったんですが、書かないまま今日に至ってしまいました。

しかも、 iOSDC 2017 ではベストトーク賞入選で、欲しかった Apple TV 4K までいただいたのに・・・。

というわけで、昨年の iOSDC を振り返りつつ僕が去年書いた CfP を紹介します。 iOSDC 2018 に参加したい、トークの応募をしたいと考えている方の参考になればうれしいです。

iOSDC 2017

僕が初めてのカンファレンスに参加したのは try! Swift Tokyo 2016 でした。

try! Swift Tokyo 2016

僕はエンジニアコミュニティから隔絶された生活を送っていたんですが、 Swift が発表されたのをきっかけに時々 Qiita に投稿していたら try! Swift で発表しないかと声をかけていただきました。それは、僕にとってカンファレンスはおろか勉強会を含めてもほぼ初めての発表でした(新人の頃に一度だけ勉強会で発表したことがありました)。その発表が

  • 参加者数百人の国際カンファレンス
  • ( LT ではなく) 25 分枠
  • 英語

とスーパーハードモードだったので正直めちゃくちゃ大変でしたが、そのおかげで @cockscomb さんや @ikesyo さん、 @inamiy さん、 @ishkawa さんら、 iOS 界のスターエンジニアの皆さんと知り合うことができました(日本人スピーカーは数人だけ&スピーカー限定参加のイベントもあり、一緒に過ごす時間も長く親しくなれました)。 try! Swift に参加して感じたのが、プログラミングについて心ゆくまで話すのはめちゃくちゃ楽しい!ということです。マイナーな趣味を持つ人が初めて同じ趣味を持つ同志を見つけたような心境でしょうか。

そんなわけで、「カンファレンス楽しい! iOSDC も参加したい!」と思っていたのですが、スケジュールの関係で残念ながら iOSDC 2016 には参加できませんでした。みんなが楽しそうにしているタイムラインを横目に、「来年は絶対参加しよう」と心に誓ったのでした。

そして迎えた 2017 年、僕は地方在住なんですが、「せっかく東京まで行って参加するなら発表したい!」ということで、数撃ちゃ当たるだろうと 5 本のトークを応募しました。

結果、無事に "具体例とクイズで学ぶ、Swiftの4種類のエラーの使い分け" が採択されて iOSDC 2017 で発表できることになりました。

iOSDC Japan 2017

iOSDC 2017 は最高に楽しかったです。ここでは、印象に残っている出来事を三つ紹介します。

Kotlin の Non-local returns について

@ezura さんの発表 "Swift と Kotlin" をきっかけに、 Kotlin の Non-local returns の是非について、僕と @omochimetaru, @sonson さん、 @takasek さんなどの間で議論が盛り上がりました。

Kotlin の Non-local returns とは、次のようにラムダ式( Swift で言うところのクロージャ式)の中からラムダ式の外側の関数やメソッドを return させる仕組みです。

// Kotlin
// すべての要素が true なら true を返す関数
fun and(elements: List<Boolean>): Boolean {
    // fold は Swift の reduce に相当
    return elements.fold(true) { _, element ->
        // false の要素が出てきたら即時 false を返して and を終了
        if (!element) { return false }
        true
    }
}

同じ関数を Swift で実装すると次のようになります。

// Swift
// すべての要素が true なら true を返す関数
func and(of elements: [Bool]) -> Bool {
    return elements.reduce(true) { result, element in
        return result && element
    }
}

Swift の and の実装だと、最初の要素が false だったときにその時点で and の結果が false だと確定しても、 reduce は最後の要素まで計算を続けます。

// Swift
and(of: [false, true, true, true, true])

Kotlin の and の実装なら、 Non-local returns によって最初の要素の時点で andfalsereturn し、無駄な計算が行われません。

ラムダ式のスコープの外側に制御構文が作用するのは一見気持ち悪いように思えますが、次のように考えると違った視点が見えてきます。

Perl や Ruby には unless という if の反対の制御構文があります(条件が false なら実行)。

# Perl
unless( $a == 42 ) {
    # $a が 42 でないときに実行される
    return;
}

これを Kotlin で作ってみます。

// Kotlin
inline fun unless(condition: Boolean, body: () -> Unit) {
    if (!condition) { body() }
}

この unless は次のようにして使えます。

// Kotlin
unless(a == 42) {
    // a が 42 でないときに実行される
    return
}

もちろん、この { } の中の return{ } の外側の関数を return します。この { } はラムダ式ですが、 if{ } と同じように見えると return がラムダ式の外側に作用しているのが自然に感じられないでしょうか。

Swift の Trailing closures や Kotlin における同様の仕組みを使うと、制御構文と高階関数がよく似た見た目になります。

// Kotlin
if (a) {
    ...
}

while (a) {
    ...
}

foo(a) {
    ...
}

これらが同じような挙動を示すのはある意味一貫性があるとも考えられます1

そんなことを、昼休みに延々と話していました。ネット上で(顔を合わせずに)議論をするとすぐにケンカになったり、内容さえ正しければ正義と言わんばかりの無配慮なマサカリが飛んできたりしがちです。しかし、対面での議論だと平和に進行することが多く(マサカリを投げ合う勉強会の話も伝え聞くので、 iOS 界隈が平和なだけかもしれません)、あーだこーだ言いながらプログラミングについてとりとめもなく話すのはとても楽しいです。色んな人と顔を合わせてそのような話ができるのがカンファレンスの醍醐味だと思います。

個人的ベストトーク

僕が個人的にベストトークだと思ったのが @taketo1024 さんの『Swift で数学のススメ 〜 プログラミングと数学を同時に学べ』です。

内容のおもしろさも、トークの熱量も、話の進め方も最高です。僕は理想のトークの一つとして、いつもこのトークを思い描いています。

@taketo1024 さんとはいつの間にか相互フォローになり、たまにリプを送り合う間柄だったんですが、このときまでお会いしたことがありませんでした。オンラインの友人や知り合いと実際に会えるのもカンファレンスの楽しみです。

が、残念ながら iOSDC 2017 中は @taketo1024 さんと直接お話する機会がなく( Twitter ではやりとりしてました)、後日僕が主催する Swift Tweets発表していただいた際にたまたま僕の家に遊びに来ることになり、対面を果たしました。

飲み仲間を募ったら幻影旅団ができた

try! Swift 2017 のハッカソンでチームを組んだ @rintaro さんと再会し、最終日にでも飲みに行こうと盛り上がりました。そんなわけで iOSDC 2017 の期間中に出会った人や再会した知り合いに声をかけていたんですが、なにせ僕は普段は東京にいないですし知り合いも多くありません。必然的に声をかけるのは try! Swift で知り合ったスピーカー仲間(?)が中心になります。蓋を開けてみると、↓のような豪華メンバーが集結していました(あと何名かいらっしゃったんですが ID がわからず・・・すみません)。

このメンバーが集まって歩いている様子を、 HUNTER×HUNTER の幻影旅団のようだと思いながら後ろから眺めていました。

こんなすごいメンバーに混ざって飲みに行って貴重な話が聞けるのもカンファレンスならではです。

iOSDC 2017 の CfP

前置きが長くなってしまいましたが、僕が昨年応募したトーク 5 本を紹介します。

具体例とクイズで学ぶ、Swiftの4種類のエラーの使い分け

Swiftには4種類のエラー( https://goo.gl/kAj76N )があり、標準ライブラリもこれを使い分けています。この使い分けを知らないと適切なエラー設計ができません。また、知識として知っている人でも、実際のコーディングでうまく活かせていないのをよく見かけます。このトークでは、単なる知識にとどまらない実践的な考え方を身に付けられるように、エラーの使い分けをクイズ形式で考えてもらいながら具体例を通して説明します。

採択されて発表したトークです。

これ以前に Swift Tweets で "Swiftのエラー4分類が素晴らしすぎるのでみんなに知ってほしい" という発表をしたり、 try! Swift Tokyo 2016 でもこの 4 種類のエラーを元に話したりしたんですが、なかなか思うように伝わらないと感じていました。やっぱり、人間は一度自分で考えてみないと身に付きません。そこで、トークの途中でクイズを出題することで考えてもらい、参加者には選択肢の中から正解だと思うものに挙手してもらうといいんじゃないかと考えました。

悩みどころだったのが、出題するからには考えてもらう時間を設けなければいけないことです。問題に取り組むのは宿題形式にして後で考えてもらうことだってできます。そうすれば、 30 分という貴重な発表時間をフルにトークに使うことができます。 30 分の内、少なくない割合を考えてもらう時間に充てて、参加者に満足してもらえるだろうかと悩みました。

しかし、仮に僕が参加者だったら後で宿題をまずやらないだろうと思いました。僕が提供できる価値で一番重要なことは、トークを聞きに来てくれた人にその内容を身に付けて帰ってもらうことのはずです。それなら、多少時間を無駄遣いしているように思えても、その 30 分の中で得られるものを最大化する方がいいだろうと考えました。

結果的にこのクイズ形式は多くの方に評価してもらい、ベストトーク賞の 4 位に入賞できました。インタラクティブなクイズ形式にしたことは、その後も色んな場所で色んな人からよかったと言ってもらえたので、悩んだけれどもこの形式にしてよかったです。

iOSDC には数十本のトークと数百本の応募があります。採択やベストトーク賞を目指すには、何か少し変わったことをやってみるのも一つの手です。ただ、やりすぎてトークの本質を損ねたり、奇をてらっただけのものにならないように注意が必要です。

Swiftの!を恐れずに使おう!!

Swiftの!やtry!は安全性を崩す悪いもの、できるだけ使わない方が良いものとされることが多いように思います。しかし、Swiftのエラーに関する言語設計を考えると、if letやdo-try-catchより!やtry!を使った方が適切なケースはたくさんあります。このトークでは、どのようなケースで!を使うべき/使うべきでないのかを具体例を交えて説明し、適切なケースで!を恐れずに使えるようになることを目指します。

たとえば、↓のコードの ! は僕は良い使い方だと考えています。

let image = UIImage(named: "Foo")!

このコードが失敗するのはアプリに画像が正しくバンドルされてない場合です。通常、そのような場合には実行時に動的に対処する方法はなく(「4種類のエラーの使い分け」でいうところの Logic failure )、アプリを修正して正しく画像をバンドルすることによって対処すべきです。そのような ! を使うべきケース、使うべきでないケースを取り上げ、怖がらずに使うべきところでは ! を使おうというトークの予定でした。

これは、 "具体例とクイズで学ぶ、Swiftの4種類のエラーの使い分け" の内容の一部分にフォーカスし、切り口を変えて見せたものです。 iOSDC では複数のトークを応募することが推奨されており、そのように切り口を変えてどんどん応募して下さいと(たしか)公式にアナウンスされてました。この CfP はまさにそれを体現したものです。

このトークで話したかったような内容は、 @hironytic さんが先日 Qiita に投稿していたので御覧下さい。

Swiftのassert, precondition, fatalErrorをどのように使い分けるか

Swiftにはassert, assertionFailure, precondition, preconditionFailure, fatalErrorと似たような関数があります。当然それらの挙動は異なるのですが、使い分けが曖昧に済まされていることが多いように思います。いつ・どれを使うべきかを考えるにはSwiftのエラーについての考え方を理解する必要があります。このトークでは、背景となる考え方とassert等の使い分けを具体例を通して説明します。

これも "具体例とクイズで学ぶ、Swiftの4種類のエラーの使い分け" の切り口を変えたものです。ただ、実際の発表の中では練習段階から時間が足らず、この内容については省いて後日まとめるという宿題にさせてもらいました。

その宿題は Mobile Act OSAKA #2 での LT と Qiita の Advent Calendar の投稿を兼ねる形で一石三鳥でこなしました。

ライブコーディングでArrayを実装してCopy-on-writeの挙動を理解する

SwiftではArrayやDictionary等のコレクションは値型ですが、Copy-on-write(以下COW)という仕組みで不要なコピーが発生しないように作られています。COWによるコピーは代入時ではなくlazyに発生するので、仕組みを理解していないとパフォーマンスチューニング上の問題が生じることがあります。このトークでは、COWを使ったMyArrayをライブコーディングで実装し、その仕組みを説明します。

COW は Swift において重要な役割を果たしています。 Swift は値型中心の言語ですが、そのためには ArrayDictionary のようなコレクションが値型であることが欠かせません。たとえば、 Swift と同じく structclass を持つ C# では、コレクションはクラス(参照型)です。

// C#
var a = new List<int> { 2, 3, 4 };
var b = a;
a[2] = 5;
Console.WriteLine(string.Join(", ", a.Select(e => e.ToString()))); // 2, 3, 5
Console.WriteLine(string.Join(", ", b.Select(e => e.ToString()))); // 2, 3, 5
// Swift
var a = [2, 3, 4]
var b = a
a[2] = 5
print(a) // [2, 3, 5]
print(b) // [2, 3, 4] ← 最後の要素が 4 になる

コレクションを使わずにコードを書くことは困難なので、 C# では値型だけでコードを簡潔させることは難しく、主役はクラスになります。 Swift ではコレクションも値型なので、値型だけでコードを完結させることも可能です。

しかし、単純に値型のコレクションを作って代入の度にバッファを丸ごとコピーするのは、パフォーマンス的にとても現実的ではありません。 100 万個の要素を持つ Array を代入したり引数に渡したりしたときに 100 万要素分のメモリ領域をコピーしていたらとんでもないことになってしまいます。

そのような事態を避けるために Swift では COW が使われています。その挙動を理解するにはやはり作ってみるのが一番です。このトークは、ライブコーディングで過程を見せながら COW について解説しようというものでした。

コーディング面接やペアプロをやったことがある人だとわかると思いますが、完成したコードを見るのとコードが書かれる過程を見るのでは、コードに対する理解がまるで異なります。過程を見ると、そのプログラマが何を考えてそれを書いたのかが手に取るようにわかります。 COW の話は目で見えるものでないのでどのように動作しているのかわかりづらいですが、ライブコーディングにすることで伝わりやすいのではないかと考えました。

同時に、ライブコーディングには採択を勝ち抜くための変わり種としての側面もありました。僕はライブコーディングで発表したことはないですが、イメージしているのは @ishkawa さんの try! Swift Tokyo 2016 のトークです。

これがめちゃくちゃおもしろかったので、いつか自分でもやってみたいと思っています。

Promiseに失敗はいらない

最近では、Promiseは非同期処理のための当たり前の道具としてプログラマーの間で広く受け入れられていると思います。しかし、一番大きな影響を与えたであろうJavaScriptのPromiseは非同期処理だけでなくエラー処理の仕組みも含んでいます。それをそのまま持ってきても、型による安全なエラー処理機構を持つSwiftには馴染みません。このトークでは、Promiseからエラー処理を取り除き、どのようにして非同期エラー処理を行うかについて説明します。

僕が初めて JavaScript の Promise を知ったとき、すぐに違和感を感じました。非同期処理だけでなくエラー処理も内包していたからです。

Optional は値があるかもしれないし存在しない( nil )かもしれないことを表すものなら、 Promise は今はまだ値がないけど将来のどこかで手に入るものを表します。そのように考えると、 PromisethenmapflatMap に対応することに気付きました。

let a: Optional<Int> = ... // 存在するかしないかわからない値
let b: Optional<Int> = a.map { $0 * $0 } // 存在するならそれを 2 乗
let a: Promise<Int> = ... // 将来のいつか手に入る値
let b: Promise<Int> = a.map { $0 * $0 } // 手に入ったときにそれを 2 乗

『すごい Haskell 』風に言うと、 Optional は存在するかわからないという文脈を、 Promise は将来のいつか手に入るという文脈を持ちます。しかし、 JavaScript の Promise は将来のいつか手に入るという文脈と、エラーかもしれないという文脈を両方抱え込んでいるように見えました。エラーかもしれないという文脈は別のもので表して、それらを組み合わせて利用した方がキレイです。

let a: Promise<Result<Int>> = ... // 将来のいつか手に入る、エラーかもしれない値

これを実現するために、僕は PromiseK というライブラリを作りました。

この話は Swift 5 で導入されそうな async/await につながっていて、 PromiseResult が独立であることと、 async/awaitthrows/try が独立であることがキレイに対応しています。これは、僕が try! Swift 2016 で話したテーマの一部であり、 Swift の言語機能として提案したいと思っていたことであり、何年間もおもしろいと思っていたテーマです。

ちょうど CfP を提出してから iOSDC が行われるまでの間に Swift の async/await が提案されたので、もしこのトークが採択されていたらちょうど良いタイミングで async/await についてのおもしろい話ができたと思います。残念ながらこのトークは採択されませんでしたが、より大きな枠組みの話にまとめて Swift Tweets で発表しました。

このトークは特に何か変わり種を仕込んだわけではないですが、僕ができる一番おもしろい(と思う)話の一つだったので応募しました。変わり種を仕込むのもいいですが、一番大事なのは自分がおもしろい、聞いてほしいというテーマを選ぶことだと思います。

iOSDC 2018 の CfP

ついでに、今年僕が応募したトークも紹介します。

ライブコーディングで、Swiftの値型の特性を活かしてiOSアプリを作る

Swiftは値型中心の言語です。標準ライブラリで提供されている型はほぼすべてが値型です。値型を活用することでミュータブル/イミュータブルクラスのいいとこどりをし、簡潔でメンテナンス性の高いコードを書くことができます。しかし、Obj-CやUIKitの影響もあり、iOSアプリは今も参照型中心で開発されることが多いように思います。このトークでは、ライブコーディングでアプリを丸々一つ作り、値型の特性を活かしたiOSアプリの開発手法を紹介します。

このところ、僕が力を入れて話しているのが Swift と値型についてです。次のように、色々なところで値型をテーマに話しています。

しかし、これまで値型を直接 iOS アプリ開発と結びつけた話はできていません。というか、意図的にしてきませんでした。 iOS アプリ開発について話すなら iOS DC はうってつけです。昨年 iOSDC 2017 に参加したときから「来年はこのテーマで応募しよう」と考え温存してきました。

ライブコーディングにしたのは、数行の簡単なサンプルコードならともかく、アプリのように複雑なものをスライド上で短時間で理解するのは困難だと思うからです。↑で

コーディング面接やペアプロをやったことがある人だとわかると思いますが、完成したコードを見るのとコードが書かれる過程を見るのでは、コードに対する理解がまるで異なります。過程を見ると、そのプログラマが何を考えてそれを書いたのかが手に取るようにわかります。

と書いた通り、このトークテーマのようにある程度の分量のあるコードを理解してもらうには、ライブコーディングは一つの有効な手法だと思います。そして、

僕はライブコーディングで発表したことはないですが、イメージしているのは @ishkawa さんの try! Swift Tokyo 2016 のトークです。
これがめちゃくちゃおもしろかったので、いつか自分でもやってみたいと思っています。

これを実現する機会でもあります。この後、まだ何本か CfP を出そうとは思っていますが、是非ともこのトークテーマで発表したいです!


  1. ただし、制御構文で実現ができるけれども高階関数では実現できないこともあります。