post Image
余計なOptionalはやめてくれ

Optional型

Optional型はSwift入門者には結構ハマる点のようで、Qiitaにもよく記事が上がっているのを見かけます。

もちろんかなり趣味も大いにあると思うけれど、「空にできるのがOptional!」などという表現には、本質的でないと感じます。あくまで、nilは「空である」ことを意味する値だと思っています。

先日こんなツイートがありました。とても的を射ていて、わかりやすいと思います。

ただし、Swiftでは少し違うと思っていて、
Swiftでのnullは、本当に何もない、看板すらない状態だと思います。
そしてこの看板がOptionalであり、数字または nil がセットされます。

以降シチュエーションはすこし極端目に書きますが、もちろん似ていてもそうじゃないときも往々にしてあると思うので、ご容赦ください。

Optionalはめんどくさい

そもそも、Optionalは面倒くさい。
Optionalを画面に反映したり、サーバーに送ったりするには、必ずUnwrapしなければいけないので、直接の値のほうが嬉しい。

もちろん、Optionalが必要なシーンも多くありますし、自分もかなりの頻度で使います。

例:Bool?

例えば、Bool? 型の値の意味ってなんだろう?

let isValid: Bool?

さて、このコードで isValidnil だった時、その状態は果たしてvalidなのかinvalidなのか?

nilの意味

Optionalはnilまたは値を入れられる型だと考えます。
nilは何かしらの意味を持つべきで、意味が無いならOptionalを使うべきではない。

例えば、サーバーからのレスポンスは、届くまでに時間がかかる。この時に Bool? 型を使うのであれば、以下のようにみなせます。

意味
nil 通信前、通信中
true 通信の結果、true
false 通信の結果、false

値を入力してもらう画面の場合、

意味
nil 未入力
true 入力の結果、true
false 入力の結果、false

もちろん、Bool以外についても同じことが言えるし、こういうOptionalは積極的に使うべきだと思います。

ただ、例えばオブジェクトがvalidかどうかはどんな状態かによらず分かりたいし、 _isValid = nil がvalidかinvalidかはビジネスロジック依存だと思うので、getterなどで、外部へのインターフェースは非オプショナルのほうが良い場合も多いと思います。
これで、意味がより明確になります。

private var _isValid: Bool?
var isValid: Bool {
    return _isValid ?? false
}

デフォルト引数としてのnil?

init(color: UIColor? = nil) {
    if let color = color {
        self.color = color
    } else {
        self.color = .white
    }
}

引数がないことを表すnilです。が、これは本当に意味があるのでしょうか?

個人的にはプログラムの中で「引数がない」という情報はさほどどうでもよく、挙動の中で「どんな色であるか」という情報だけが大事だと考えます。
よって、以下のように書く方を好みます。

init(color: UIColor = .white) {
    self.color = color
}

?? 演算子と同じで、「デフォルト値である」ことがわかりやすくて良い気がしています。

?? 演算子

?? 演算子はアンラップを行うというより、Optiona -> 非Optionalへの変換だと感じています。

optionalValue ?? defaultValue

nilの時のデフォルト値を右辺に設定することで、非Optionalとみなせます。

エラーの時にnil?

関数の返り値で、「エラーの時にnilになります」という運用はどうでしょうか。自分は、throwsのほうが良い場合が多いと思います。

まず、throwableなメソッドの呼び出し時に、Optionalに変換することは簡単です。

// エラーを無視してOptionalに変換する、エラー時はnil
let a = try? throwable()

更に、nilだけだとエラーの内容はわかりませんが、throwすればcatchして中身を見ることができます。

もちろん実装コストはかかるので、エラーが明らかなときや何でも良い時、忙しいときは、Optionalでよいです。

でも結局あなたの趣味なんでしょ?

もちろん、その通りです。

例えばUILabelのtextはOptional型ですが、自分が実装するならOptionalにしないし、あまり何故かわかっていないです。

でも、自分は例えば登録後にサーバーに保存するユーザー名を "" でなくて nil にする必要はないと思うし、 "" にしてから保存します。

議論するの好きなので、どしどしお待ちしています!


『 Swift 』Article List