Swift ファーストインプレッション
とりあえずThe Swift Programming Language読んで、実際に自分で少し書いてみた感想。
諸事情でAppleにiOSデベロッパーとしてお布施していたので Xcode6beta落として少し書いてみた。プロジェクトスケルトンをswiftで生成できるので、そのコードを眺めたりしていた。
ファーストインプレッション
Immutable脳の人が設計したっぽい。 スクリプト言語っぽい構文に、型注釈。これはGoとシンタックス上の設計思想が似ているんだと思う。
基本的にImmutableな設計でありながら、オブジェクト指向を採用しており、Scalaっぽいマルチパラダイム感がある。Scalaの人は好きになりそう。
型推論のおかげで動的型付け言語触ってきた人にも抵抗がない感じになってる。推論のおかげで静的型付け言語が動的型っぽくみえるのはHaskellとかOCaml方面の雰囲気。
LLVMはレジスタの値が不変だと最適化しやすいので、それにあわせてる気がする。どうせ中はLLVMだろう。
気になった機能
let が immutableで var が mutable
let implicitInteger = 70 let implicitDouble = 70.0 let explicitDouble: Double = 70
let式は成功/失敗の値を返す
if let actualNumber = possibleNumber.toInt() { println("\(possibleNumber) has an integer value of \(actualNumber)") } else { println("\(possibleNumber) could not be converted to an integer") }
Dictionary式。JSONっぽいけど違う。
var occupations = [ "Malcolm": "Captain", "Kaylee": "Mechanic", ] occupations["Jayne"] = "Public Relations"
StructualSubtypingできるのかなぁ。
生のアドレス触る手段もある。
func swapTwoInts(inout a: Int, inout b: Int) { let temporaryA = a a = b b = temporaryA } var someInt = 3 var anotherInt = 107 swapTwoInts(&someInt, &anotherInt)”
関数表記はML風っぽい。引数名が必須という点ではTypeScriptとかあの辺にも似てる。
var mathFunction: (Int, Int) -> Int = addTwoInts func greet(name: String, day: String) -> String { return "Hello \(name), today is \(day)." } greet("Bob", "Tuesday")
調べた感じ暗黙のreturnはない
func makeIncrementer() -> (Int -> Int) { ... }
Goといい、関数をfuncと表記するのが流行りなのかな。javascriptにおけるfunctionの面倒臭さの反省のような気もする。
タプルでリターン。
func getGasPrices() -> (Double, Double, Double) { return (3.59, 3.69, 3.79) }
switch式でのパターンマッチ
let somePoint = (1, 1) switch somePoint { case (0, 0): println("(0, 0) is at the origin") case (_, 0): println("(\(somePoint.0), 0) is on the x-axis") case (0, _): println("(0, \(somePoint.1)) is on the y-axis") case (-2...2, -2...2): println("(\(somePoint.0), \(somePoint.1)) is inside the box") default: println("(\(somePoint.0), \(somePoint.1)) is outside of the box") }
とか
let yetAnotherPoint = (1, -1) switch yetAnotherPoint { case let (x, y) where x == y: println("(\(x), \(y)) is on the line x == y") case let (x, y) where x == -y: println("(\(x), \(y)) is on the line x == -y") case let (x, y): println("(\(x), \(y)) is just some arbitrary point") }
クラス宣言にはC#っぽさも感じる
class GameScene: SKScene { override func didMoveToView(view: SKView) {
このコードでエラーが出た。
class Point { var x : Int var y : Int init(){ self.x = 0 //self.y = 0 } }
initで必ずyも初期化しろとのこと。null安全志向。 newはないので Point() みたいに用いる。Pythonと似ている。クラス専用キーワードのせいでメタプロし辛いのがこれで解決するかもしれない。
デストラクタとして deinit
もある。
初期化
class Player { var tracker = LevelTracker() let playerName: String func completedLevel(level: Int) { LevelTracker.unlockLevel(level + 1) tracker.advanceToLevel(level + 1) } init(name: String) { playerName = name } } player = Player(name: "Beto")
オブジェクトリテラルっぽい引数渡し
メンバ修飾。これはC#と同じ。。
var simpleDescription: String { get }
protocol 宣言 で実装付インターフェースが作れる。要はtrait
protocol P { var z : Int {get; set} mutating func adjust() { z += 10 } }
副作用を起こすときはmutatingキーワードが必要。このケースでは要らんかった
enumが賢い。HaxeのEnum思い出した。 パターンマッチができて、メソッドも生やせる。
enum ServerResponse { case Result(String, String) case Error(String) } let success = ServerResponse.Result("6:00 am", "8:09 pm") let failure = ServerResponse.Error("Out of cheese.") switch success { case let .Result(sunrise, sunset): let serverResponse = "Sunrise is at \(sunrise) and sunset is at \(sunset)." case let .Error(error): let serverResponse = "Failure... \(error)" }
Optional Chaining
if let johnsStreet = john.residence?.address?.street { println("John's street name is \(johnsStreet).") } else { println("Unable to retrieve the address.") }
CoffeeScriptにあるやつだ。相手がnullableな場合、アクセス不可な場合チェインが途切れてfailする。くっそ便利。
TypeAlias
typealias Point = (Int, Int) let origin: Point = (0, 0)
ほう
あとで調べる
!.
アクセッサーunowned
修飾@lazy
修飾。C#のasync相当にみえる。じゃあawait相当のものもある?extension
traitっぽい。protocolをmixinするもの?subscript
値の監視や言語組み込みのオブザーバー?面白そうな気配がする。
最高な点
- 驚き最小
- まともに動く!!!!
全体的によく練られた良い設計だと思う。
残念な点
- ネームスペースがない。SpriteキットがSKNodeみたいな感じで使わざるをえない。
- Appleロックイン。ポテンシャルが高い言語なのでアップルエコシステム以外にも貢献できるはず
こんな感じです。スクリプト言語みたいに軽く扱えるようになってほしい。そんでライブラリマネージャ出てほしい。それなりにコード書いたらまた印象変わると思う。
まぁ思いますよね / “jchannon/SwiftJS · GitHub” http://t.co/l0WRfeII6C
— 五月病(旧暦) (@KOBA789) 2014, 6月 2
LLVMがSwiftを高速なネイティブコードに変換してくれる、という理解なんだけど、そのネイティブコードはiOSのバージョン関わらず動作するんだろうか。さっき手元の7.1.1ではSwiftのコードが動いた。
— ruboty (@naoty_k) 2014, 6月 3
iOS 8がリリースされるまではSwiftを使ったアプリは申請できないと書いてある。
— ruboty (@naoty_k) 2014, 6月 3
!., optional を explicit に剥がすのが ! じゃなかったっけ
— utatane (@Constellation) 2014, 6月 3
lazy 修飾は, lazy prop みたいなので, 初期化遅延できるみたいなのだったはず. scala にもなかったっけ.
— utatane (@Constellation) 2014, 6月 3
@mizchi let 式は成功/失敗を返すんじゃなくて if let foo = optionalFoo { ... } が特別扱いされてて、 optionalFoo が Some なら値を unwrap して束縛して if 文に入るとかやってる
— 女の子の柔らかい身体 (@uasi) 2014, 6月 3