Swiftに今後追加される言語仕様について調べてみた

[mixiグループアドベントカレンダー](http://qiita.com/advent-calendar/2015/mixi)25日目です！

#はじめに
モバイルグループの田代です！
最近新規画面はSwiftで書いてます！
そのおりにSwift3.0の話がチーム内ででたので、そのあたりを調べてみました！

# 概要
Swiftがgithubで公開されAppleだけでなく開発者もSwiftの言語仕様にコミットできるようになりました
それが[Swift-Evolution](https://github.com/apple/swift-evolution)です！
現在(2015/12/24)でも提案された8つの新仕様がAcceptedとなりSwift2.2やSwift3.0で導入する予定となっています
今回はどういった仕様が追加されていくのか見ていきたいと思います


# Proposal
## Proposalとは
新仕様の提案書です
上記リポジトリに``` 0000-template.md ```というフォーマットが用意されており、それを元に提案したい仕様をまとめてコミットしレビューしてもらい、導入するか否かを決めてもらいます

# Proposals
## SE-0001: [Allow (most) keywords as argument labels](https://github.com/apple/swift-evolution/blob/master/proposals/0001-keywords-as-argument-labels.md) (Accepted)
### 概要
```inout,var,let``` を除いた単語を引数ラベルとして設定できるようにする

```swift:Xcode7.2
func hoge(in:String) {   /// Error:Expected ',' separator
}
```

たとえば上記のように ``` in ``` を仮引数のラベルに設定するとXcode7.2ではエラーになります
ただこれはバグらしく、修正コミットがこちらにあります
https://github.com/apple/swift/commit/c8dd8d066132683aa32c2a5740b291d057937367
こうやって変更点をコードで確認できるのはうれしいですね

## SE-0002: [Removing currying ```func``` declaration syntax](https://github.com/apple/swift-evolution/blob/master/proposals/0002-remove-currying.md) (Accepted)
### 概要
Swiftにはカリー化のための専用の宣言方法がある(初めて知った！)のですが、わかりづらいから削除しようとのことらしいです

```swift:Xcode7.2
// Before:
func curried(x: Int)(y: String) -> Float {
  return Float(x) + Float(y)!
}

// After:
func curried(x: Int) -> (String) -> Float {
  return {(y: String) -> Float in
    return Float(x) + Float(y)!
  }
}
```
上記のProposalの例はどちらもXcode7.2では動きますが今後はBeforeはなくなるようです

## SE-0003: [Removing var from Function Parameters and Pattern Matching](https://github.com/apple/swift-evolution/blob/master/proposals/0003-remove-var-parameters-patterns.md) (Accepted)
### 概要
関数パラメーターとパターンマッチングから```var```を削除するとのことですが、よくわからないので例文を見ていきます
例示は理解の試金石ですね

```swift:Xcode7.2
func foo(i: Int) {
  i += 1 // illegal
}

func foo(var i: Int) {
  i += 1 // OK
}
```
上記の例文では```i```がimmutableになっているのに再代入しようとしてエラーになってしまいます
Proposalでは他にも```if,while,guard,switch,for```などの例があり、どれも変数をimmutableに宣言することによってその後に変数を変更しようとするとエラーになってしまうことが列挙されています

パターンマッチングの例も書いてあったのですが、なにがパターンマッチングなのか判然としなかったので詳しい人がいたら教えてほしいですm(_ _)m

上記solutionとして提示されているのは

* All function parameters are either unannotated constants or are marked with inout.
* Only ```if let``` is allowed, not ```if var```.
* Only ```guard let``` is allowed, not ```guard var```.
* Only ```while let``` is allowed, not ```while var```.
* Only ```case .Some(let x)``` is allowed, not case ```.Some(var x)```.
* Only ```for x``` in is allowed, not for ```var x in```.

となっており、基本的にimmutableとして扱い、mutableにしたい場合は

```swift
if let x = getOptionalInt() {
  var x = x
  x += 1
  return x
}
```
と一度置き換えるようです

## SE-0004: [Remove the ++ and -- operators](https://github.com/apple/swift-evolution/blob/master/proposals/0004-remove-pre-post-inc-decrement.md) (Accepted)

### 概要
簡単にいえば```++```や```--```のオペレーターを廃止しようということです
理由としては```x++```や```++x```で値の返り値が違うけどあんまり気にしてないよね？ということらしいです

```swift
var i=0
i += 1 /// 1
```
ではどうやってincrementやdecrementを表現するのかといえば上記のようにするようです
ただ代替案も提示されていて```x++```と```++x```はどちらも同じ結果が変えるようにするということですが、
最終的にどうなるかは気になるところです
ちなみにPythonには```++```や```--```のオペレーターはないそうです

## SE-0005: [Better Translation of Objective-C APIs Into Swift](https://github.com/apple/swift-evolution/blob/master/proposals/0005-objective-c-name-translation.md) (Accepted)

### 概要
Swift内でのObjective-CのAPIをよりよく置き換えるとのことですが、これは例を見たほうがわかりやすいと思うのでPoposalの例を見てみます

```swift:swift2.0
class UIBezierPath : NSObject, NSCopying, NSCoding {
  convenience init(ovalInRect: CGRect)
  func moveToPoint(_: CGPoint)
  func addLineToPoint(_: CGPoint)
  func addCurveToPoint(_: CGPoint, controlPoint1: CGPoint, controlPoint2: CGPoint)
  func addQuadCurveToPoint(_: CGPoint, controlPoint: CGPoint)
  func appendPath(_: UIBezierPath)
  func bezierPathByReversingPath() -> UIBezierPath
  func applyTransform(_: CGAffineTransform)
  var empty: Bool { get }
  func containsPoint(_: CGPoint) -> Bool
  func fillWithBlendMode(_: CGBlendMode, alpha: CGFloat)
  func strokeWithBlendMode(_: CGBlendMode, alpha: CGFloat)
  func copyWithZone(_: NSZone) -> AnyObject
  func encodeWithCoder(_: NSCoder)
}
```

```swift:swift3.0
class UIBezierPath : Object, Copying, Coding {
  convenience init(ovalIn: CGRect)
  func moveTo(_: CGPoint)
  func addLineTo(_: CGPoint)
  func addCurveTo(_: CGPoint, controlPoint1: CGPoint, controlPoint2: CGPoint)
  func addQuadCurveTo(_: CGPoint, controlPoint: CGPoint)
  func append(_: UIBezierPath)
  func reversing() -> UIBezierPath
  func apply(_: CGAffineTransform)
  var isEmpty: Bool { get }
  func contains(_: CGPoint) -> Bool
  func fillWith(_: CGBlendMode, alpha: CGFloat)
  func strokeWith(_: CGBlendMode, alpha: CGFloat)
  func copy(zone _: Zone = nil) -> AnyObject
  func encodeWith(_: Coder)
}
```

要点としては
#### **```swift_name```属性の適用を一般化する**
```swift_name``` の存在をいま知ったわけですが、Objective-CにSwiftのための名前を定義できる仕組みのようです

```swift
// @see https://github.com/apple/swift/blob/master/test/ClangModules/attr-swift_name.swift

// CHECK: warning: too few parameters in swift_name attribute (expected 2; got 1)
// CHECK: + (instancetype)testW:(id)x out:(id *)outObject SWIFT_NAME(ww(_:));
```
いまはenumやファクトリーメソッドのリネームにしか許可されてないけどCやObjective-Cの実体（entity）？の任意のリネームもできるようにしようということらしいです

#### **冗長な型名の切り落とし**
[SwiftAPIのガイドライン](https://swift.org/documentation/api-design-guidelines.html#omit-needless-words)に合わせて、不要な単語を省略しよう

```swift
public mutating func removeElement(member: Element) -> Element? /// bad

public mutating func remove(member: Element) -> Element? /// good
```

#### **デフォルト引数を追加する**
SwiftにAPIをインポートするとき、デフォルト引数に必要なヒントあれば推論してくれるようにする

#### **一番初めの引数にラベルを追加する**
メソッドの最初のパラメーターがデフォルト値が設定されていたら、そのメソッドのためにラベルを設定しようとのことです
https://swift.org/documentation/api-design-guidelines.html#first-argument-label

#### **ブーリアン型のプロパティには```is```を前につける**
Objective-Cのガイドラインでは```is```を接頭語としてつけるのは禁じられていましたが、Swiftのガイドラインに合わせようということらしいです

#### **FoundationAPIsの```NS```プレフィックスは除去する**
クロスプラットフォームAPIにプレフィックスは時代錯誤っぽいのでやめようって話みたいです

詳細はProposalに書いてあるのでそちらを見てほしいのですが、
これは最終的には開発者にも影響あるのですが、まずはApple内でのObjective-Cの規約のような感じもします

## SE-0006: [Apply API Guidelines to the Standard Library](https://github.com/apple/swift-evolution/blob/master/proposals/0006-apply-api-guidelines-to-the-standard-library.md) (Awaiting Review)

### 概要
これはSwift3.0向けのガイドラインをまとめようぜという話らしく、ひとまずアプリ開発者には関係なさそうです

## SE-0007: [Remove C-style for-loops with conditions and incrementers](https://github.com/apple/swift-evolution/blob/master/proposals/0007-remove-c-style-for-loops.md) (Accepted for Swift 3.0)

### 概要
Cライクな```for-loop```を削除しようとのことです
理由としては```for-in```と```stride```がSwiftらしい同じような価値を提供してくれるし、```for-in```のほうが```for-loops```に比べて文字数が少ないし、SE-0004でもあったけど```++```などのoperator削除されるから、などの理由が挙げられてました

```swift
for (var i=0; i<10; i++) {
  //-- anything
}
```
ちなみにC-style for-loopは上記みたいな構文です

## SE-0008: [Add a Lazy flatMap for Sequences of Optionals](https://github.com/apple/swift-evolution/blob/master/proposals/0008-lazy-flatmap-for-optionals.md) (Accepted for Swift 2.2)

### 概要
現在flatmapには二種類あって（詳しくは[koherさんの記事](http://qiita.com/koher/items/6a95cb8edb04fb81f787)をどうぞ）Optionalをとるものとそうでないものがあります
それがそれぞれで```.lazy```したときの挙動が違うので治そうということみたいです

```swift:Xcode7.2
[1, 2, 3]
  .lazy
  .flatMap { n in n..<5 }
// LazyCollection<FlattenBidirectionalCollection<LazyMapCollection<Array<Int>, Range<Int>>>>

(1...10)
  .lazy
  .flatMap { n in n % 2 == 0 ? n/2 : nil }
// [1, 2, 3, 4, 5]
```

# 終わりに
ざっとReview済みのProposalを見てきましたが、既存のObjective-C周りにも言及されていて、SwiftのNSRangeまわりではまった自分としてはそのあたりも使いやすくなってくれるとうれしいです