【Swift】3.0でどうやら`Self`が拡張されるみたい

Wednesday, May 11, 2016

Githubのwatchで、swift-evolutionにどんな提案が追加されたのか、 accept されたのか見たりしているのですが、
最近みていて気になったものがあったのでピックアップしてみました。

一部の例はproposal内のものを引用したりしています。
(※この記事では完全な和訳などはしていません。要点絞って自分の解釈で書いております。)

“Expanding Swift Self to class members and value types”

今まで、Selfは自分自身の型を指すものとして使われていて、特にプロトコルと相性が良いものでした。

protocol HogeProtocol {
    func myType() -> Self
}

// HogeProtocolを適応する

class Fuga: HogeProtocol {
    // ここでSelfはそのまま使えないので、自分自身の型を書く
    func myType() -> Fuga {
        // ...
        return Fuga()
    }
}

ただ、あくまでも自分自身の型を指すよ〜って宣言できるだけで、実際に型として使うことができません。
上記の例だと、プロトコル定義ではSelfとして(仮で)自分自身の型だよと記述はできますが、プロトコルを適応した際に、Selfをそのまま使うことができません。

そんなSelfが、Swift3.0では進化するようです。

class/staticメソッドを呼び出す

例えば、以下のように、インスタンスメソッド内から、自分自身のclass/staticメソッドを呼び出す場合、以下の2パターンがあります。

struct MyStruct {
    static func staticMethod() { ... }
    func instanceMethod() {
        MyStruct.staticMethod() // 1
        self.dynamicType.staticMethod() // 1
    }
}

Objective-C だと、

@implementation MyClass
+ (void)staticMethod
{
    ...
}

- (void)instanceMethod
{
    [MyClass staticMethod]; //1
    [[self class] staticMethod]; //2
}
@end

となります。

1の場合、型がMyStructに固定されてしまうので、この例ではstructですが、 class だった場合にこのように書いてしまうと、常にそのクラスのstaticメソッドが呼ばれてしまうため、staticMethodをオーバーライドした場合に困ったことになります。
そういう場合には、2のように、 self.dynamicType を書いてあげることで、Objective-Cの、 [self class] と同様の事が行えます。
しかし、

  • dynamicTypeは、今後のSwiftのガイドライン(?)でもある、lowercased keywordの規則に沿わないものである
  • self.dynamicTypeより、Selfと書けたほうが明らかに短く書ける
  • 例えば、MyExtremelyLargeTypeNameという型名だった場合に、MyExtremelyLargeTypeName.staticMethod()と書くよりは、Self.staticMethod()と書くほうが簡単にアクセスできて、かつ短く書くことができる
  • 型の名前が変わっても、型名をハードコーディングしなくて済むので、修正の手間が減る

・dynamicType remains an exception to Swift’s lowercased keywords rule. This change eliminates a special case that’s out of step with Swift’s new standards.
・Self is shorter and clearer in its intent. It mirrors self, which refers to the current instance.
・It provides an easier way to access static members. As type names grow large, readability suffers. MyExtremelyLargeTypeName.staticMember is unwieldy to type and read.
・Code using hardwired type names is less portable than code that automatically knows its type.
・Renaming a type means updating any TypeName references in code.
・Using self.dynamicType fights against Swift’s goals of concision and clarity in that it is both noisy and esoteric.


などといった事が考えられ、`Self`を拡張しようという提案が出され、承認されたようです。

Swift3.0ではこうなる…?

元記事には提案された場合の具体例が載ってはいないのですが、

struct MyStruct {
    static func staticMethod() { ... }
    func instanceMethod() {
        Self.staticMethod()
    }
}

のように スッキリ 書くことができるんじゃないかと思ってます。
あとは、Expanding Swift Self to class members and value typesと言われているので、

protocol HogeProtocol {
    func myType() -> Self
}

class Fuga: HogeProtocol {
    func myType() -> Self {
        return Fuga()
    }
}

といった形でそのままSelfが使えるのかもしれないです。ここは完全に推測ですが。。



しっかり訳せてなくて、所々間違っているかもなので何かあればブコメなりでご指摘もらえればと思います。
都度情報は追って、修正すべきところは直していきます。

Swift3.0楽しみ。

おまけ

提案するにあたってのやりとりは、ここで見れます。

techSwiftSwift3.0

【RxSwift】毎回DisposeBagを作るのから解放されたい

会社のTech Blogを書きました