mixiグループアドベントカレンダー25日目です!
#はじめに
モバイルグループの田代です!
最近新規画面はSwiftで書いてます!
そのおりにSwift3.0の話がチーム内ででたので、そのあたりを調べてみました!
概要
Swiftがgithubで公開されAppleだけでなく開発者もSwiftの言語仕様にコミットできるようになりました
それが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 (Accepted)
概要
inout,var,let
を除いた単語を引数ラベルとして設定できるようにする
func hoge(in:String) { /// Error:Expected ',' separator
}
たとえば上記のように in
を仮引数のラベルに設定するとXcode7.2ではエラーになります
ただこれはバグらしく、修正コミットがこちらにあります
https://github.com/apple/swift/commit/c8dd8d066132683aa32c2a5740b291d057937367
こうやって変更点をコードで確認できるのはうれしいですね
SE-0002: Removing currying func
declaration syntax (Accepted)
概要
Swiftにはカリー化のための専用の宣言方法がある(初めて知った!)のですが、わかりづらいから削除しようとのことらしいです
// 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 (Accepted)
概要
関数パラメーターとパターンマッチングからvar
を削除するとのことですが、よくわからないので例文を見ていきます
例示は理解の試金石ですね
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, notif var
. - Only
guard let
is allowed, notguard var
. - Only
while let
is allowed, notwhile var
. - Only
case .Some(let x)
is allowed, not case.Some(var x)
. - Only
for x
in is allowed, not forvar x in
.
となっており、基本的にimmutableとして扱い、mutableにしたい場合は
if let x = getOptionalInt() {
var x = x
x += 1
return x
}
と一度置き換えるようです
SE-0004: Remove the ++ and -- operators (Accepted)
概要
簡単にいえば++
や--
のオペレーターを廃止しようということです
理由としてはx++
や++x
で値の返り値が違うけどあんまり気にしてないよね?ということらしいです
var i=0
i += 1 /// 1
ではどうやってincrementやdecrementを表現するのかといえば上記のようにするようです
ただ代替案も提示されていてx++
と++x
はどちらも同じ結果が変えるようにするということですが、
最終的にどうなるかは気になるところです
ちなみにPythonには++
や--
のオペレーターはないそうです
SE-0005: Better Translation of Objective-C APIs Into Swift (Accepted)
概要
Swift内でのObjective-CのAPIをよりよく置き換えるとのことですが、これは例を見たほうがわかりやすいと思うのでPoposalの例を見てみます
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)
}
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のための名前を定義できる仕組みのようです
// @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のガイドラインに合わせて、不要な単語を省略しよう
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 (Awaiting Review)
概要
これはSwift3.0向けのガイドラインをまとめようぜという話らしく、ひとまずアプリ開発者には関係なさそうです
SE-0007: Remove C-style for-loops with conditions and incrementers (Accepted for Swift 3.0)
概要
Cライクなfor-loop
を削除しようとのことです
理由としてはfor-in
とstride
がSwiftらしい同じような価値を提供してくれるし、for-in
のほうがfor-loops
に比べて文字数が少ないし、SE-0004でもあったけど++
などのoperator削除されるから、などの理由が挙げられてました
for (var i=0; i<10; i++) {
//-- anything
}
ちなみにC-style for-loopは上記みたいな構文です
SE-0008: Add a Lazy flatMap for Sequences of Optionals (Accepted for Swift 2.2)
概要
現在flatmapには二種類あって(詳しくはkoherさんの記事をどうぞ)Optionalをとるものとそうでないものがあります
それがそれぞれで.lazy
したときの挙動が違うので治そうということみたいです
[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まわりではまった自分としてはそのあたりも使いやすくなってくれるとうれしいです