swift-evolution note 6/5

WWDC 2019が開催されましたね！
個人的にはSwiftUIで盛り上がっていました。

そんなSwiftUIのサンプルコードに次のようなものがありました。

```swift
struct Content: View {
  @State var model = Themes.listModel

  var body: some View {
    List(model.items, action: model.selectItem) { item in
      Image(item.image)
      VStack(alignment: .leading) {
        Text(item.title)
        Text(item.subtitle)
          .color(.gray)
      }
    }
  }
}
```
(from: https://developer.apple.com/xcode/swiftui/)

この短いコードにはSwift5まででは実現できない機能が複数含まれています。
しかし、ほとんどは突然出てきた機能ではなく、[Swift Forums](https://forums.swift.org)で提案され、コミュニティが議論し、Core Teamがレビューして実装された機能です。

この記事では、[swift-evolutionのproposals](https://github.com/apple/swift-evolution/tree/master/proposals)から自分が興味深いと思った機能を(適当に)拾い、紹介します。

ただし、全てのSwift5.1の新機能は紹介しませんし、個人的に面白いと思った[Opaque Result Type](https://github.com/apple/swift-evolution/blob/master/proposals/0244-opaque-result-types.md)はすでに素晴らしい紹介記事があるのでここでは言及しません。

[Swift 5.1 に導入される Opaque Result Type とは何か - Qiita](https://qiita.com/koher/items/338d2f2d0c4731e3508f)

またテンプレですが、間違いがあった場合などはご指摘をお願いします :bow: 

## Implemented (Swift 5.1)
すでにマージされていてSwift5.1から使えるようになる提案。

### [Synthesize default values for the memberwise initializer](https://github.com/apple/swift-evolution/blob/master/proposals/0242-default-values-memberwise.md)

Swift5までは以下のようにstructを書くとイニシャライザが自動生成されていました。

```swift
struct Dog {
  var age: Int = 0
  var name: String
  
  // ↑を書くと↓のイニシャライザが自動生成される
  init(age: Int, name: String)
}

// Dog.ageにはデフォルト値があるが、イニシャライザで指定する必要がある
let dog = Dog(age: 0, name: "Sparky")
```

しかし`age`にはデフォルト値として`0`があるので以下のようなイニシャライザを生成してほしいよねという提案。

```swift
struct Dog {
  var age: Int = 0
  var name: String
  
  // ↑を書くと↓のイニシャライザが自動生成される
  init(age: Int = 0, name: String)
}

// ageがデフォルト値でいい場合、省略可能になった！
let dog = Dog(name: "Sparky")
```

なお、注意点としてTupleの場合はデフォルト値にはならないみたいです。

```swift
struct Dog {
  var (age, name) = (0, "Sparky")
  
  // init(age: Int = 0, name: String = "Sparky")とはならない
  init(age: Int, name: String)
}
```

またプロパティがletの場合は今まで通りイニシャライザは生成されません。

```swift
struct Dog {
  let age: Int = 0
  var name: String
  
  // ageは自動生成されない
  init(name: String)
}
```


### [Key Path Member Lookup](https://github.com/apple/swift-evolution/blob/master/proposals/0252-keypath-dynamic-member-lookup.md)

Swift4.2ではDynamic Member Lookupが追加されました。

[[参考]Swift4.2で導入された機能 Dynamic Member LookupでSwiftのコードをよりCOOLにしよう - Qiita](https://qiita.com/tamappe/items/191382e8c11c6a91e3f9)

これにより、実行時にプロパティを決定することが可能になり、動的型言語との親和性が向上しました。

ところで、実行時にプロパティを決定できる方法がSwiftにはまだあります。

その1つがKeyPathです。

KeyPathを使うことで特定の状況で簡潔に書くことができます。

```swift
// これは多分コンパイルエラー起こしそうだけど雰囲気で。。。
struct Lens<T> {
  let getter: () -> T
  let setter: (T) -> Void

  var value: T {
    get {
      return getter()
    }
    set {
      setter(newValue)
    }
  }
}

extension Lens {
  func project<U>(_ keyPath: WritableKeyPath<T, U>) -> Lens<U> {
    return Lens<U>(
        getter: { self.value[keyPath: keyPath] },
        setter: { self.value[keyPath: keyPath] = $0 })
  }
}
```

KeyPathを使わない場合上の例だとprojectでクロージャを渡したり色々面倒そうですね。


アクセスは以下のようにできます。

```swift
struct Point {
  var x, y: Double
}

struct Rectangle {
  var topLeft, bottomRight: Point
}

func projections(lens: Lens<Rectangle>) {
  let topLeft: Lens<Point> = lens.project(\.topLeft)
  let top: Lens<Double> = lens.project(\.topLeft.y)
}
```

現時点でも結構簡潔なのですが、いちいち`\.topLeft`や`\.topLeft.y`のように`\`を使用しなくていいよね、直接`lens.topLeft`のようにアクセスしたいよね、ということで以下のように書けるようにしようぜという提案。

```swift
@dynamicMemberLookup
struct Lens<T> {
  let getter: () -> T
  let setter: (T) -> Void

  var value: T {
    get {
      return getter()
    }
    set {
      setter(newValue)
    }
  }

  subscript<U>(dynamicMember keyPath: WritableKeyPath<T, U>) -> Lens<U> {
    return Lens<U>(
        getter: { self.value[keyPath: keyPath] },
        setter: { self.value[keyPath: keyPath] = $0 })
  }
}

func projections(lens: Lens<Rectangle>) {
  // コンパイラは`let topLeft = lens[dynamicMember: \.topLeft]`に展開する
  let topLeft: Lens<Point> = lens.topLeft
}
```

基本的に文字ベースの@dynamicMemberLookupと似た感じであり、以下のようなルールになります。

- KeyPathに指定できるのは@dynamicMember型に含まれないプロパティ名
  - `Lens<Rectangle>.topLeft`プロパティがあった場合、`lens.topLeft`としても`Rectangle`の`topLeft`にはアクセスできない(隠蔽される)
- @dynamicMemberLookupはextensionには書けない
- @dynamicMemberLookupには引数ラベルがdynamicMemberで型がkey path型(e.g., KeyPath, WritableKeyPath)の単一のパラメータ
- 文字列ベースとKeyPathベースの両方のdynamicMemberがあった場合、KeyPathが優先される
  - 文字列よりKeyPathのほうがより多くの情報を持っているため




### [Static and class subscript](https://github.com/apple/swift-evolution/blob/master/proposals/0254-static-subscripts.md)

今までインスタンス限定だったsubscriptをstatic(とclass)プロパティでも使えるようにしようぜという提案。

以下みたいな感じ。

```swift
public enum Environment {
  public static subscript(_ name: String) -> String? {
    get {
      return getenv(name).map(String.init(cString:))
    }
    set {
      guard let newValue = newValue else {
        unsetenv(name)
        return
      }
      setenv(name, newValue, 1)
    }
  }
}

Environment["PATH"] += ":/some/path"
```

また、@dynamicMemberLookupを使って以下のようにも書けるようになります。

```swift
@dynamicMemberLookup
public enum Environment {
  public static subscript(_ name: String) -> String? {
    // as before
  }

  public static subscript(dynamicMember name: String) -> String? {
    get { return self[name] }
    set { self.name = newValue }
  }
}

Environment.PATH += ":/some/path"
```

結構便利そう。

これにKeyPath member lookupみたいにKeyPathでもアクセスできるようになればもっと便利そうですが、staticなKeyPathは結構複雑らしく、この提案には含まれません。



### [Implicit returns from single-expression functions](https://github.com/apple/swift-evolution/blob/master/proposals/0255-omit-return.md)

クロージャは単一の式である場合、returnを省略できます。
それを普通の関数とかでも認めようという提案。

以下のように書けます。

```swift
// 今までクロージャでしか書けなかったけど...
let closure: () -> Int = { 1 }

// 関数でもOK!
func add(lhs: Int, rhs: Int) -> Int { lhs + rhs }

var location: Location {
  get {
    // getでもOK!
    .init(latitude: lat, longitude: long)
  }
  set {
    self.lat = newValue.latitude
    self.long = newValue.longitude
  }
}

struct Echo<T> {
  // subscriptでもOK!
  subscript(_ value: T) -> T { value }
}

class Derived: Base {
  // initでも書けるけど実質nilだけを返す場合のみ
  required init?() { nil }
}
```

なおこの提案は破壊的変更が含まれているのですが、該当するパターンは以下です。

```swift
func bad(value: Int = 0) -> Int { return 0 }
func bad() -> Never { return fatalError() }

func callBad() -> Int { bad() }
```

現在のSwiftのバージョンでは`callBad`を読んだ場合、`() -> Never`のほうの`bad`で解決されます。
しかし、この提案では`(value: Int = 0) -> Int`のほうの`bad`で解決されるようになるみたいです。

ただこのようなパターンは非常にレアで、実際互換性チェックのテストは問題なく動いているようです。

また、KotlinやScalaでは単一の式であった場合、`{}`自体を省略できます。

```kotlin
// Kotlin
fun squareOf(x: Int): Int = x * x
```

```scala
// Scala
def squareOf(x: Int): Int = x * x
```

ただこれをSwiftでやろうとすると以下のようなときに問題になります。

```swift
class Foo {
  var get: ()
  var value: Void {
    // このときの get = () は
    // get { return () } ?
    // self.get = () ?
    get = ()
  }
}
```

新しい文法にもなるため、言語の複雑度を上げてまで取り入れない模様。

またRustでは単一式ではなく、関数中の最後の式もセミコロンをつけなければ戻り値になります。

```rust
fn call() -> i64 {
  foo();
  bar();
  baz()
}
```

ただSwiftで似たようなことをやる場合、例えば以下の関数

```swift
func evenOrOdd(_ int: Int) -> EvenOrOdd {
  if int % 2 == 0 {
    return .even
  }
  
  .odd
}
```

`.odd`は省略できているのに`.even`はreturnが必須で少し残念です。

Rustではifも式なので以下のように書けます。

```rust
fn even_or_odd(i: i64) -> EvenOrOdd {
  if i % 2 == 0 {
    EvenOrOdd::Even
  } else {
    EvenOrOdd::Odd
  }
}
```

Swiftもifを式にすればいいのですが、それは大きな変更でありこの提案の範囲外になります。

なお、冒頭に書いたSwiftUIのサンプルコードで

```swift
var body: some View {
    List(...)
}
```

のようなget-onlyなプロパティでreturnがないコードが出てきましたが、この提案の機能を使っているそうです。

## Accepted
採用され将来的にSwiftに実装される予定の提案。

### [Key Path Expressions as Functions](https://github.com/apple/swift-evolution/blob/master/proposals/0249-key-path-literal-function-expressions.md)

以下のようなstructがあった場合、

```swift
struct User {
  let email: String
  let isAdmin: Bool
}
```

`User`の配列から`email`だけを取得したい場合、Swiftではよく以下のように書きます。

```swift
users.map { $0.email }
```

でもいちいちあるプロパティだけを参照するのにクロージャで書くのめんどいよね、Swiftには特定のプロパティを指定する構文がすでにあるよねということで以下のように書きたい。

```swift
users.map(\.email)
```

ただmapとかfilterとかにKeyPathのオーバーロードを追加していくのは負けだよねということで上のように書いたら以下のようなコードをコンパイラが生成するようにしない？という提案。

```swift
//↓を書くと
users.map(\.email)

//↓のようなコードに展開される
users.map { $0[keyPath: \User.email] }
```

現状、一旦変数に入れて型推論した場合は (Root) -> Valueにはなりません。

```swift
// users.mapを考慮して (Root) -> Valueに展開して欲しいが・・・・
let f = \User.email
// 現状はそうならず、KeyPath<User, String>になってしまう
users.map(f) // error: Cannot convert value of type 'WritableKeyPath<Person, String>' to expected argument type '(Person) throws -> String'

// 型を指定すればセーフ
let f: (User) -> String = \.email

// キャストしてもセーフ
let f = \.email as (User) -> String

// 実際には↓のように展開される
let f: (User) -> String = { kp in { root in root[keyPath: kp] } }(\User.email)
```

また子プロパティを指定したりselfで自分を指定したりできます。

```swift
users.map(\.email.count) // ok
[1, nil, 3, nil , 5].compactMap(\.self) // ok
```

注意点として、関数としてのKeyPath式の中に関数等の処理を書いた場合、関数が呼び出されるたびに中の処理も呼び出されるのではなく、KeyPath式が評価されたときに処理が呼び出されます。

```swift
var nextIndex = 0
func makeIndex() -> {
  defer { nextIndex += 1}
  return nextIndex
}

let getFirst = \Array<Int>.[makeIndex()]
// ↑のように書いた場合、Compilerは↓のようなコードを生成する
// let index = makeIndex() // 1
// let getFirst = { array: Array<Int> in array[index] }

let getSecond = \Array<Int>.[makeIndex()]

// なので何回呼び出しても同じindexを参照する
assert(getFirst([1, 2, 3]) == 1) 
assert(getFirst([1, 2, 3]) == 1)
assert(getFirst([1, 2, 3]) == 1)
assert(getSecond([1, 2, 3]) == 2)
assert(getSecond([1, 2, 3]) == 2)
assert(getSecond([1, 2, 3]) == 2)
```

### [Callable values of user-defined nominal types](https://github.com/apple/swift-evolution/blob/master/proposals/0253-callable.md)

現在、Swiftでは関数のように呼び出し可能な値が3つあります。

- 関数型の値
- 型名
  - Tのような型があった場合T()と呼べる(実際はT.init()になる)
- @dynamicCallable型の値

しかし、以下のような型がある場合

```swift
struct Adder {
  var base: Int
  func add(_ x: Int) -> Int {
    return base + x
  }
}

let add3 = Adder(base: 3)
add3.add(10) // => 13
```

`Adder`は型でaddすることを表現しておりそれに対してaddを呼ぶのは文法的に少し冗長です。
ということで以下のように呼びたいよねという提案。

```swift
struct Adder {
  var base: Int
  func call(_ x: Int) -> Int {
    return base + x
  }
}

let add3 = Adder(base: 3)
add3(10) // add3.call(10) に展開される
```

callメソッドを定義することで関数型のように値から直接関数を呼び出せるようになります。

なお`callable value`(call メソッドを持っている値)は暗黙的に関数型にはできない予定です(やるとしてもあとで)

```swift
let add1 = Adder(base: 1)
let f: (Int) -> Int = add1 // コンパイルエラー(予定)
let f: (Int) -> Int = add1.call // やるとしたらcallを直接指定
let f = add1 as (Int) -> Int // もしかしたらasキャストはOKになるかも？
```

また、これを利用して関数型をprotocolのように使うことによって効率化できる可能性があるそうです。

```swift
struct BoundClosure<T, F: (T) -> ()>: () -> () {
  var function: F
  var value: T
  
  func call() { return function(value) }
}

let f = BoundClosure({ print($0)}, x)
f()
```

こうすることでクロージャのサイズをあらかじめ決定でき、最適化されやすくなるそうです(Rustとかは似たようなことをやっているっぽい)
参考: https://forums.swift.org/t/pitch-introduce-static-callables/21732/2
(ここいらへん詳しくないので誰か・・・)

なお呼び出し方は色々提案されたみたいです。

`call`という名前の代わりに`apply`または`invoke`にしようという提案もありましたが、以下の理由により`call`が優勢っぽいです。

- Swiftっぽくない
  - [Functions — The Swift Programming Language (Swift 5)](https://docs.swift.org/swift-book/LanguageGuide/Functions.html) でも`apply`や`invoke`という言葉を使わずに、関数呼び出しは"function calls"という言葉を使っている。

- `apply` や `invoke` は SwiftのAPIガイドラインに沿っていない。
  - APIガイドラインでは副作用のあるなしで関数名を変更(副作用のある場合は動詞、ない場合は動詞+edなど)するが、`apply`や`invoke`は明らかに動詞
  - 一方`call`は動詞でも名詞でもあるのでこちらのほうが自然

また、以下のように特殊な文法を使う提案もありました。

```swift
struct Adder {
  var base: Int
  
  // 関数名がない方法
  func(_ x: Int) -> Int {}
  
  // 関数名を_(underscore)で書く方法
  func _(_ x: Int) -> Int {}
  
  // `self` keyword を使う方法
  func self(_ x: Int) -> Int {}
  
  // call という修飾子を使う方法
  call func(_ x: Int) -> Int {}
}
```

ただし、これらは上で述べた

```swift
let f = add1.call
```

みたいなことをしたいときに困ります。
またcall修飾子をつける方法はパーサに変更が入り、シンプルではありません。
その点`call`メソッドによる方法は`.init`と動作が一致しており、統一的です。

また属性ベースやProtocolベースの提案もありましたが、どれもノイズが多くなるなどで結局`call`のほうが良いという方向っぽいです。

---


私がこの部分を書いていたときは提案のレビュー中だったのですが、レビューが終了し、Acceptされました。
ただCore Teamは`call`という名前ではなく`callFunction`に修正しています(ただ、`callFunction`は不評で、このあとでさらに`callAsFunction`に[変更しています](https://forums.swift.org/t/accepted-with-modification-se-0253-callable-values-of-user-defined-nominal-types/24605/166))

[[Accepted with Modification] SE-0253 - Callable values of user-defined nominal types - Announcements - Swift Forums](https://forums.swift.org/t/accepted-with-modification-se-0253-callable-values-of-user-defined-nominal-types/24605)

また、しれっと書いてあるのですが、Core Teamは`@dynamicCallable`や`@dynamicMemberLookup`について、属性をつける制限を外す検討をしているようです。


## Returned for revision
議論し直し。

### [Eliding commas from multiline expression lists](https://github.com/apple/swift-evolution/blob/master/proposals/0257-elide-comma.md)

現在Swiftでは1行に複数のステートメントを書くのでなければ末尾のセミコロンはオプショナルでつけてもつけなくてもどちらでも大丈夫です。

```swift
let a = 1 //;は必要ない
let b = 1; // もちろん明示的につけてもOK
```

ところで関数呼び出し時は引数が複数ある場合カンマで分ける必要があります。

```swift
let a = foo(
  bar: bar(),
  baz: baz(),
  nyarn: nyarn()
)
```

これをセミコロンみたいに改行で区切れるようにしてカンマを消そうぜという提案。

```swift
let a = foo(
  bar: bar()
  baz: baz()
  nyarn: nyarn()
)
```

これにより地味に便利なのが引数リストの最後をコメントアウトしたいとき。

カンマありの場合最後の引数をコメントアウトするとエラーになります。

```swift
print(
  "red",
  "green",
  "blue", // error: unexpected ',' separator
//  "cerulean"
)
```

しかしカンマなしならそのままコンパイルが通ります。

```swift
print(
  "red"
  "green"
  "blue" // OK!
//  "cerulean"
)
```

なお配列リテラルは最後がカンマでもコンパイルは通ります。

```swift
let array = [
  1,
  2, // OK!
//  3,
]
```

関数の引数でも最後のカンマを許可すればいいじゃないかという意見もありますが、前に似たような議論があり、却下されています。
[Allow trailing commas in parameter lists and tuples](https://github.com/apple/swift-evolution/blob/master/proposals/0084-trailing-commas.md)


なおこの提案についてCore Teamの

- Chris Lattner氏は[反対しています](https://forums.swift.org/t/se-0257-eliding-commas-from-multiline-expression-lists/22889/89)。
- Douglas Gregor氏は[支持しています](https://forums.swift.org/t/se-0257-eliding-commas-from-multiline-expression-lists/22889/92)。
- Ben Cohen氏は[支持しているみたいです](https://forums.swift.org/t/se-0257-eliding-commas-from-multiline-expression-lists/22889/97)?
- Ted Kremenek氏(Project Lead)は[Code of Conduct](https://swift.org/community/#code-of-conduct)を守って議論してねと[言っています](https://forums.swift.org/t/se-0257-eliding-commas-from-multiline-expression-lists/22889/191)。

個人的にはカンマをつけるのがめんどくさいときがあったのでなるほどなあという気持ちです。

### [Property Delegates](https://github.com/apple/swift-evolution/blob/master/proposals/0258-property-delegates.md)

端的に言うとKotlinのDelegated PropertiesみたいなのをSwiftにも導入しようぜという提案。

以下のように定義すると

```swift
@propertyDelegate
enum Lazy<Value> {
  case uninitialized(() -> Value)
  case initialized(Value)

  init(initialValue: @autoclosure @escaping () -> Value) {
    self = .uninitialized(initialValue)
  }

  var value: Value {
    mutating get {
      switch self {
      case .uninitialized(let initializer):
        let value = initializer()
        self = .initialized(value)
        return value
      case .initialized(let value):
        return value
      }
    }
    set {
      self = .initialized(newValue)
    }
  }
}
```

以下のように使えるようになります。

```swift
@Lazy var foo = 1738
```

コンパイラは上記の`@Lazy`がついたプロパティを見つけると以下のように展開する想定です。

```swift
var $foo: Lazy<Int> = Lazy<Int>(initialValue: 1738)
var foo: Int {
  get { return $foo.value }
  set { $foo.value = newValue }
}
```

なおこの$fooはコンパイラが生成する値ですが、コード上でもアクセスできる予定です。

```swift
extension Lazy {
  /// newValue で初期化し直す
  mutating func reset(_ newValue:  @autoclosure @escaping () -> Value) {
    self = .uninitialized(newValue)
  }
}

$foo.reset(42)
```

また`delegateValue`という値を定義することで`$foo`でアクセスしたときに`delegateValue`の値を使えます。

```swift
protocol Copyable: AnyObject {
  func copy() -> Self
}

@propertyDelegate
struct CopyOnWrite<Value: Copyable> {
  init(initialValue: Value) {
    value = initialValue
  }
  
  private(set) var value: Value
  
  var delegateValue: Value {
    mutating get {
      if !isKnownUniquelyReferenced(&value) {
        value = value.copy()
      }
      return value
    }
    set {
      value = newValue
    }
  }
}

@CopyOnWrite var storage: MyStorageBuffer

let index = storage.index(of: ...)
// delegateValue が参照される
$storage.append(...)
```

ちなみに現在Swiftでは`$`で始まる変数名を許可していません。
なのでこの提案が採用された場合、その制限は緩められる予定です。
ただし、今までと同じように自分で定義することはできません。

```swift
@Lazy var x = 17
print($x) // OK
let $y = 17 // error: cannot declare entity with $-prefixed name '$y'
```

この提案は議論し直しとなり、以下のProposalのような方向性で議論しています。

[swift-evolution/0258-property-wrappers.md at property-wrappers · DougGregor/swift-evolution · GitHub](https://github.com/DougGregor/swift-evolution/blob/property-wrappers/proposals/0258-property-wrappers.md)

主に以下の内容に変更されました。

- 名前は"property delegates"から"property wrappers"に変更された(やっぱりdelegateは紛らわしかった)
- property wrapper型にパラメータがないinitがある場合、それを使用するプロパティは暗黙的にそのinitで初期化される
- property wrapper型をネストできる
  - `@A @B var x: Int = 42`があった場合、`var $x: A<B<Int>> = A(initialValue: B(initialValue: 42))`で初期化される
- property wrapper型を使用するプロパティはgetとsetを持てない
  - 既存のlazyと一緒の制約
- property wrapper を持つプロパティはfinalである必要はない
- ストレージ($fooでアクセスできるやつ)はデフォルトでprivate
  - 外からも見えるようにしたい場合は`public(wrapper)`のようにする

また、property wrapperは現在も活発に議論されています。

(6/4 時点で3スレッド目)
[[Pitch #3] Property wrappers (formerly known as Property Delegates) - Pitches - Swift Forums](https://forums.swift.org/t/pitch-3-property-wrappers-formerly-known-as-property-delegates/24961)

また、冒頭で書いたようにSwiftUIに

```swift
struct Content: View {
  @State var model = ...

  var body: some View { 
    ... 
  }
}
```

というコードがありましたが、この中に出てくる`@State`はproperty wrappersを使用している[みたいです](https://forums.swift.org/t/what-is-this-thing-from-wwdc/25160/6)。

ちなみに私は読み過ごしていたのですが、

>  the Core Team had already decided and publicly stated that the feature was going to be eventually accepted into Swift. 

(from: https://forums.swift.org/t/important-evolution-discussion-of-the-new-dsl-feature-behind-swiftui/25168/49)

らしく、ステータスとしてはReturned for revisionというよりはAccepted with Revisionな感じなんですかね・・・？(ここいらへんの英語の語感がわからない)

また、この機能は単にプロパティを拡張できるだけでなく、ユーザー定義の属性が(プロパティに対してのみにですが)使えるようになるということです。

これはSwiftにとって大きな変更ですが、依然としてプロパティに対してのみです。
もともとユーザー定義の属性を作りたいという議論はあり、Core Teamもビルド時のコード解析で使用され、バイナリには出力されない`@staticAttribute`、バイナリに含まれ、リフレクションを用いて実行時に取得できる`@runtimeAttribute`、そして`@propertyWrapper`でカスタム属性をサポートしようという[議論](https://forums.swift.org/t/pitch-introduce-custom-attributes/21335/47)があります。

property wrappersはまだまだ魅力的な使い方や制限などがありますが、まだ議論中であり、大きな機能なので別の機会に詳細を書きたいと思います。

## おまけ
### Function Builders

冒頭で出てきたSwiftUIのサンプルコードに以下のようなものがあります。

```swift
VStack(alignment: .leading) {
    Text(item.title)
    Text(item.subtitle)
        .color(.gray)
}
```

一見するとクロージャの中でただ`Text`をinitしているだけのように見えますが、実際には縦方向に並んだテキストが表示されます。

この機能(?)は謎だったんですが、WWDCの基調講演から数時間後にSwift Forumsに以下のスレッドが突如として生えました。

[IMPORTANT: Evolution discussion of the new DSL feature behind SwiftUI - Pitches - Swift Forums](https://forums.swift.org/t/important-evolution-discussion-of-the-new-dsl-feature-behind-swiftui/25168)

あまりに突然すぎて若干物議を醸していますが、要するにSwiftでDSLのような書き方をサポートするみたいです。

実際の議論は以下で行われています。

[[Pitch] Function builders - Pitches - Swift Forums](https://forums.swift.org/t/pitch-function-builders/25167)

DraftのProposalも以下にあります。

[swift-evolution/XXXX-function-builders.md at 9992cf3c11c2d5e0ea20bee98657d93902d5b174 · apple/swift-evolution · GitHub](https://github.com/apple/swift-evolution/blob/9992cf3c11c2d5e0ea20bee98657d93902d5b174/proposals/XXXX-function-builders.md)

簡単な例を出すと以下のようになります。

```swift
// 以下のソースコードを書くと
@TupleBuilder
func build() -> (Int, Int, Int) {
  1
  2
  3
}

// 以下のように書いたのと同じようになる
func build() -> (Int, Int, Int) {
  let _a = 1
  let _b = 2
  let _c = 3
  return TupleBuilder.buildBlock(_a, _b, _c)
}
```

実際の使い方など書いていきたいのですが、ifやforなどの扱い方や制限など、内容が大きく、またまだ議論段階なので詳しい説明はあとで別に書くなりしたいと思います(と言ってる間に誰かが詳しい説明を書いてくれることを期待...)

---

まだまだ他にも興味深いProposalはあるのですが、とりあえずこのへんで。
Proposalsを見てるだけでも今すぐ使いたい！と思うような機能がたくさんありました。
今後ますます便利になっていくといいなと思います！