willDisplayCell で cellHeights を更新して、 estimatedRowHeightAtIndexPath で読み出すからdelegateメソッドでしか使われてないよね、という話ではなく?class HogeObj { } が書いてあるファイルでのみHogeObjのextensionにstored propertyを持たせられるようになったらな〜という話。これだったらUIKitのクラスに対してextensionでstored property足せない
// MARK: -- で分けるのはどうかと思ったけど、 protocol conformanceが一番上に集まっちゃうから微妙かな (edited)interface Base { fun print() } class Derived(b: Base) : Base by bb は Base 型のフィールドで、 Derived が Base に conformさせるのを by b で指定してる。class の右にしか書けないけど、 Swiftなら conformanceがそもそもextensionに書けるわけだからextension UserStatusViewController : UIScrollViewDelegate by scrollViewDelegateMixIn {}scrollViewDelegateMixIn は UserStatusViewController の storedProperty名で struct ScrollViewDelegateMixIn : UIScrollViewDelegate という型がついてる想定。 (edited)class { } の中に書かないといけないならkotlinみたいに上のところでもいいのかなextension ViewController { class ScrollViewDelegate: UIScrollViewDelegate { //ここに実装 } } だけどこれでも、ViewController.ScrollViewDelegateの宣言は本体側にないといけないよね、そこは解決しないのでは。まあすっきりはするか。var scrollViewDelegate: ScrollViewDelegateをどこに書くの?と言う問題は残っているtableView.delegate = self の右辺が self じゃなくてもいいじゃんって事かclass ScrollViewDelegate: NSObject, UIScrollViewDelegate { weak var parent: ViewController? } とかでまあおおよそ問題はないはず.delegate = なケースだけで (edited)let a = 3let a = 3class C { p: number; // Should be an error under --strictNullChecks method() { this.p; } }--strictNullChecks は このようなコンストラクタでのフィールドの初期化忘れに対して何も検査しないため 簡単に undefined を踏むのだ (edited)private struct Hoge {} fileprivate struct Hoge {} これが一番モニョいclass Cat { var a: String { didSet { // 呼ばれない print("nyaa") } } init() { self.a = "a" } } Cat()
@here 知ってた?T? へのキャストはされない事がわかった。 T と T? 両方行けるときは T? になることがわかった。T? になることから、 T では駄目になる事を検証しているという仮説は成り立たなかった。 T と T? の倍々で増えていくという仮説についても、 4倍で増えていくことから成り立たなかった。T? への暗黙キャストはしない。.hoge() ってドット構文になった時点で Int しか試されない。func commonIntFunc(_ x: Int?) -> Int {...} func commonIntFunc(_ x: Int!) -> Int {...} この2つは共存出来ないのか機種名: MacBook 機種ID: MacBook8,1 プロセッサ名: Intel Core M プロセッサ速度: 1.3 GHz プロセッサの個数: 1 コアの総数: 2 二次キャッシュ(コア単位): 256 KB 三次キャッシュ: 4 MB メモリ: 8 GB機種名: iMac 機種 ID: iMac17,1 プロセッサ名: Intel Core i7 プロセッサ速度: 4 GHz プロセッサの個数: 1 コアの総数: 4 二次キャッシュ(コア単位): 256 KB 三次キャッシュ: 8 MB メモリ: 32 GBtime コマンドの real を張ってる。1回しかやってないし他の作業も止めてないからだいぶガバガバだけど。 (edited)~ (๑˃̵ᴗ˂̵)ﻭ < time swiftc compile.swift -o compile swiftc compile.swift -o compile 15.78s user 0.30s system 99% cpu 16.137 totalthis が使えないためサブクラスのフィールドを埋める前に親クラスのコンストラクタが呼ばれる 厳しさ2. サブクラスのコンストラクタ内部で呼ばれた親クラスのコンストラクタにおいてメソッドを呼び出すと、それがサブクラスでオーバーライドされている場合、サブクラスの実装が呼ばれる これらの組み合わせによって、フィールドが未初期化のサブクラスのメソッドが呼ばれて、 undefined を踏む。 下記はその問題によって、純粋なJSユーザーが困っている事例2件 http://stackoverflow.com/questions/32615034/call-parent-function-which-is-being-overridden-by-child-during-constructor-chain
http://stackoverflow.com/questions/32449880/parent-constructor-call-overriden-functions-before-all-child-constructors-are-fiprivate と、構文スコープになった scoped に再び分裂する、みたいな流れになったら草private ですよねえ。/** * Calls the specified function [block] with `this` value as its argument and returns its result. */ @kotlin.internal.InlineOnly public inline fun <T, R> T.let(block: (T) -> R): R = block(this)=> 演算子でSwiftに導入すると、次のような事ができる// こんな関数があったとして func hogehogeFunc(str: String, int: Int) -> String { return "" } // こんなStructがあったとして struct Cat { var name: String var age: Int } // こんな関数が合ったとして func createPrettyCat() -> Cat { return Cat(name: "mike", age: 2) } // 従来は・・・ func demo1() { let cat = createPrettyCat() let result = hogehogeFunc(str: cat.name, int: cat.age) print(result) } // こういうのがシュッと1行にできなくて萎える // 提案のもとでは・・・ func demo2() { print(createPrettyCat() => { hogehogeFunc(str: $0.name, int: $0.age) }) } // 左から右にシュ〜っとかける=> の方がいい?->> より ダブルアローのほうが 打ちやすくていい => 式の評価結果はクロージャの結果そのものだから、hoge => { $0.piyo } => { $0.fuga }Any に extension でメソッド生やせないから諦めてた。let メソッドと同じ順序で書ける。class Cat attr_accessor :name, :age def initialize @name = "mike" @age = 3 end end p Cat.new.tap {|x| x.age } # => #<Cat:0x007f1790eb9b60 @name="mike", @age=3> Rubyのtapは確かに違った。。 (edited)dependencies: [ .Package(url: "https://github.com/koher/swiflet.git", majorVersion: 0) ] (edited)tap: method for Objective-C borrowed from Ruby.func fastUnwrap<T>(_ arg: T!) -> T? { return arg } (edited)return arg として出現していますがclass Outer<T> { static var staticVar: T class Inner { static var staticVar: T } }Outer<Int>.staticVar = 3 Outer<String>.staticVar = "abc" Outer<Int>.Inner.staticVar = 4 Outer<String>.Inner.staticVar = "xyz"error: static stored properties not supported in generic types static var staticVar: TCatInt, CatString は static contextが2つあるけど、 Cat<Int>, Cat<String> は1つしか無いんだなlet a = 42 a.map { $0 } // error
(edited)Any? に map を生やしてみたら、 List の map が正しく動かなくなって大変なことに。T? への暗黙の型変換は起こる場合と起こらない場合が使い分けられていることに気付きました。. の左側では暗黙の型変換をしないだけかもですが。.の左って暗黙変換すると非決定性が高すぎて実現不可能な気がするんですがpublic class Main { public static void main(String[] args) { System.out.println(2.compareTo(3)); } }
$ javac Main.java Main.java:3: error: ')' expected System.out.println(2.compareTo(3)); ^ Main.java:3: error: not a statement System.out.println(2.compareTo(3)); ^ Main.java:3: error: ';' expected System.out.println(2.compareTo(3)); ^ 3 errorsa を int に変えたらダメ。 public class Main { public static void main(String[] args) { Integer a = 2; System.out.println(a.compareTo(3)); } }let みたいな Any 由来のメソッドは使えるけど、それは暗黙の型変換なく使えるんで。foo?.let { x -> bar(x) }map かつ flatMap になります。?.let { } はアツいよねmap を生やしてみたら、という話なので、実用上は問題ないです。Promiseの.thenみを感じるAnything : Null = Kotlin : Any? : Nothing? の話を整理して Qiita に書きたい。 (edited)typealias Anything = Any? typealias Null = Nothing? とすれば Ceylon と同じになる。typealias Object = Any これもいるか。Never が bottom type になるかもという話も興味深い。IMO, if we accept a single error type per function, there could be a simpler model for this. We could say that the `throws` type is a generic parameter of all function types, and it defaults to the uninhabited `Never` type for functions that don't throw. () -> () == () throws Never -> () () throws -> () == () throws Error -> () In this model, you'd get many benefits: - `rethrows` could become first-class, reducing down to just polymorphic `throws`: func foo(_: () throws -> ()) rethrows // Swift 3 func foo<T: Error>(_: () throws T -> ()) throws T // Swift XNever が bottom type でないと辻褄が合わない。rethorws がただのシュガーになっちゃって、 reasync との対応の解釈が難しいです・・・。 https://gist.github.com/koher/df007741788cb197d65b6babe2acf480actor も Swift 5+ って書かれてるし、 4 ではない気がしてます。 http://researcher.watson.ibm.com/researcher/files/us-lmandel/lattner.pdf public class func Package(url: String, versions: ClosedRange<Version>) -> Dependency { return Package(url: url, versions: versions.lowerBound..<versions.upperBound.successor()) }a...b と a..<b の両方に対応しようとすると、 a...b => a ..< b.successor() の変換をオーバーロードの内側でやらないといかんのか。protocol Sequence { associatedtype Iterator : IteratorProtocol ... associatedtype SubSequence : Sequence // currently ill-formed, but should be possible } シーケンスのサブシーケンスはシーケンス、としたいけど現状はできない、とかがあるらしいprotocol Eq { static func (a: Self, b: Self) -> Bool } ↑これはできるけど protocol EqX { associatedtype X static func (a: X, b: X) -> Bool } struct Hoge : EqX { typealias X = Hoge } これはできない? (edited)protocol EqX { associatedtype X static func (a: X, b: X) -> Bool } protocol EqSelf { typealias X = Self } struct Hoge : EqSelf { } これが駄目なのかな?protocol EqX { associatedtype X static func (a: X, b: X) -> Bool } struct Hoge : EqX { typealias X = Self } HogeじゃなくてSelfか (edited)protocol A { associatedtype B } class C: A { typealias B=Self } ↑できないself 式の型が Self だし。protocol HasB { associatedtype B } protocol A: HasB { } class AnyAs: HasB { typealias B = AnyAs.Type } class AnyA<T>: AnyAs where T: A { typealias B = T.B } class C: A { typealias B = C } AnyA<C>.B.selfclass D: C {}と書いたらどうなりますか?xs.map {|x| y = f(x) y ? [y] : [] }.flatten(1)let error: MyCustomError = MyCustomError() にしたらどうなるの?. の左の暗黙の型変換ですかw
swift package pin --enable-autopin), although package project owners can choose to disable this if they wish to have more fine grained control over their pinning behavior.$ cd a $ swift build $ .build/debug/alet a = F<O>() print(a.f())import GlibC したとき何が使えるのかさっぱりわからん (edited) var fileActions: posix_spawn_file_actions_t? try PosixError.run { posix_spawn_file_actions_init(&fileActions) } defer { try PosixError.run { posix_spawn_file_actions_destroy(&fileActions) } }foo() defer { bar() } return baz() は foo() let r = baz() bar() return r と等価だと思ってた。foo() return baz() bar() こう考えると、throwできないわけだdefer で try できないのは↓書いてるときに遭遇して、できてもいいのになぁと思った。 http://qiita.com/koher/items/e4c1d88981291c35d571swift func foo() throws -> String { ... } // Java のような `throws` 節 ```swift...close できないことがありえないならそもそも throws である必要ないんじゃ?
public static func run(proc: () -> Int32) throws { let code = proc() guard code == 0 else { throw PosixError(code: code) } } こういうユーティリティだから try! PosixError.run { posix_spawn_file_actions_destroy(&fileActions) } try! になるlet ret = posix_spawn_file_actions_destroy(&fileActions) fatalError(ret == 0, PsoxiError(code: ret).description) (edited)ret がスコープ汚染しちゃって、同じような処理を他にも書く必要があるから、これは採用できない。>= は rethorws にしないといけない気がしてきた。fatalError(ret == 0, PsoxiError(code: ret).description) 0判定、PosixErrorで包む、descriptionを呼び出す、などが冗長 try! PosixError.run { posix_spawn_file_actions_destroy(&fileActions) } これならそのいずれもなくなっていて、同じことをする上で無駄が無い>=はrethrowsじゃないとダメですねextension NSString { open func components(separatedBy separator: String) -> [String] @available(iOS 2.0, *) open func components(separatedBy separator: CharacterSet) -> [String] }.の!!左側で!!!import Foundation extension NSString { func piyo() -> Int { return 33 } } let a: String = "abc" a.piyo()_SwiftBridgeable が気になる感// // util.swift // RuString // // Created by omochimetaru on 2017/03/31. // // internal func findSubArray<C: Collection, I>( array: C, index: I, target: C ) -> I? where I == C.Index { var i: C.Index = index while i < array.endIndex { if matchArray(array1: array, index1: i, array2: target, index2: target.startIndex, length: target.distance(from: target.startIndex, to: target.endIndex)) { return i } i = array.index(after: i) } return nil } internal func matchArray<C: Collection, I, D>( array1: C, index1: I, array2: C, index2: I, length: D) -> Bool where I == C.Index, D == C.IndexDistance, C.SubSequence.Iterator.Element : Equatable { if array1.index(index1, offsetBy: length) >= array1.endIndex { return false } if array2.index(index2, offsetBy: length) >= array2.endIndex { return false } let test1 = array1[index1..<array1.index(index1, offsetBy: length)] let test2 = array2[index2..<array2.index(index2, offsetBy: length)] for (x1, x2) in zip(test1, test2) { if x1 != x2 { return false } } return true }C.Index って書いてたんだけどinternal func findSubArray<C: Collection>( array: C, index: C.Index, target: C ) -> C.Index? { var i: C.Index = index while i < array.endIndex { if matchArray(array1: array, index1: i, array2: target, index2: target.startIndex, length: target.distance(from: target.startIndex, to: target.endIndex)) { return i } i = array.index(after: i) } return nil } internal func matchArray<C: Collection>( array1: C, index1: C.Index, array2: C, index2: C.Index, length: C.IndexDistance) -> Bool where C.SubSequence.Iterator.Element : Equatable { if array1.index(index1, offsetBy: length) >= array1.endIndex { return false } if array2.index(index2, offsetBy: length) >= array2.endIndex { return false } let test1 = array1[index1..<array1.index(index1, offsetBy: length)] let test2 = array2[index2..<array2.index(index2, offsetBy: length)] for (x1, x2) in zip(test1, test2) { if x1 != x2 { return false } } return true }where C.SubSequence.Iterator.Element : Equatable を付ける必要があった/// A type that explicitly supplies its own playground Quick Look. /// /// A Quick Look can be created for an instance of any type by using the /// `PlaygroundQuickLook(reflecting:)` initializer. If you are not satisfied /// with the representation supplied for your type by default, you can make it /// conform to the `CustomPlaygroundQuickLookable` protocol and provide a /// custom `PlaygroundQuickLook` instance. public protocol CustomPlaygroundQuickLookable { /// A custom playground Quick Look for this instance. /// /// If this type has value semantics, the `PlaygroundQuickLook` instance /// should be unaffected by subsequent mutations. public var customPlaygroundQuickLook: PlaygroundQuickLook { get } }/// A type that explicitly supplies its own mirror. /// /// You can create a mirror for any type using the `Mirror(reflect:)` /// initializer, but if you are not satisfied with the mirror supplied for /// your type by default, you can make it conform to `CustomReflectable` and /// return a custom `Mirror` instance. public protocol CustomReflectable { /// The custom mirror for this instance. /// /// If this type has value semantics, the mirror should be unaffected by /// subsequent mutations of the instance. public var customMirror: Mirror { get } } /// A type that explicitly supplies its own mirror, but whose /// descendant classes are not represented in the mirror unless they /// also override `customMirror`. public protocol CustomLeafReflectable : CustomReflectable { }public struct ObjectIdentifier : Hashable {== じゃなくて === ベースでDictionaryのキーにしたいときに[ObjectIdentifier: Hoge] こうすんのか/// Supply the default "slicing" `subscript` for `BidirectionalCollection` /// models that accept the default associated `SubSequence`, /// `BidirectionalSlice<Self>`. extension BidirectionalCollection where Self.SubSequence == BidirectionalSlice<Self>, Self.SubSequence.Index == Self.Index, Self.SubSequence.IndexDistance == Self.IndexDistance, Self.SubSequence.Indices == DefaultBidirectionalIndices<BidirectionalSlice<Self>>, Self.SubSequence.Iterator == IndexingIterator<BidirectionalSlice<Self>>, Self.SubSequence.SubSequence == BidirectionalSlice<Self>, Self.SubSequence._Element == Self._Element, Self.SubSequence.Indices.Index == Self.Index, Self.SubSequence.Indices.IndexDistance == Int, Self.SubSequence.Indices.Iterator == IndexingIterator<DefaultBidirectionalIndices<BidirectionalSlice<Self>>>, Self.SubSequence.Indices.SubSequence == DefaultBidirectionalIndices<BidirectionalSlice<Self>>, Self.SubSequence.Indices._Element == Self.Index, Self.SubSequence.Iterator.Element == Self._Element, Self.SubSequence.SubSequence.Index == Self.Index, Self.SubSequence.SubSequence.Iterator == IndexingIterator<BidirectionalSlice<Self>>, Self.SubSequence.SubSequence.SubSequence == BidirectionalSlice<Self>, Self.SubSequence.SubSequence._Element == Self._Element, Self.SubSequence.Indices.IndexDistance.IntegerLiteralType == Int, Self.SubSequence.Indices.IndexDistance.Stride == Int, Self.SubSequence.Indices.IndexDistance._DisabledRangeIndex == Int._DisabledRangeIndex, Self.SubSequence.Indices.Iterator.Element == Self.Index, Self.SubSequence.SubSequence.Iterator.Element == Self._Element, Self.SubSequence.Indices.IndexDistance.Stride.IntegerLiteralType == Int { public subscript(bounds: Range<Self.Index>) -> BidirectionalSlice<Self> { get } } 4> for (i, c) in "a\r\nb".characters.enumerated() { 5. print("[\(i)] \(c)") 6. } [0] a [1] [2] b CR + LFは書記素クラスタとして1つに結合するらしいlibswiftFoundation.dylib`(extension in Foundation):Swift.String.components (separatedBy : Swift.String) -> Swift.Array<Swift.String>: 0x1032ae46b <+43>: callq 0x103326aaa ; symbol stub for: Swift.String._bridgeToObjectiveCImpl () -> Swift.AnyObject 0x1032ae470 <+48>: movq %rax, %r15 0x1032ae473 <+51>: movq %rbx, %rdi 0x1032ae476 <+54>: callq 0x10332706e ; symbol stub for: swift_unknownRetain 0x1032ae47b <+59>: movq %r12, %rdi 0x1032ae47e <+62>: movq %r14, %rsi 0x1032ae481 <+65>: movq %rbx, -0x38(%rbp) 0x1032ae485 <+69>: movq %rbx, %rdx 0x1032ae488 <+72>: callq 0x103326aaa ; symbol stub for: Swift.String._bridgeToObjectiveCImpl () -> Swift.AnyObject 0x1032ae48d <+77>: movq %rax, %r12 0x1032ae490 <+80>: movq 0x97881(%rip), %rsi ; "componentsSeparatedByString:" 0x1032ae497 <+87>: movq %r15, %rdi 0x1032ae49a <+90>: movq %r12, %rdx 0x1032ae49d <+93>: callq 0x103326f00 ; symbol stub for: objc_msgSendswift_rt_swift_dynamicCastClassとかあったりしてStringからNSStringのキャストと、NSArrayからArray<String>を持ってるString.componentsが見えない、参照できないのはCollectionにおける不可視のIndexと似た何かな?と思った(self as NSString).components(separatedBy: separator)_nsが生えてるextension String { //===--- Bridging Helpers -----------------------------------------------===// //===--------------------------------------------------------------------===// /// The corresponding `NSString` - a convenience for bridging code. var _ns: NSString { return self as NSString } (edited)Foundation/String でFoundation だからFoundation の中の extension String に行くべきところが、 Foundation/String なページに飛ぼうとするところがバグっぽいですね。Tweet<U: User>は有りなんじゃねーかなーとかenum NullableResponseField<T> { case .some(T) case .null case .notProvided } enum NonnullResponseField<T> { case .some(T) case .notProvided } とかやるか、 Optional<Optional<T>> とするしか無さそう (edited)struct UserResponse { var name: NonnullResponseField<String> var bio: NullableREsponseField<String> }extension NonnullResponseField { var asOptional: E?? } ならまぁ。protocol PartialResponseType { associatedtype ConcreteType } 的な何かで、 User と UserResponse を紐付けておくとなんか嬉しいところがあるかも・・・? (edited)NullableResponseField に当たる、Optionalみたいなパシッとした名前ないかなあというのが最初のツイートtypealias Maybe<T> = Optional<T>enum NullableResponseField<T> { case .some(T) case .null case .notProvided } enum NonnullResponseField<T> { case .some(T) case .notProvided }omochimetaru - 今日 午後4時55分 Absentable<T> Optionalの類義語探すだけになりそう。なんか有名なパターンとかないんかねえ。 hiragram - 今日 午後4時56分 > Optionalの類義語探すだけになりそう そうなのよwswitch x { case .none, case .some(.none) case .some(.some) }enum NullableResponseField<T> { case .some(T) case .null case .notProvided } enum NonnullResponseField<T> { case .some(T) case .notProvided }friend 文はけっこ〜闇だったけどstruct Hoge { typeprivate var fuga: String } extension Hoge { func sayFuga() { print(fuga) } } みたいな?within a file だから同一ファイルだけじゃないかな * An extension of “X” in the same file * The definition of “X”, if it occurs in the same file * A nested type (or extension thereof) of one of the above that occurs in the same file This design has a number of apparent benefits: + “private” becomes the right default for “less than whole module” visibility, and aligns well with Swift coding style that divides a type’s definition into a number of extensions. + “fileprivate” remains for existing use cases, but now it’s use it more rare, which has several advantages: + It fits well with the "progressive disclosure” philosophy behind Swift: you can use public/internal/private for a while before encountering and having to learn about “fileprivate” (note: we thought this was going to be true of SE-0025 <https://github.com/apple/swift-evolution/blob/master/proposals/0025-scoped-access-level.md>, but we were clearly wrong) + When “fileprivate” occurs, it means there’s some interesting coupling between different types in the same file. That makes fileprivate a useful alert to the reader rather than, potentially, something that we routinely use and overlook so that we can separate implementations into extensions. + “private” is more closely aligned with other programming languages that use type-based access control, which can help programmers just coming to Swift. When they reach for “private”, they’re likely to get something similar to what they expect—with a little Swift twist due to Swift’s heavy use of extensions. + Loosening the access restrictions on “private” is unlikely to break existing code.protocol FieldProperty { associatedtype Value } struct Field<T> { enum Requirable: FieldProperty { typealias Value = T case some(T) case notProvided } enum Nullable: FieldProperty { typealias Value = T? case some(T?) case notProvided } } (edited)open class Hoge<T> { public typealias ErrorInfo = (error: Error?, isCancelled: Bool) var receiveError: ((ErrorInfo) -> Void)? } Hoge<String>().receiveError = { (errorInfo: Hoge.ErrorInfo) in print(errorInfo) }open class Hoge<T> { public typealias ErrorInfo = (error: Error?, isCancelled: Bool) var receiveError: ((ErrorInfo) -> Void)? } Hoge<String>().receiveError = { (errorInfo: Hoge<Any>.ErrorInfo) in print(errorInfo) }// o Hoge<Any>.ErrorInfo // x: 3.1〜Hoge.ErrorInfoとHoge<T>.ErrorInfoは区別する Hoge.ErrorInfo (edited)struct に indirect なプロパティほしいなぁと思ってるんだけどどうでしょう?struct Hoge { let a : Hoge } ↑できないenum は indirect の導入で解決されたOptional じゃないといけないかも。Optional だと入れられるのかenum に逃がして解決したはず。 1> struct Foo { 2. var bar: Int 3. var foo: Foo? 4. } error: repl.swift:1:8: error: value type 'Foo' cannot have a stored property that references itself struct Foo { ^Optional は indirect じゃないからだ。indirect な Optional を作れば解決するのか。indirect enum IndirectOptional<T> { case some(T) case none } struct T { let i: Int let a: IndirectOptional<T> }Optional で包んだ時点でヒープにいっちゃうのかstruct Foo { var bar: Int indirect var foo: Foo? }indirect enum Foo { case Tail(int: Int, str: String) case Head(int: Int, str: String, foo: Foo) var int: Int { // switch書く } var str: String { // switch書く } var foo: Foo? { // switch書く } init(int: Int, str: String, foo: Foo?) { if let foo = foo { self = .Head(int: int, str: str, foo: foo) } else { self = .Tail(int: int, str: str) } } }struct Foo { var bar: Int indirect var foo: Foo } はできないわけだし、ちょっとややこしそうだな。enum の indirect も同程度の理解を要求されるしいいのか?indirect enum IndirectOptional<T> { case some(T) case none init(_ value: T?) { switch value { case .some(let t): self = .some(t) case .none: self = .none } } } extension IndirectOptional { var asOptional: T? { switch self { case .some(let t): return .some(t) case .none: return .none } } } struct T { var i: Int private var _a: IndirectOptional<T> init(i: Int, a: T?) { self.i = i self._a = IndirectOptional(a) } var a: T? { set { _a = IndirectOptional(newValue) } get { return _a.asOptional } } } 使う側も書く側も楽に出来た気がする。indirect プロパティほしいなぁ。enum も昔は参照で Box してたけど indirect で解決されたわけだから、 struct でだけ Box が必要って今の状況は変な気がする。enum IndirectOptional<Wrapped> { case none indirect case some(Wrapped) }indirect 付けたい。indirect var a: Int? と var b: Int? があるときに (edited)a と b のメモリ上でのレイアウトが違っちゃって、 Int? に2種類のレイアウトがあることになるからa だけアドレスになんじゃないの?struct Foo { var bar: Int indirect var foo: Foo? } のサイズは 64 bit 環境だと 16 バイトvar xx: Foo? はFoo? は 17 バイトでしょ??Foo は値型で、 Foo が 16 バイトだから。indirect Int? と Int? の2つがあることを前提にコンパイラを修正しないといけないindirect case から値を取り出すときと何が違うの?indirect プロパティも「ついてない場合」なんてないのでは??xxのような場合についてない。indirect var foo: Foo? を var foo: Box<Foo?> と読み替えるのでは?enum でもパターンマッチして取り出す時にアンボクシングしてるのでは?indirect は enum 全体が indirect されるわけじゃなくて、あくまで個別 case が indirect されるだけでしょ? (edited)struct でも個別のプロパティが Box だったと解釈すればいいんじゃないの?indirect じゃないバージョンも考慮する必要がないよ。Int? は実在してるから。 (edited)enum の case も同じなんじゃないの?enum に入れるときにはボクシングするしenum そのものが indirect されてるわけじゃなくてcase が indirect なだけだから。enum Foo<T, U> { case bar(T) indirect case baz(U) }U だけ Box になる。enum Foo<T, U> { case bar(T) case baz(Box<U>) } ↑と等価。 (edited)struct のプロパティから値を取り出すときとそんな違いがありますか? indirect なプロパティなら unboxing すればいいだけな気が。baz が indirectだからうんぬんってことを気にすればいいのが 明示的に記述される switch-caseでの分解の時だけってのが大きな違いだと思うって事enum Foo { indirect case bar(int: Int, str: String, foo: Foo) } この時に、barの中身が全部Boxingされてると仮定するなら、内側のFoo単体についてはBoxに纏わる何かを考えなくて良い。 従ってBoxが関わってるのは外側のFoo型でswitchなりif caseなりで一気になんとかできる。 structのpropertyとは別な印象があります。 (edited)house.cat.name = "tama" みたいなときのgetter/setterの差し込み , didSet等が無ければその省略func ==(left: shared String, right: shared String) -> Bool { ... } これとか面白いstruct Foo { private var _inner: Any? = nil var inner: Foo? { get { return _inner.map { $0 as! Foo } } set { _inner = newValue } } } (edited) get { return _inner as! Foo? } はうまくいかないんですっけ?Any に Optional<T> を入れる手と Optional<Any> の Any を T にさせる手があるのかなMemoryLayout<Foo>.size == 8。 indirect enum Box<T> { case val(T) init(_ val: T) { self = .val(val) } var val: T { switch self { case .val(let val): return val } } } struct Foo { private var _inner: Box<Foo>? var inner: Foo? { get { return _inner?.val } set { _inner = newValue.map(Box.init) } } }indirect enum Box<T> って class Box<T> じゃダメなんでしょうか? class 使わずあくまで値型で済ませるならってこと?Box は隠蔽するからやっぱ class でも変わらないような?get, set のことばっか考えてた・・・indirect を class の Box で代替しても問題なかったのは、 enum がイミュータブルだからなのか。 (edited)Box そのものをいじっちゃったらダメだけど。enum の値取り出してたんだ??case let value? とかが追加になったくらいdealloc から deinit に名前が変わっている点についてdealloc じゃなくて deinit であるなあと気がついたdeallocの名前が不適切、ということUnsafePointer 周りの用語としても、 メモリ確保はAllocation/Deallocation、確保したメモリにオブジェクトをレイアウトする/剥がしてデストラクトするのが Init / deinit って用語がちゃんと揃ってるXXXXeable ってよく間違えられてるから間違えてるのではstruct Tuple2<A,B> ← 正直これ使いたくなるwwwclass Animal {} class Cat: Animal {} let cf: () -> (Cat, Cat) = { (Cat(), Cat()) } let af: () -> (Animal, Animal) = cf // エラーにならない let aa: (Animal, Animal) = af()var だったとしても共変で問題ないはずで、そもそもできないのが謎だけど何か理由があるのかな。class Animal {} class Cat: Animal {} class Dog: Animal {} var cats: [Cat] = [Cat()] var animals: [Animal] = cats // ここがコピーなので animals.append(Dog()) // これができても問題ないArray を Swift で実装するならってこと?Array ってピュア Swift なんだっけ?違った気が。var cats: [Cat] = [Cat()] var animals: [Animal] = cats // ここがコピーなので は _arrayForceCast() ってので実装されているので、cats.map { $0 } とほぼ同義です。 https://github.com/apple/swift/blob/master/stdlib/public/core/ArrayCast.swift#L30-L50import XCTest class SwiftCovariantCopyTests: XCTestCase { func testCopyWithoutAppend1M() { measure { let cats: [Cat] = [Cat](repeating: Cat(), count: 1_000_000) let animals: [Animal] = cats XCTAssertTrue(animals.last! is Cat) } } func testCopyWithAppend1M() { measure { let cats: [Cat] = [Cat](repeating: Cat(), count: 1_000_000) var animals: [Animal] = cats animals.append(Dog()) XCTAssertTrue(animals.last! is Dog) } } func testCopyWithoutAppend10M() { measure { let cats: [Cat] = [Cat](repeating: Cat(), count: 10_000_000) let animals: [Animal] = cats XCTAssertTrue(animals.last! is Cat) } } func testCopyWithAppend10M() { measure { let cats: [Cat] = [Cat](repeating: Cat(), count: 10_000_000) var animals: [Animal] = cats animals.append(Dog()) XCTAssertTrue(animals.last! is Dog) } } } class Animal {} class Cat: Animal {} class Dog: Animal {}
Test Case '-[SwiftCovariantCopyTests.SwiftCovariantCopyTests testCopyWithoutAppend1M]' passed (0.592 seconds). Test Case '-[SwiftCovariantCopyTests.SwiftCovariantCopyTests testCopyWithAppend1M]' passed (0.790 seconds). Test Case '-[SwiftCovariantCopyTests.SwiftCovariantCopyTests testCopyWithoutAppend10M]' passed (4.162 seconds). Test Case '-[SwiftCovariantCopyTests.SwiftCovariantCopyTests testCopyWithAppend10M]' passed (6.556 seconds). (edited)append 分だけ遅くなってる。map だから再生成って感じ?public var lazy: LazyRandomAccessCollection<Array<Element>> { get } これを使うとlazyになるのかあ。 (edited)#if _runtime(_ObjC) のほうに流れると思うのです。 (edited)ContiguousArray instance'), ('ArraySlice', 'an ArraySlice instance'), ('Array', 'an array'), ] }%
Test Case '-[SwiftCovariantCopyTests.SwiftCovariantCopyTests testCopyWithoutAppend10M]' passed (0.624 seconds). Test Case '-[SwiftCovariantCopyTests.SwiftCovariantCopyTests testCopyWithAppend10M]' passed (2.282 seconds). Test Case '-[SwiftCovariantCopyTests.SwiftCovariantCopyTests testCopyWithoutAppend100M]' passed (4.037 seconds). Test Case '-[SwiftCovariantCopyTests.SwiftCovariantCopyTests testCopyWithAppend100M]' passed (23.242 seconds).measure の外に出した。Test Case '-[SwiftCovariantCopyTests.SwiftCovariantCopyTests testCopyWithoutAppend10M]' measured [Time, seconds] average: 0.000, relative standard deviation: 114.231%, values: [0.000023, 0.000005, 0.000003, 0.000003, 0.000003, 0.000003, 0.000003, 0.000003, 0.000003, 0.000003], Test Case '-[SwiftCovariantCopyTests.SwiftCovariantCopyTests testCopyWithAppend10M]' measured [Time, seconds] average: 0.163, relative standard deviation: 4.494%, values: [0.183134, 0.158554, 0.160044, 0.163250, 0.155895, 0.158189, 0.163386, 0.161289, 0.159981, 0.167179], Test Case '-[SwiftCovariantCopyTests.SwiftCovariantCopyTests testCopyWithoutAppend100M]' measured [Time, seconds] average: 0.000, relative standard deviation: 115.617%, values: [0.000020, 0.000003, 0.000003, 0.000003, 0.000003, 0.000003, 0.000003, 0.000003, 0.000003, 0.000003], Test Case '-[SwiftCovariantCopyTests.SwiftCovariantCopyTests testCopyWithAppend100M]' measured [Time, seconds] average: 1.762, relative standard deviation: 2.715%, values: [1.793434, 1.729103, 1.745168, 1.726823, 1.730955, 1.749660, 1.729168, 1.716899, 1.845567, 1.851858], (edited)reserveCapacity はまだしてないです。 (edited)_arrayForceCast って as! の時が基本の用途っぽいんですけど今回みたいな型安全な代入でも挿入されるのか今気になってて探ってるけどまだ手がかり無しmeasure 外で reserveCapacity できない・・・。 animal は measure の中で代入して生成されてるから・・・。-emit-sil で %17 = function_ref @_TFs15_arrayForceCastu0_rFGSax_GSaq__ : $@convention(thin) <τ_0_0, τ_0_1> (@owned Array<τ_0_0>) -> @owned Array<τ_0_1>, loc "test.swift":7:27, scope 21 // user: %18 %18 = apply %17<Cat, Animal>(%14) : $@convention(thin) <τ_0_0, τ_0_1> (@owned Array<τ_0_0>) -> @owned Array<τ_0_1>, loc "test.swift":7:27, scope 21 // user: %19cats で reserveCapacity しておけば、buffer 共有されているなら capacity 維持されるはずだからreserveCapacity したいのって、代入時にコピーが走ってるけど append でバッファのallocateが走ってしまってるから With と Without で差が付いている可能性を排除したいってことですよね?append 時にはどのみち allocate されるから関係なくないですか?import XCTest class SwiftCovariantCopyTests: XCTestCase { func testCopyWithoutAppend10M() { let cats: [Cat] = [Cat](repeating: Cat(), count: 10_000_000) measure { let animals: [Animal] = cats XCTAssertTrue(animals.last! is Cat) } } func testCopyWithAppend10M() { let cats: [Cat] = [Cat](repeating: Cat(), count: 10_000_000) measure { var animals: [Animal] = cats animals.append(Dog()) XCTAssertTrue(animals.last! is Dog) } } func testCopyWithoutAppend100M() { let cats: [Cat] = [Cat](repeating: Cat(), count: 100_000_000) measure { let animals: [Animal] = cats XCTAssertTrue(animals.last! is Cat) } } func testCopyWithAppend100M() { let cats: [Cat] = [Cat](repeating: Cat(), count: 100_000_000) measure { var animals: [Animal] = cats animals.append(Dog()) XCTAssertTrue(animals.last! is Dog) } } } class Animal {} class Cat: Animal {} class Dog: Animal {}Without の方が速かったのが、という意味ならその通りですし、 CoW が効いてるのがという意味なら @omochimetaru の言う通りどちらでも効いてて、生成が measure のノイズになっていたということです。
map になっちゃうのか。// こういうジェネリックなstructがあるときに struct S<T> { var s: T } var scat: S<Cat> = S<Cat>(s: Cat()) // ↓こんな事や var sani1: S<Animal> = sa // ↓次善でこんな事が var sani2: S<Animal> = sa.upcast() // できたらいいのにな (edited)std::enable_if<std::is_convertible<T, U>::value> なんかこんな雰囲気でできる。var sani1: S<Animal> = S(s: scat.s)func some<T, U> (_ something: A<T>) -> A<U> where T: Uextension S { init<U>(_ o: S<U>) where T: U { self.init(s: o.s) } } // ↑これでいけるかとおもったけど駄目だった。 (edited)(T, (S)) を (T, S) と同一視する」というルールを設ければ色々解決したりしませんかねtype(of: (1, (2))) // (Int, Int).Type type(of: (1, 2)) // (Int, Int).Type(T) を T と同一視する」はそうなってるんですが、それとは違って… と思ったけど言い方がよくなかったですね(1,2) == (1, (2)) // 2 == (2) なので true (1,2,3) == (1,(2,3)) // Binary operator '==' cannot be applied to operands of type '(Int, Int, Int)' and '(Int, (Int, Int))' 下が通れば無限個のタプルを処理できるなーということです (edited)Equatable 準拠とか出来ないので == もタプルの要素数毎に定義されてますよね。(6要素まで) public func == <A : Equatable, B : Equatable, C : Equatable, D : Equatable, E : Equatable, F : Equatable>(lhs: (A,B,C,D,E,F), rhs: (A,B,C,D,E,F)) -> Bool { たぶんタプルを型として扱える様にしないとタプルのネストとか解決できない。(A,B,C) が (A,(B,C)) のシュガーシンタクスだと解釈できるようになれば、 public func == <A : Equatable, B : Equatable>(lhs: (A,B), rhs: (A,B)) -> Bool で全て賄えるはずだなと思ったんです、が… たしかにご指摘の通り、現状の言語仕様だとそもそもタプルをEquatable準拠させることが不可能なので、 B: Equatable が成立しないとこで詰みますねfileprivate を使う機会を減らせそう((A, B), C) と (A, (B, C)) は違う型ということやんね?それは同意です。struct を利用する圧力になっていると思う。struct がプロトコル型の stored property を持ってるのと同じじゃないですか?P1 だったとすると、 var x: (P1, P1) の取扱は、 var y: P1 と、ただの単一変数が、 struct S { var y: P1 ; var z: P1 } とフィールドに並んだ場合と同じだと思います。
enum のペイロードもタプルだと思っていたのだけど、記述がない?The kind of type is stored at offset 0, which is as follows: 0 for a class, 1 for a struct, or 2 for an enum. 結果的に認識とは一致していそう。タプルやファンクションはnon-nominalですね() -> Animal に対する extension は () -> Cat にも使えるのか。class Animal {} class Cat: Animal {} let a: () -> (Int, (String, Cat)) = { (42, ("xyz", Cat())) } let b: () -> (Int, (String, Animal)) = alet c: (Int, (String, Animal)) -> () = { _, _ in } let d: (Int, (String, Cat)) -> () = clet convarianceAnimalCage = AnyAnimalCage<Animal>(~catCage) // Adding `~` operator, pass compile it! 💪let foo: () -> (Cat, Int) = { (Cat(), 1) } let foo2: () -> (Animal, Int) = foo のときは -dump-astで (function_conversion_expr implicit type='() -> (Animal, Int)' (declref_expr type='() -> (Cat, Int)' )) だけどfunction_conversion_expr が噛まされているってことですね // We need to convert the source element to the destination type. if (!fromTupleExpr) { // FIXME: Lame! We can't express this in the AST.reduce で Dictionary 作る時とかだるすぎたからlet anyany: (Any, Any) = (Int(1), Int(1)) if let intint = anyany as? (Int, Int) { print(intint) // 3.0.2: unreachable, 3.1: "(1, 1)\n" } if let int0 = anyany.0 as? Int, let int1 = anyany.1 as? Int { print(int0, int1) // "1 1\n" }
(edited)let a: (AnyObject, AnyObject) = (Cat(), Cat()) let b = a as! (Animal, Animal) みたいなときは、静的なキャストができなくてタプル全体が実行時キャストになるから FIXME のところまで到達しないと思います。 (edited)prefixとdropで足りるんですけどねprotocol 作ればできる気がする。protocol GeneralRange { associatedtype Value: Comparable var lowerBound: Value? var upperBound: Value? } extension Range: GeneralRange {} ... (edited)RangeとClosedRangeでupperBoundの意味が違った記憶subscript だと 4 通りだけど、組みわせになると爆発するから https://github.com/koher/EasyImagy/blob/swift-3/EasyImagy/Image.swift#L78-L92var includingUpperBound: Bool も生やせば解決? (edited)1<..42 とかも作って欲しい。<..<まででてくると気持ち悪そう<.< か <..< か悩ましいな。(begin, end): begin <= x && x < end とするのが好きで、理由はこれだと連続な直線を過不足なく繰り返し分割できるからRange で事足りると言ってる?a<..b が要らない理由とはならない気が。 (edited)extension ${Self}: RangeExpression { こんな書き方初めて見たGenerate Your Boilerplateswift_oss_helper.py helps debugging Swift Standard Library using source code with Swift Toolchain distributed at swift.org.class Animal {} class Cat: Animal {} let strinCat: (String, Cat) = ("xyz", Cat()) if let stringAnimal: (String, Animal) = strinCat as? (String, Animal) { print(stringAnimal) } でエラー: Playground execution failed: warning: 20170418-130912.xcplaygroundpage:1:50: warning: conditional cast from '(String, Cat)' to '(String, Animal)' always succeeds if let stringAnimal: (String, Animal) = strinCat as? (String, Animal) { ^ error: 20170418-130912.xcplaygroundpage:1:41: error: cannot express tuple conversion '(String, Cat)' to '(String, Animal)' if let stringAnimal: (String, Animal) = strinCat as? (String, Animal) { ^warning: conditional cast … always succeeds と言われるので as? から as へ変えると、2番目のエラーだけになる。 (edited)FIXME: に引っかかってるぽいですclass Animal {} class Cat: Animal {} let strinCat: (String, Cat) = ("xyz", Cat()) print(strinCat) if let stringAnimal: (String, Animal) = strinCat as Any as! (String, Animal) { print("yatta") print(stringAnimal) } これでyattaが出力された・・・ (edited)protocol Integral {} extension Int: Integral {} struct Foo<T> {} extension Foo where T: Integral { func foo() { let zelf = self as! Foo<Int> print(zelf) } } let foo: Foo<Int> = Foo() foo.foo()
$ swift AlwaysFailed.swift AlwaysFailed.swift:8:25: warning: cast from 'Foo<T>' to unrelated type 'Foo<Int>' always fails let zelf = self as! Foo<Int> ~~~~ ^ ~~~~~~~~ Foo<Int>() (edited)T == Intできるから見なくなったやつですねFoo を Array にするとコンパイルエラーになるという謎挙動だったはず。 (edited)extension Array where Element: Integral { func foo() { let zelf = self as! Array<Int> print(zelf) } } swift sandboxで何も言われないlet zelf = self as! Foo<Int>Ty<Some> から Ty<Covariant> への変換) って https://devforums.apple.com/thread/261699 で語られているんですが、 https://devforums.apple.com/message/1102432#1102432 のArrayとかは出来るけど任意の value type には当てはまらないって文脈で > this doesn't apply to every value type (because value types can contain references and not enforce copy-on-write) らしいのですが、どういうケースなんでしょう? (edited)Farm<Cow> を Farm<Animal> として扱えないという。Array<Cow> を Array<Animal> として扱っていい理由の話ですが、 CoW はあんま関係ない気がしますね。Farm<Cow> as Farm<Animal> できるとして、どういう不整合が発生する可能性があるのかを知りたい。func some(_ t: T) が生えてる場合は困ったことになる気がするfunc makeAllAnimalsSpeakInFarm(farm : Farm<Animal>) { farm.listenToAnimals() } じゃなくて func makeAllAnimalsSpeakInFarm<A: Animal>(farm : Farm<A>) { farm.listenToAnimals() } でいいんじゃない?って言ってる。この、サブタイピングに頼らずジェネリック関数で解決するの、 Swift 的に正しいと思う。 (edited)func some<T, U> (...) where T: U が書けないのでfunc some<T, U> (...) where T: U ←これのどこらへんが書けない?func some<T, U> (...) where T == U って書いて、Uに束縛される側を、サブタイピングなGenericsで宣言し直すtypealias AnySequence<Element> = Any<Sequence where .Iterator.Element == Element> これって完全にあの書くのがめんどくさいTypeErasureのList<Integer> xs = new ArrayList<Integer>List<String> とか書くノリで、 [String] じゃなくて AnySequence<String> になってしまいそう。java // Java List strings = new ArrayList(); ArrayList インスタンスを `Arr...List<String> な世界を目指すなら Generalized existentials や Type Erasure はめんどくさすぎますし、サブタイピングに頼らない静的ディスパッチな世界を目指すなら Generalized existentials もプロトコル型変数すらもいらないと思うんですよねぇ。S: Sequence な S を受け取るだけだから、 その S の makeIteartorに転送するだけのコードがAnySequenceの実体ですtypealias AnySequence<Element> = Any<Sequence where .Iterator.Element == Element> let strings: AnySequence<String> = ["a", "b", "c"] (edited)AnySequence とは別物では?func f <E, S : Sequence> (s: S) where S.Iterator.Element == E とかやったときに、 これを呼び出す時に引数に渡したArrayがSequenceとしてアップキャストされるときと、 同じような仕組みで実現されると思っていてtypealias AnySequence<Element> = Any<Sequence where .Iterator.Element == Element> Generic Existential + type alias としての AnySequenceは_makeIterator = { _ in s.makeIterator() } ←これはクソ遅くなりそうだというのはわかるけど、 _makeIterator = s.makeIterator ←これはセーフでは?class MyAnyIteratorBoxBase<Element> { func next() -> Element? { fatalError("abstract") } } class MyAnyIteratorBox<I : IteratorProtocol> : MyAnyIteratorBoxBase<I.Element> { var base: I init(_ base: I) { self.base = base } override func next() -> I.Element? { return base.next() } } struct MyAnyIterator<Element> : IteratorProtocol { var base: MyAnyIteratorBoxBase<Element> init<I : IteratorProtocol>(_ base: I) where I.Element == Element { self.base = MyAnyIteratorBox(base) } func next() -> Element? { return base.next() } } こんな感じ。Foo<T> があったときに struct Foo<T> { var ts: Any<Sequence where .Iterator.Element == T> init(_ ts: Any<Sequence where .Iterator.Element == T>) { self.ts = ts } } ↓で作った a と b の間で同じ型なのにメモリレイアウトを変えないといけなくなりません? var a: Foo<Int> = Foo(Array([2, 3, 5])) // Arrayにspecializeされる var b: Foo<Int> = Foo(Set([2, 3, 5])) // Setにspecializeされる a = b // どうなる??class Animal {} class Cow : Animal {} class Sheep : Animal {} class Fence<T> { var animal: T? = nil } struct Farm<T> { var fence: Fence<T> = Fence<T>() } func buySheep(farm: Farm<Animal>) { farm.fence.animal = Sheep() } let farm = Farm<Cow>() buySheep(farm: farm as Farm<Animal>)Farm が Generic なクラスを持ってたらだめってことでした。struct Farm<T> { var 困る奴: (T)->() }class Box<out T> {} みたいに、 Tの前に in か out をつけられる (edited)class Foo[+A] // A covariant class class Bar[-A] // A contravariant class class Baz[A] // An invariant class[ ] は < > だと思えばOKMirror って積極的に使っても良いものなのだろうか?struct とイミュータブルクラスは等価だから書き変えて、 variance annotation ( out ) を付けて考えると Fence の animal がコンパイルエラーですね。 setter が許容できない。 class Animal {} class Cow : Animal {} class Sheep : Animal {} class Fence<out T> { var animal: T? = nil // コンパイルエラー } class Farm<out T> { let fence: Fence<T> = Fence<T>() } func buySheep(farm: Farm<Animal>) { farm.fence.animal = Sheep() } let farm = Farm<Cow>() buySheep(farm: farm as Farm<Animal>)
// Kotlin open class Animal() class Cow : Animal() class Sheep : Animal() class Fence<out T> { var animal: T? = null } class Farm<out T> { val fence: Fence<T> = Fence<T>() } fun buySheep(farm: Farm<Animal>) { farm.fence.animal = Sheep() } fun main(args: Array<String>) { val farm = Farm<Cow>() buySheep(farm) } 予想通り Fence の animal でコンパイルエラー。 $ kotlinc NestedGenerics.kt NestedGenerics.kt:6:17: error: type parameter T is declared as 'out' but occurs in 'invariant' position in type T? var animal: T? = null ^out な型パラメータは引数でつかえず、 in な型パラメータは戻り値で使えません。Foo<in T> だったときにout T の型の中で Foo<T> を引数として使うことはできます。(T) -> U を Function<in T, out U> と読み替えれば OK です。T について covariant な Foo<T> ( Foo<out T> のように振る舞う)を作ることに成功した。 typealias Foo<T> = () -> T class Animal {} class Cat: Animal {} let a: Array<Foo<Cat>> = [] let b: Array<Foo<Animal>> = a // OKclass Animal {} class Cow : Animal {} class Sheep : Animal {} class Fence<T> { var animal: T? = nil } typealias Farm<T: Animal> = () -> Fence<T> func makeFarm<T: Animal>() -> Farm<T> { return { Fence<T>() } } func buySheep(farm: Farm<Animal>) { farm().animal = Sheep() } let farm: Farm<Cow> = makeFarm() buySheep(farm: farm) // FenceがinvariantなのでfarmもinvariantでコンパイルエラーFence を covariant にしようとして typealias Fence<T> = () -> T? にすると、今度は animal を var にできません( Fecce の T が out である制約が効いていると解釈できる)。mutating func は static メソッドに読み替えれば解釈できそう。 ↓ Array は covariant にできる class Array<out E> { func get(_ index: Int) -> E { ... } static func set<E>(_ this: Array<E>, _ index: Int, newValue: E) -> Array<E> { ... } } けど、 Fence は covariant にできない。 class Fence<T> { var animal: T? = nil } class Farm<out T> { let fence: Fence<T> = Fence<T>() // Fence が T について invariant なのでエラー }class Fence<out T> { func getAnimal() -> T? { ... } static func setAnimal(_ this: Fence, newValue: T?) -> Fence { ... } } このように定義しておけば、 Farm<out T>も成り立ちそう。Fence が struct と等価になってしまって、最初の「不整合」なケースの前提が崩れてしまいます。逆に言えば、 Fence も struct なら struct Farm は covariant 的に振る舞っても問題ないということですね。 (edited)class Animal {} class Cat extends Animal {} class Dog extends Animal {} public class CovariantArray { public static void main(String[] args) { Cat[] cats = { new Cat() }; Animal[] animals = cats; animals[0] = new Dog(); // 実行時エラー System.out.println(cats[0]); } }private extension Hoge: FugaProtocol {} こういうのできたらいいのになーって思ったことないですかfileprivate protocol Foo { func foo() -> Int } extension Int: Foo { fileprivate func foo() -> Int { return self } }internal で、それをある特定のファイルの中だけで満たすよう( fileprivate )にしたいというニーズということですか?protocol Hoge {} private protocol PrivateHoge { var xxx, yyy, zzz } extension Hoge where Self: PrivateHoge { ... } (edited)xxx とかつけるの逆に考えてて( Hoge につけるの考えてて)、だめだなぁと思ってた。 (edited)private protocol Testable { var test: Int { get } } extension MyVC: Testable { fileprivate var test: Int { return 1 } }private protocol をより広い protocol が継承するのは変だ。Hoge を色んなところで使いたくて、それをある場所では private に使いたいという話だと思うんですが、PrivateHoge から Hoge に流す部分で、Hoge が使いたかった箇所から可視にすることができない気がします。class MyViewController { class ScrollViewDelegateImpl: UIScrollViewDelegate { let parent: MyViewController } lazy private (set) var scrollViewDelegate: ScrollViewDelegateImpl = { [unowned self] in ScrollViewDelegateImpl(self) }() }Comparable の変更含まれていないのね。 (edited)let str = [ "hello \(name)", "world" ].joined(separator: "\n") 配列はこうかなhogeDisposable.disposed(by: fuga) は「fugaによってdisposeされたhogeDisposable」が返るってことにならんかなあとおもって// Allowed, equal to "foo\nbar" """ foo bar """ // Not allowed """foo bar """ // Not allowed """ foo bar"""""" をベースに考えるってことかな?妥当な気がする。 (edited)var x = """ hogehoge """""""は一つ落としたい感じが// Kotlin val text = """ |Tell me and I forget. |Teach me and I remember. |Involve me and I learn. |(Benjamin Franklin) """.trimMargin()""" でコントロールっておもしろいなぁ。"""の中なら、"はエスケープしなくても良いのかな、可読性一気に上がりそうassert( xml == """ <?xml version="1.0"?> <catalog> <book id="bk101" empty=""> <author>\(author)</author> <title>XML Developer's Guide</title> <genre>Computer</genre> <price>44.95</price> <publish_date>2000-10-01</publish_date> <description>An in-depth look at creating applications with XML.</description> </book> </catalog> """ )// Allowed, equal to "foo\nbar" """ foo bar """ は "foo\nbar\n" ではなく "foo\nbar" なのか。""" を書かせることでインデントをコントロールできるところがミソかと。"""aaa bbb""" これで "aaa\nbbb" になる。""" でインデントと本文を区別させる方式なら"\m" を入れるわけにはいかない。最後の "\n" を消す方法がなくなっちゃうから。let s = """ abc def """ 今の仕様ならこれで末尾 "\n" が実現できるし。trimMargin もいらないし、これはうまい仕様だなぁ。 // equal to "foo\nfoo\nfoo\nfoo" """^J foo^M^J foo^J foo^M foo^M """disposed(by: )についてはペアがでてこなそうなのでこれで良い気もする。import Foundation protocol MyCustomErrorProtocol: Error { var hoge: Int { get } } struct MyCustomError: MyCustomErrorProtocol { var hoge: Int { return 1 } } extension NSError: MyCustomErrorProtocol { var hoge: Int { return -1 } } let error: Error = MyCustomError() if let cError = error as? MyCustomErrorProtocol { print(cError.hoge) // macOS: -1, linux: 1 } (edited)struct B: Foo, FooStandard, FooFatal {} こっちはコンパイル通らないしextension Foo where Self: FooStandard vs extension Foo where Self: FooFatalsil_witness_table hidden AAA: Foo module a { method #Foo.foo!1: @_TTWC1a3AAAS_3FooS_FS1_3foofT_SS // protocol witness for Foo.foo() -> String in conformance AAA }sil_vtable AAA { #AAA.deinit!deallocator: _TFC1a3AAAD // AAA.__deallocating_deinit #AAA.init!initializer.1: _TFC1a3AAAcfT_S0_ // AAA.init() -> AAA } sil_vtable BBB { #AAA.init!initializer.1: _TFC1a3BBBcfT_S0_ // BBB.init() -> BBB #BBB.deinit!deallocator: _TFC1a3BBBD // BBB.__deallocating_deinit }sil_witness_table hidden AAA: Foo module a { method #Foo.foo!1: @_TTWC1a3AAAS_3FooS_FS1_3foofT_SS // protocol witness for Foo.foo() -> String in conformance AAA } sil_witness_table hidden AAA: FooStandard module a { } sil_witness_table hidden BBB: FooFatal module a { }open にしない限りサブクラス系の問題はモジュール内で解決できちゃうし、基本 open はよっぽどの理由が無い限り使わないように、ってことになってるので、プライオリティは低い気がしますねぇ。-emit-irを使うとメソッドにどのwitness tableが渡されてるかわかるぽい。 callFoo(B()) // hello
%112 = call { i64, i64, i64 } @main.callFoo <A where A: main.Foo> (A) -> Swift.String(%swift.opaque* noalias nocapture %111, %swift.type* %21, i8** getelementptr inbounds ([1 x i8*], [1 x i8*]* @protocol witness table for main.A : main.Foo in main, i32 0, i32 0))
class C: Foo, FooStandard, FooFatal {} callFoo(C()) // fatal
%122 = call { i64, i64, i64 } @main.callFoo <A where A: main.Foo> (A) -> Swift.String(%swift.opaque* noalias nocapture %121, %swift.type* %118, i8** getelementptr inbounds ([1 x i8*], [1 x i8*]* @protocol witness table for main.C : main.Foo in main, i32 0, i32 0)) (edited)class Bed {} class Nook : Bed {} class Cat<T> { func eat(snack: T) {} func play(game: String) {} func sleep(where: Nook) {} } class Dog : Cat<(Int, Int)> { // 'T' becomes concrete override func eat(snack: (Int, Int)) {} // 'game' becomes optional override func play(game: String?) {} // 'where' becomes a superclass override func sleep(where: Bed) {} }
(edited)Dog: Cat ってカオスwimport Cocoa class CrasherBase: NSView { var hasRect: Bool = false var rect: CGRect? { return hasRect ? CGRect(x: 0, y: 0, width: 50, height: 50) : nil } override func draw(_ dirtyRect: NSRect) { NSEraseRect(dirtyRect) } } class Crasher2: CrasherBase { override var rect: CGRect { return CGRect(x: 0, y: 0, width: 100, height: 100) } override func draw(_ dirtyRect: NSRect) { NSEraseRect(rect) } }class Animal { var foo: Int? { return nil } } class Cat: Animal { override var foo: Int { return 42 } } (edited)Crasher2#drawを消したらクラッシュしないんですがNSEraseRect(rect) がミソですねclass Animal { var foo: Int? { return nil } } class Cat: Animal { override var foo: Int { return 42 } func useFoo() -> Int { return self.foo * 2 } }func でもダメだ。 class Animal { func foo() -> Int? { return nil } } class Cat: Animal { override func foo() -> Int { return 42 } func useFoo() -> Int { return self.foo() * 2 } } (edited)class Animal { func foo() -> Int? { return nil } } class Cat: Animal { override func foo() -> Int { return 42 } } Cat().foo() * 2 ↑外で呼んでもダメですねOptional とサブタイピングについて調べてたときに踏んだ気がする。継承で戻り値狭められるから Foo は Foo? のサブタイプ扱いされてますねって話で、でもメソッド定義するだけじゃなくて使おうとしたらすぐ死んでた気が。class Animal { func foo() -> Int? { return nil } } class Cat: Animal { override func foo() -> Int { return 42 } } let f = Cat().foo f() ↑回避できたCat.foo(f)()だと行けるかと思ったけど死んだFoo が Foo? に暗黙の型変換されるのを邪悪だと言ってますが、オーバーライドで戻り値を Foo? から Foo に狭められるなら Foo は Foo? のサブタイプでないといけないわけで、それなら Foo? 型変数に Foo を代入するのは暗黙の型変換ではなくアップキャストとみなせるわけですが、それについてはどうですか?Foo と Foo? のサブタイピング自体が邪悪ってことですね。Optional は Tagged Union なんだから本来サブタイプじゃないはずなんですけど、サブタイプ的にに振る舞わせることで、 Untagged Union で作られた Optional みたいになっちゃってるんですよね。Foo? は Foo|Null という (Untagged) Union になってて、当然 Foo は Foo?` のサブタイプなんですけど、Foo?? とかもできるわけだし、サブタイプ的に振る舞わせるのが微妙ですよねぇ・・・。Foo? を Foo に狭めるのも、代入時の暗黙の型変換も全部なしってのがシンプルな気がする。今更無理だけど。Some(x) で包むので特に不便感じないSimpleDomainError が throws じゃダメな理由がわかりました。Optional と Simple domain error が区別されることも意味がありますが、 Simple domain error が Recoverable error と区別されることにも意味がありそうです。struct SimpleDomainError: Error {} は、当然ですが Simple domain error なので、エラーが発生したという情報しか持たないわけです。extension Int { struct SDE: Error {}} とか (edited)throws というのはエラーを合成したり伝播したりして処理するために設計されているんで (edited)Error にしてしまうとそういう風に使うことをミスリードしてしまうわけです。Error のまま取り回したり合成したりすることを推奨するのは望ましくないと。enum Failable<Value> { case success(Value) case failure } を Optional とは別に作るのがいいかもしれません。array.first とか dictionary[foo] とか)Error か Optional のどっちに寄せるかと言われると、個人的にはすぐ処理することが強制される Optional かなぁと思います。Error にするという世界もあり得るとは思います。 (edited)Optional か、 Error で表す Recoverable error か。array.first とか array.max とかを Optional にするなら、それで消せるのって Int.init(String) くらいな気もするんですよね。Optional を合成しちゃうと出処がわからなくなってnil じゃないはずの値が nil になっちゃったときに、どれが元々 nil なんだ?ってのを探るのが大変Int を足して偶数を期待する状況は稀にしかおこりませんが、nil だと起こると思うんですよ。return curry(User.init) <^> json["name"] <*> json["age"] <*> json["gender"]nil だった場合にどのパラメータが nil だったんだ?みたいな。name: String? と age: Int? と gender: Gender? があるときにOptional プロパティからとってきたときかもしれないですよね?struct UserRecord { var name: String? var age: Int? var gender: Int? }json が json じゃなくて record という Dictionary かも。guard let name = record["name"] else { throw ... } guard let age = record["age"] else { throw } guard let gender = record["gender"] else { throw } return User(name, age, gender) (edited)Optional をすぐに処理すべきという話。extension Dictionary { subscript(key: Key) throws -> Value { ... } }do { return try User(record["name"], record["age"], record["gender"]) } catch { throw User.Error.decodeFail(error) } (edited)User 各プロパティに nil が許されているけど、特定の機能に関してはすべて非 Optional なプロパティをもった CompleteUser が求められているかもしれないです。そういうときに User から CompleteUser を作るのも同じ話になります。
Optional をローカルで取り回したいケースってどういうときがありますか?Optional な引数に渡す値を作って、可読性のために一度変数に代入したいときとか?Optional としてそのまま使いたい場合、つまり、何かの引数に渡したい場合ってことであってる?
Optional であったとしても関数ローカルではすぐにハンドリングすべきというのが僕の考えでnil かどうかで分岐して何か処理する場合。 < 引数に渡さない場合 (edited)Optional であったとしても、その値が nil の状態で実行するとその処理としてはエラーとして Error を throw するとかはあり得る。Optional の合成は必ずしも悪ではないと考えていますが、それにしてもその合成結果を長々と取り回す必要はなくて、 N 個の Optional を合成後すぐに処理すべきですよね?
Optional 値を生成するという以外に、 Optional のまま値を取り回したいケースってないような気がするんですよね。let foo: Foo? = ... ... let bar: Bar? = foo?.bar(...) ... let baz: Baz? = a.b?.c.flatMap { bar?.baz($0) } ... guard let qux = baz.map { Qux($0) } else { ... }Optional を使うのは当然あり得ると思います。try(相当のもの) は右にあるべきだった。 (edited)Int.init(String) とかも面倒で、 string.toInt() みたいに右にある方が使いやすかった。string => { Int($0) } ですかね・・・。 (edited)Int.init(String) 等の conversion 系は throws であるべきというのはあり得る。index とか、 first, min や Dictionary.subscript がエラーなのかどうかは解釈次第だと思う。 @tarunon さんの言うようにオーバーロードも一つの解なのかもしれないけど、それを正しく使い分けられる人は少なそう・・・。Optional to throws の簡単な方法があればいいんじゃないかな? (edited)Optional 用の ??? 演算子を提案しててguard でいいでしょということで終わった。!! は ! より危なそうに見えるからfunc f() -> String? { return "Optional<String>" } func f() throws -> String { return "String" } let a = try? f() // "String" let b: String? = f() // "Optional<String>" // ^ 型アノテーションがないと error: ambiguous use of 'f()'throws に対して Logic failure 無視の ! より危険そうな !! を割り当てるのは微妙そう。try は書かないといけないから同じじゃないかな?class C { func s() throws -> String { return "a" } func s() -> String? { return "b" } } do { let a: String = try C().s() // a let b: String? = C().s() // b } catch { print(error) }struct S { func f() -> String? { return "Optional<String>" } func f() throws -> String { return "String" } func nonThrow() { let a = try? f() // "String" let b: String? = f() // "Optional<String>" // ^ 型アノテーションがないと error: ambiguous use of 'f()' } } (edited)??? があればよかったのかなぁ。array.first とかが throws なのはきつい気も。throws にできない問題が。first はプロパティなのでarray.first が first() のメソッドリファレンスかもしれない・・・first というプロパティがあって、最初の値がないから nil ってのはごく自然な解釈だとも思うんだよなぁ。Optional プロパティも否定してない? < 無いものは取れない (edited)birthday: Date? を持ってる User 型に対して、 birthYear を取り出す処理はどっち? (edited)Optional と throws のオーバーロードが推測でうまく扱えるようになったとして、じゃあそんなメソッドを書くときは実行速度の観点から Optional 版を書いてそれを throws 版でラップする形になる?Int? 。空としてのnoneはbirhtdayのストレージのところに実在してるからbirthday: Date? を保持しているのか、 birthYear/Month/Date : Int? を保持しているのかはカプセル化された中の話。Optional ってことね。 > @omochimetaru (edited)first のように一段抽象度の高い概念かどうかだと。??? を実装して使ってみるとかstruct OptionalError: Error { let file: String let function: String let line: Int } extension Optional { func `throw`(file: String = #file, function: String = #function, line: Int = #line) throws -> Wrapped { guard let wrapped = self else { throw OptionalError(file: file, function: function, line: line) } return wrapped } } オペレーターで十分な情報を取る方法が思いつかなかった (edited)do { let user = try User( name: name.throw(), age: age.throw(), gender: gender.throw() ) } catch { throw User.Error.decodeFail(error) } こんな感じにしてサクッと特定できる世界観にはなりますねnil だったか知りたいみたいなのには応えられるのかな (edited)#line で分岐とかゾッとするので、Mirror とか使うといいのかな (edited)??? とは別物って感じですね。??? は出てこないけど。first とかも含めて SDE なんてなくして適切なエラー情報込みで throws にすべきだとして、 ??? はいるんですっけ?現実的に first とかが Optional を返すからってこと?extension Array { func first() throws -> Element { guard let value = self.first else { throw EmptyError() } return value } } struct EmptyError: Error {} let array = [2, 3, 5] let a = array.first let b = try! array.first() print(a) // Optional(2) print(b) // 2 (edited)array.first は ambiguous にならないんだろう?class C { var s: String? { return "a" } } extension C { func s() throws -> String { return "b" } }extension Array { var first: Element? { return nil } } 普通にこれが通るのでfunc first() throws -> Element はオーバーライドじゃなくてオーバーロードですよね?これが同一モジュールだとできないのにモジュール外だとできるのはなんでなんでしょう??// ModuleA public extension Array { public var first: Element? { return nil } } // ModuleB import ModuleA let a = [1,2,3].first とかしたらambigousになると予想。 (edited)import ModuleA してなければ元の first が実行されるんですよね? (edited)// ModuleA public extension Array { public var first: Element? { return nil } } // ModuleB public extension Array { public var first: Element? { return self[0] } } // main import ModuleA import ModuleB let a = [1,2,3].first さすがにこれはambigous (edited)import でコントロールできるんだったら、 extension メソッドにプレフィックスつけたりネームスペース切ったりするのが流行ってたけど不要?import したくて衝突したときに、どっちか指定する方法がないのか・・・。foo.bar にせずに foo.rx_bar とか foo.rx.bar みたいなやつ。// ModuleA public extension Array { public var first: Element? { return nil } } // ModuleB import ModuleA public extension Array { public var first: Element? { return self[0] } } // main import ModuleB let a = [1,2,3].first これでambigous。これはまずいんじゃ・・・// ModuleA public extension Array { public var first: Element? { return nil } } // ModuleB import ModuleA // main import ModuleB let a = [1,2,3].first これはnil になる。まずすぎる (edited)struct Matrix { var elem: [[Float]] } について 可 let a: [[Float]] = [[1, 2], [1.0/2 1.0/3]] _ = Matrix(elem: a) 不可 _ = Matrix(elem: [[1, 2], [1.0/2 1.0/3]])_ = Matrix(elem: [[1.0, 2.0], [1.0/2.0 1.0/3.0]]) これもだめですかねERROR at line 9, col 31: cannot convert value of type 'Double' to expected element type 'Float' _ = Matrix(elem: [[0, 1], [1.0/2.0, 1.0/3.0]]) ~~~^~~~ Float( )struct Matrix { var elem: [[Float]] } _ = Matrix(elem: [[1.0, 2.0], [1.0/2.0, 1.0/3.0]])_ = Matrix(elem: [[1.0, 2.0], [1.0/2.0, 1.0/3.0]]) これが通らないのはバグな気がする[[Float]]に代入するところができますからねぇ/// - Parameters: /// - optional: An optional value. /// - defaultValue: A value to use as a default. `defaultValue` is the same /// type as the `Wrapped` type of `optional`. public func ??<T>(optional: T?, defaultValue: @autoclosure () throws -> T) rethrows -> TintOpt ?? throw HogeError() こう書けるって事?intOpt ?? HogeError() (edited)public func parse(data: Data) throws -> Any { return UIImage(data: data) ?? Error.imageNotFound }_ = Matrix(elem: [[1, 2], [1.0/2 1.0/3]]) は master で -Xfrontend -propagate-constraints ていう experimental なフラグ付けたら通りました。enum Error: Swift.Error { case unavailable } let dictionary: [AnyHashable:Any] = [:] do { _ = try dictionary["unavailable"] ?? { throw Error.unavailable }() } catch { print(error) // "unavailable\n" } (edited)extension Error { func `throw`<T>() throws -> T { throw self } } struct MyError : Error {} let str = "hoge" do { try print(Int(str) ?? MyError().throw()) } catch { print(error) } いやーw-> T にしないとダメですね。 try dictionary["unavailable"] ?? { throw Error.unavailable }() みたいに、期待される型が Any だとエラーにならない。extension Swift.Error { func `throw`<T>() throws -> T { throw self } } extension Optional { func `else`<T: Swift.Error>(_ error: @autoclosure () -> T) throws -> Optional { guard case .some = self else { throw error() } return self } func unwrap<T: Swift.Error>(or error: @autoclosure () -> T) throws -> Wrapped { guard case let .some(wrapped) = self else { throw error() } return wrapped } enum Error: Swift.Error { case isNone(String) } func `else`(_ message: @autoclosure () -> String) throws -> Optional { guard case .some = self else { throw Error.isNone(message()) } return self } func unwrap(or message: @autoclosure () -> String) throws -> Wrapped { guard case let .some(wrapped) = self else { throw Error.isNone(message()) } return wrapped } } enum Error: Swift.Error { case unavailable, notInt } let dictionary: [AnyHashable: Any] = ["available": 1] do { let a = try (dictionary["available"] ?? Error.unavailable.throw()) as? Int ?? Error.notInt.throw() let b = try dictionary["available"].unwrap(or: Error.unavailable) as? Int ?? Error.notInt.throw() let c = try dictionary["available"].map({ try ($0 as? Int).unwrap(or: Error.notInt) }).unwrap(or: Error.unavailable) let d = try dictionary["available"].map({ try $0 as? Int ?? Error.notInt.throw() }) ?? Error.unavailable.throw() let e = try dictionary["available"].else(Error.unavailable).map({ $0 as? Int }).unwrap(or: Error.notInt) let f = try dictionary["available"].else("\"available\" does not exists").map({ $0 as? Int}).unwrap(or: "Fail converting to Int") } catch { print(error) }
associatedtype に where を付けられるようになって、 Sequence.Iterator.Element が Sequence.Element になるのはうれしいんだけど、 https://github.com/airspeedswift/swift/blob/8869509174859ca30eeca37001463b3b46e9f7fc/stdlib/public/core/Sequence.swift#L330-L331
associatedtype Element associatedtype Iterator : IteratorProtocol where Iterator.Element == Element こう宣言しなければいけないのは直感的ではないなー。 associatedtype Iterator : IteratorProtocol typealias Element = Iterator.Element で実現できなかった理由はなんなんだろう。Sequence はあくまで Iterator を生成するものなんだから、やっぱ Iterator 起点なのが直感的な気が。 associatedtype Iterator : IteratorProtocol typealias Element = Iterator.Element (edited)associatedtype Iterator : IteratorProtocol associatedtype Element where Element == Iterator.Element もできるのかな? (edited)associatedtype って変じゃないですか?typealias Element = Iterator.Element って既存用法と何か違うっけ?typealias が protocol に復活したときに typealias Element = Iterator.Element いけるじゃん!みたいなので騒いでいたのは事実で https://github.com/apple/swift/pull/1610associatedtype を縛る方は typealias のままだったのか。書くことないから忘れてた。 https://twitter.com/chriseidhof/status/700305519328755712associatedtype Foo = Bar の方が良くないのかな?何かダメな理由あるっけ?associatedtype Foo=Bar は束縛じゃなくてデフォルト実装なんですよassociatedtype のデフォルト実装ってどんなときに使うんですか?associatedtype って大体↓みたいな感じで暗黙的に解決されちゃって明示的に指定することがないんで、デフォルト実装がありがたいイメージがありませんでした。 protocol Foo { associatedtype Bar func bar() -> Bar } struct Baz: Foo { func bar() -> Int { return 42 } } (edited)protocol Foo { associatedtype Bar = Void func bar() -> Bar } extension Foo where Bar == Void { func bar() -> Bar {} } struct Baz: Foo { // 書かなくてもBar==Voidが推論される } Sequence は Element を持ってない気がします。 Sequence は IteratorFactory にすぎない気が。Iterable<E> は E を指定して Iterator<E> を返すけど、 Swift の Sequence は Iterator の種類まで決定するという意味で違いがありそうな。struct AlwaysOneIterator : IteratorProtocol { func next() -> Int? { return 1 } } struct AlwaysOneSequence : Sequence { func makeIterator() -> AlwaysOneIterator { return AlwaysOneIterator() } } (edited)associatedtype Element が解決できないみたい。associatedtype Element associatedtype Iterator : IteratorProtocol where Iterator.Element == Element // ↑これだとElementをIteratorから推論できない associatedtype Iterator : IteratorProtocol associatedtype Element = Iterator.Element where Element == Iterator.Element // ↑この書き方ができるなら、ElementはIteratorから推論可能。protocol MySequence { //associatedtype Iterator : IteratorProtocol //associatedtype Element where Element == Iterator.Element associatedtype Element associatedtype Iterator: IteratorProtocol where Iterator.Element == Element func makeIterator() -> Iterator } struct AlwaysOneIterator : IteratorProtocol { func next() -> Int? { return 1 } } struct AlwaysOneSequence : MySequence { func makeIterator() -> AlwaysOneIterator { return AlwaysOneIterator() } }
struct AlwaysOneSequence : MySequence を struct AlwaysOneSequence : Sequence に変えると通るようになる。Result と Promsie で、 throws と async があれば <- を try と await で代用できるから、それで大体 OK ってことですか?Opservable もあるかと思いましたが、あれは色んなオペレータ組み合わせて使うし flatMap だけできてもって感じですか?IO モナドとかもいらないし、 Result, Promise あたりがやっぱメインですよね。Promise で済むケースが多そう。
Any<Sequence where>なんちゃらも、この問題を解決出来る…わけではないですよね、恐らくパフォーマンスに影響が出るSelf はあるのに Higher kinded type はないのと、 associatedtype があるとプロトコル型変数作れないのに associatedtype がなければ作れるのは何か中途半端感を感じます。rec って言語機能があるとかないとか、そんな話を資料で読んだ// let + クロージャー (と小道具)で再帰 let fib3 = rec { (fib: (Int) -> Int, x: Int) -> Int in switch (x) { case 0: return 0 case 1: return 1 default: return fib(x - 2) + fib(x - 1) } }swift-3.1.1-RELEASE 何が変わったのか$ swift -version Apple Swift version 3.1 (swiftlang-802.0.53 clang-802.0.42) Target: x86_64-apple-macosx10.9 表記だけの問題?#if swift(>=3.1.1) print("3.1.1") #endif これが true にならないのとか、ほんとにイケてない。guard した場合って else ブロックに何書けばいいんでしょうか? fatalError とかでなく正常終了したい場合。 return はできないようです。 "swift top level guard exit" とかで軽くググってみたんですがよくわからず・・・。exit(1) abort() fatalError() らへんが使えると思うけど違いは分からないexit(0) ?MAIN: do { // ... guard ... else { break MAIN } // ... }exit 呼べばいい気がしてきました。 exit ってちゃんと Never になってるんですね。func main() { } main() ってやってますfunc に突っ込んじゃうのが楽ですよね。__attribute(noreturn)__ だったっけ。 (edited)func main() { } main() ↑これは main() のコールが C とかより冗長で負けた感が・・・。 (edited)exit(0) が素直だった。 (edited)Never になってるの素晴らしい。exit(EXIT_SUCCESS) も呼べると思います。EXIT_SUCCESS@escaping 書けなくなりますよね。どういう扱いなんだろう。 func hoge(_ arg: (() -> ())?) {...} // ←みたいなことをした時に、argがエスケープされるとしてもそれを明記できない。@escaping 扱いです。Foo<() -> ()> と同じですしね。? の記号は便利だけど、こういう混乱を招きやすい・・・。func hoge(_ arg: (() -> ())?=nil) {...} func hoge(_ arg: (() -> ())={ _ in }) {...} 後者のほうが強いのかもしれない (edited)let strings = ["a:2", "b:3", "c:5"] let dictionary = strings.reduce(into: [:]) { (r: inout [String: Int], e) in e.components(separatedBy: ":") => { r[$0[0]] = Int($0[1])! } } // ["a": 2, "b": 3, "c": 5] (edited)=> は前話してた Kotlin の let 代わり。e.components(separatedBy: ":") => { r[$0[0]] = Int($0[1])! } これの型はどこで決まるの?=> like let in Kotlin for Swiftinfix operator => public func =><T, U>(lhs: T, rhs: (T) throws -> U) rethrows -> U { return try rhs(lhs) } extension Sequence { func reduce<A>(into initial: A, _ combine: (inout A, Iterator.Element) -> ()) -> A { var result = initial for element in self { combine(&result, element) } return result } } let strings = ["a:2", "b:3", "c:5"] let dictionary = strings.reduce(into: [:]) { (r: inout [Int: String], e) in e.components(separatedBy: ":") => { r[$0[0]] = Int($0[1])! } }
error: cannot subscript a value of incorrect or ambiguous type e.components(separatedBy: ":") => { r[$0[0]] = Int($0[1])! } ^~ 型推測しきれないぽい。 (edited)into: ラベルが必要です (edited)into: 足してもエラーは変わらず。let dictionary = strings.reduce(into: [:]) { (r: inout [String: Int], e) in e.components(separatedBy: ":") => { r[$0[0]] = Int($0[1])! } } で通りました。[Int: String] じゃなくて [String: Int] でしたね。42... とかもだ。 https://github.com/apple/swift-evolution/blob/master/proposals/0172-one-sided-ranges.mdlet ary1 = [1,2,3] let ary2 = ary1.reduce(into: []) { $0.append($1 + 12) } 非常によい。let dictionary = strings.reduce(into: [:]) { r, e in e.components(separatedBy: ":") => { r[$0[0]] = Int($0[1])! } } これも通った dictionary: [AnyHashable: Int] になっちゃうのか。let dictionary = strings.reduce(into: [:]) { r, e in e.components(separatedBy: ":") => { r[$0[0]] = Int($0[1])! } } だと [String: Int] で let dictionary = strings.reduce(into: [:]) { r, e in print(e) e.components(separatedBy: ":") => { r[$0[0]] = Int($0[1])! } } だと [AnyHashable: Int] single expression か否かで変わってくるみたいです。// If all properties are Codable, protocol implementation is automatically generated by the compiler: これ微妙な気が。Codable だった型にプロパティ足したときに気づかずに Codable でなくなってしまう危険があるのでは?Codable をつけていれば、プロパティを足した瞬間に気付ける。 (edited)A の Foo が元々 Codable だったのを、まったく関係ない第三者が使っていて、ある日 Foo が突然 Codable でなくなるとかあり得る。A の作者は Foo を Codable にするつもりはなかった、とか。 : Codable 宣言してなかったら Codable にならないんじゃないですか?implementation が生成されるだけで : Codable は必須ってことか。class Pathname { init<P: ToStrProtocol>(path: P) { ... } }Hashable は許せるってこと?implements Foo とか書きたくないと。@objc のデフォルト挙動を無くして 明示の方向に進んでるけど enum: Hashable を無くす議論はまだ無いですね。影響でかすぎるか。Hashable の場合も自動的に、なのかと思った。 enum がありの enum に変化するのは、ぜんぜん違うものになってる感があるし仕方ない気も。 (edited)enum で書けるってのが変かも?simple enum みたいな特殊キーワードとかもありかもenum じゃない気がするんですよね。enum じゃなくて union とかでもよかったのかも?enum とかけ離れてない?Encoder でなく T: Encoder であるべきでは? public protocol Encodable { /// Encodes `self` into the given encoder. /// /// If `self` fails to encode anything, `encoder` will encode an empty keyed container in its place. /// /// - parameter encoder: The encoder to write data to. /// - throws: An error if any values are invalid for `encoder`'s format. func encode(to encoder: Encoder) throws }public protocol Encodable { func encode<T: Encoder>(to encoder: T) throws }Encoder にはジェネリックメソッドありますね。じゃあ想定されていないのか。Serializable とは違って、シリアライズするための抽象的な仕組みを提供するだけなのか。素晴らしい。JSONSerialization で書き出すのね。 JSONEncoder は標準ライブラリじゃなくて Foundation ですよね? (edited)JSONEncoder を JSONSerialization で実装するのおもしろいですね。JSONSerialization だった。 https://github.com/apple/swift/pull/9005/files#diff-97ae7c2e808a30701d6e28271b8b6073R818CodingKey型作って init(from decoder: Decoder) throws 実装しないとだめっぽいですね。
Mirror 使いたいケース大分減りそうですね。let a: Int? = 42 let b: Any = a let c: Int? = b as! Int? はだめなのに enum Box<T> { case value(T) } let x: Box<Int> = .value(42) let y: Any = x let z: Box<Int> = y as! Box<Int> はできるんですか?(x as? Foo)! 扱いとか? (edited)class Base : Decodable { } class Concrete : Base { } struct Foo : Decodable { let obj: Base public init(from decoder: Decoder) throws { self.obj = /* ???? */ } } どうやってデコードするのだろう。 (edited)obj のタイプ情報を一緒にエンコードしておくって事ですよね?as! について分岐がある Expr *visitForcedCheckedCastExpr(ForcedCheckedCastExpr *expr) {
https://github.com/apple/swift/blob/3d178be169dd42b85f505ee1502232610535e4a3/lib/Sema/CSApply.cpp#L3491struct Foo<B: Base> : Decodable { let obj: B public init(from decoder: Decoder) throws { self.obj = /* ???? */ } } こうするんじゃないかしら (edited)Foo<Base> だとしても Concrete のインスタンスは持てるから、解決できない気がします。Base を open には出来ないってことですよね。class Base : Codable { let color: Color } class Concrete : Base { let name: String } みたいなのがあったときに { name: "FOOBAR" super: { color: "#abc109" } } みたいにエンコードされるように読めて、container.decode(Concrete.self, forKey: .obj) じゃないとデコードできないのはあきらか。public protocol Encodable { /// Encodes `self` into the given encoder. /// /// If `self` fails to encode anything, `encoder` will encode an empty keyed container in its place. /// /// - parameter encoder: The encoder to write data to. /// - throws: An error if any values are invalid for `encoder`'s format. func encode(to encoder: Encoder) throws } この生え方だと、自身の宣言がBase型かConcrete型かの区別つかない気がする (edited)public protocol Encodable { /// Encodes `self` into the given encoder. /// /// If `self` fails to encode anything, `encoder` will encode an empty keyed container in its place. /// /// - parameter encoder: The encoder to write data to. /// - throws: An error if any values are invalid for `encoder`'s format. staitc func encode(to encoder: Encoder, instance: Self) throws // <- staticなら宣言されてる型から取れる } これなら整合性が取れるかな?Base.encode: (Base) -> (Encoder) throws -> () を使っていて問題なく動くのだろうかstruct Foo : Decodable { let obj: Base public func encode(to encoder: Encoder) throws { let objType: ObjType switch self.obj { case is Concrete: objType = .concrete //... default: objType = .base } container.encode(objType, forKey: .objType) container.encode(obj, forKey: .obj) } public init(from decoder: Decoder) throws { objType = container.decode(ObjType.self, forKey: .objType) let ObjT : Base.Type switch { case .concrete: ObjT = Concrete.self // ... case .base: ObjT = Base.self } self.obj = container.decode(ObjT, forKey: .obj) } } (edited)@objc なら NSClassFromString NSStringFromClass でなんとか.struct Foo<B: Base> : Decodable { let obj: B public func encode(to encoder: Encoder) throws { B.encode(obj)(encoder) } public init(from decoder: Decoder) throws { self.obj = B(from: Decoder) } } これなら、宣言の外の情報は破棄されますが、Bはopenにできそう。class Foo { func foo() { print("Foo") } } class Bar : Foo { override func foo() { print("Bar") } } Foo.foo(Bar())() // -> "Bar" なんで、 なかなか厳しいです。let obj: Foo = Bar() Foo.foo(obj)() これでもいっしょ。class Foo { class func encode(obj: Foo) { print("Foo: \(obj)") } } class Bar: Foo { override class func encode(obj: Foo) { print("Bar: \(obj)") } } Foo.encode(obj: Bar()) // Foo: __lldb_expr_.BarBase が Codable でなければ、型が失われるのは必然に思える。protocol Encodable { static func encode(obj: Self) } class Foo: Encodable { class func encode(obj: Foo) { print("Foo: \(obj)") } } class Bar: Foo { class func encode(obj: Bar) { print("Bar: \(obj)") } } Foo.encode(obj: Bar()) // Foo: Bar.encode(obj: Bar()) // Bar: func encode<E: Encodable>(type: E.Type, obj: E) { E.encode(obj: obj) } encode(type: Foo.self, obj: Bar()) // Foo: encode(type: Bar.self, obj: Bar()) // Foo: いけるかと思ったけどダメだったBase: Codable か。DerivedConformanceCodable.cpp とかあるから、コンパイラの自動生成が頑張ってくれると期待。 https://github.com/apple/swift/pull/9004/files#diff-9ceab8e46e5cb79b6cf990fe2b464e21extension Sequence { fileprivate func grouped<U: Hashable>(by transform: (Iterator.Element) -> U) -> [U: [Iterator.Element]] { return reduce([:]) { dictionary, element in var dictionary = dictionary let key = transform(element) dictionary[key] = (dictionary[key] ?? []) + [element] return dictionary } } } で console.log error: redundant conformance constraint 'U': 'Hashable' fileprivate func grouped<U: Hashable>(by transform: (Iterator.Element) -> U) -> [U: [Iterator.Element]] { ^ note: conformance constraint 'U': 'Hashable' inferred from type here fileprivate func grouped<U: Hashable>(by transform: (Iterator.Element) -> U) -> [U: [Iterator.Element]] { ^ なんてエラーが出るようになったのね。[U: [Iterator.Element]] だから U: Hashable は要らない。public protocol Encodable { func encode(to encoder: Encoder) throws } が↓でない理由ってよくわからないままですっけ? public protocol Encodable { func encode<T: Encoder>(to encoder: T) throws } swift-evolutionとかで聞いてみたらいいのかな?decode だけど、同じ話として) (edited)(SomeProtocol) -> SomeProtocol みたいな型の変数に入れるためには抽象のままじゃないといけないけど、関数コールしてる箇所はジェネリック扱いすればよさそうだし、何かあるかな・・・。Foo: SomeProtocol があったとして、 func bar<T: SomeProtocol>(_ x: T) -> T { return x } let foo: SomeProtocol = Foo() let foo2: SomeProtocol = bar(foo) のように bar がジェネリック扱いでも問題ないですよね?func foo(x: Foo<SomeProtocol>) -> Foo<SomeProtocol> { ... } (edited)func foo<T: SomeProtocol>(x: Foo<T>) -> Foo<T> { ... } にしたら、 Foo が T について covariant じゃないから戻り値の型に互換性がなくなっちゃう。func foo(x: Int) -> SomeProtocol { switch x { case 0: return Foo() case 1: return Bar() case _: return Baz() } }AnySequence 的な型を使えばってことですか?public protocol Encodable { func encode(to encoder: Encoder) throws }Any よくない気がする・・・。Any にも気持ち悪さを感じる。Any も禁止とかしたら、さすがに無理かなぁ。どうしても Any にせざるを得ないケースもあるしなぁ。Optional と Any の問題は値型関係ないか・・・。struct Foo { var bar: BarProtocol } を struct Foo<Bar: BarProtocol> { var bar: Bar } にしてしまうと、 extension Int: BarProtocol {} extension String: BarProtocol {} var a = Foo(bar: 123) let b = Foo(bar: "xyz") a = b の最後の行ができなくなってしまう。inout は引数でもあり戻り値でもあるので、戻り値の場合と同じかと思います。func encode(to encoder: Encoder) throws は自動生成されるというのがポイントのような気がします。 (edited)// @derived func encode(to encoder: Encoder) throws {@derived というキーワードを apple/swift リポジトリで探すと、 enum の Equatable, Hashable, RawRepresentable 、 Errorの _nsErrorDomain などで使われてて、それらは全部ジェネリックでは無い。func encode(to encoder: Encoder) throws このメソッドって、実際には基本的に外部ライブラリであるエンコーダーから呼ばれるわけで、specialize しようがないと思うんですけど違います?encode<T: Encoder>( でだめな理由は無いけど、そうする意味もないのでは?ということです。 (edited)encodeが、自身が持つフィールドのencodeを呼ぶことは無いのかなlet farm = Farm(name: "Old MacDonald's Farm", location: Location(latitude: 51.621648, longitude: 0.269273), animals: [.chicken, .dog, .cow, .turkey, .dog, .chicken, .cow, .turkey, .dog]) let payload: Data = try JSONEncoder().encode(farm) 使い方がこうだから、JSONEncoderが内部でfarmのencodeメソッドを呼ぶのか。@_specialize とかもありませんでしたっけ?
@_specialize はライブラリ側につけるのか。func encode をコンパイルするときに encoder が JSONEncoder であるか否かはわからない。
(edited)@_specialize(where T == JSONEncoder) func encode<T : Encoder>(to encoder: T) throws { ... } ってしとけばいいかもしれないけど、使っちゃ駄目encode をコンパイルするときは specialize されてない抽象の状態でコンパイルし、呼び出し側をコンパイルするときに encode の specialize 版を生成することはできないですか?@_specialize は存在しないのでは (edited)encode のバイナリにリビルドするのに十分な付加情報を埋め込んでおけば(バイナリ化されたASTとか)リンク時に specialize することはできるはずです。JSONEncoder なので func encode をコンパイルする前に既にライブラリとしてコンパイルされているという認識なんですけど、それは良いですか? (edited)MyType.encode をコンパイルするときに、 specialize 出来たとして、 呼び出し側がその specialize された メソッドをどうやって呼ぶのか想像がつかないです。 (edited)<Foo: Protocol>(foo: Foo)においてFooは具体的な型パラだが、fooはProtocol型変数と変わらない状態?func foo<T: Encoder>(to encoder: T) の方が良い。public struct Foo<T> { private let array: [T] public init(array: [T]) { self.array = array } public func map<U>(_ transform: (T) throws -> U) rethrows -> Foo<U> { return Foo<U>(array: try array.map(transform)) } public var count: Int { return array.count } }public protocol BAR { func foo() } public func XXXXX<T : BAR>(arg: T) { arg.foo() } public func ZZZZZ(arg: BAR) { arg.foo() }
-O -emit-ir 結果 https://gist.github.com/rintaro/8794ecd01e78e6b001fce192b07f2d7d#file-test-silprotocol Hogeable { func hoge() -> Int } func callHogeableHoge(hogeable: Hogeable) -> Int { return hogeable.hoge() } ↑こういうのがあるとき、LLVMIRだと、↓こういう引数になってる。 (x, xt, wt) の3タプルになっている。 %P4main8Hogeable_ = type { [24 x i8], %swift.type*, i8** } define hidden i64 @_TF4main16callHogeableHogeFPS_8Hogeable_Si(%P4main8Hogeable_* noalias nocapture dereferenceable(40)) #0 { ... }open_existential_addr が入っているか否か。 https://github.com/apple/swift/blob/master/docs/SIL.rst#open-existential-addrprotocol Fugable { typealias Element func fug() -> Element } func callIntFugableFuga<F: Fugable where F.Element == Int>(fugable: F) -> Int { return fugable.fuga() } ↑一方こういうのがあるとき、LLVM IR だと↓こうなる define hidden i64 @_TF4main18callIntFugableFugauRq_S_7Fugablezqq_S0_7ElementSi_Fq_Si(%swift.opaque* noalias nocapture, %swift.type* %F, i8** %F.Fugable) #1 { Existentialがないけど、結局、引数として x, wt, xt が並んでる。 (edited)Encoder のコードも Codable ごとに specialize されうるのかな。Foundation Swift モジュールも特別扱いの対象なら可能性あるかもしれないですね。-sil-serialize-all っていうオプション付きでモジュールがコンパイルされているか否かによるみたいです。この場合、実装含めた全てのSILが .swiftmodule にシリアライズされるので、caller側はcalleeのSILレベルでの実装を見通して最適化が出来ようになると。swift build -Xswiftc -Xfrontend -Xswiftc -sil-serialize-all でビルドしてみたら LLVM ERROR: Invalid abbrev number <unknown>:0: error: merge-module command failed with exit code 1 (use -v to see invocation)
encode がジェネリックの方がいい強力な理由になるんですけどね〜。@_specialize を使うべきでないという理由はなんですか?encode については質問済みなので回答来たらまた。 https://github.com/apple/swift/pull/9004#pullrequestreview-35266665@_specialize について、 _ で始まるものは本当に使わないほうがいいです。意図的にやっているのかっていうくらい頻繁に仕様が変わります。@_specialize は実際 Swift3 と 現状の master でインターフェイス変わってます Swift3 @_specialize(Int, String) func foo<T, U>(x:T) -> U master @_specialize(where T == Int, U == String) func foo<T, U>(x:T) -> U@_specialize のインターフェースも変わってるんですね・・・@_specialize は代替手段がないから辛いですね。_Foo は使わないですが、 @_specialize は特殊なのかと思ってました。swift build -Xswiftc -Xfrontend -Xswiftc -sil-serialize-all でビルドしてみたら .swiftmodule は大きくなるけど、パッケージのは大きくならない。public struct Location : Codable { private enum CodingKeys : CodingKey { case latitude case longitude } public func encode(to encoder: Encoder) throws { // Generic keyed encoder gives type-safe key access: cannot encode with keys of the wrong type. let container = encoder.container(keyedBy: CodingKeys.self) // The encoder is generic on the key -- free key autocompletion here. try container.encode(latitude, forKey: .latitude) try container.encode(longitude, forKey: .longitude) } }Encoder の container メソッドが、 K.Type を引数で受けていて、 container の型パラに引き継がれる。 enum CodingKeysはstruct Locationのinner typeで、Locationのために自動定義されたやつだから、プロパティ名とキーが静的に結びつく{ "a": 3, "b": 2, "super": { "c": 1 } }master で -enforce-exclusivity=checked つけると試せるです。~~(lhs: Int, rhs: Int)について 1~~-2とかやるとコンパイル通らないので ~~-演算子を定義するという糞ハックencode(to:) の理由を答えてくれてる。なるほど。 https://github.com/apple/swift/pull/9004#discussion_r114044478protocol P { func foo() } struct S : P { func foo() { print("S.foo") } } func foo<T : P>(p: T) { p.foo() } let obj: P = S() foo(p: obj)Any に関しては <T : Any> は何も書かないのと一緒扱いなのかな? Any = protocol<> でしたし、今もパーサー時点で Any を 空のコンポジションとして AST に入れている。 AnyObject も protocol P : AnyObject が protocol P : class と同義であるみたいに、 class レイアウトであること「だけ」を強制するものとして、コンパイラでの特別扱いがあるので、その絡みだと思いますが、よく分かんないですね。 (edited)KeyedEncodingContainer をちゃんと読めてなくて、 public protocol KeyedEncodingContainerProtocol { associatedtype SuperEncoder: Encoder mutating func superEncoder() -> SuperEncoder ... } にできないのかがよくわかってないです。 API 全体で existential を排除できないものなのか・・・。ちょっと時間のあるときにちゃんと読んで理解して考えます。
extension Array { public mutating func update(_ operation: (inout Element) throws -> ()) rethrows { for i in startIndex..<endIndex { try operation(&self[i]) } } }
struct Foo { var value: Int } var array = [Foo(value: 2), Foo(value: 3), Foo(value: 5)] array.update { $0.value *= 2 } print(array) // [Foo(value: 4), Foo(value: 6), Foo(value: 10)] (edited)filter と filtered みたいな話になると思うんですよね。ただ、 update は map に相当するんですが、 map は戻り値の要素の型を変更できるのに対して update はできないんで、 map / mapped は違和感がありますね。 update / updated の方がいいけど、 map → updated は弊害の方が大きそうだから、 update と map かなぁと。We've definitely considered including a Result type, but our sense was that in an ideal world almost no code would be using it. It's hard to imagine an ordinary API that ought to be returning a Result rather than throwing, and once you've defined that away, the major remaining use case is just to shift computation around, like with a completion handler. That explicit computation-shifting pattern is something we're hoping to largely define away with something like C#'s async/await, which would leave Result as mostly just an implementation detail of such APIs. We didn't want to spend a great deal of time designing a type that would end up being so marginal, especially if the changing role would lead us into different directions on the design itself. We also didn't want to design a type that would become an obstacle to potential future language changes like, say, typed throws. The downside, of course, is that as long as we lack that async/await design, computation-shifting isn't real great.async / await 導入されてほしい。 https://gist.github.com/koher/df007741788cb197d65b6babe2acf480async / await って GCD の上に構築されるイメージ?throws と Result<T> は相互変換できるので、同じようにして async と Promise<T> を変換できるというものです。throws : async
try : await
Result : Promise がすべて同じ関係になるだろうと。rethrows と同じように reasync という概念が必要になるんじゃないかと思ってます。let r = await [2, 3, 5].map { (x: Int) async -> Int in ... }throws なクロージャが渡された map は try しなきゃいけないように、 async なクロージャが渡された map は↑のように await しなきゃいけないようにしたいと。 (edited)reasync がないと、 map に async なクロージャを渡せなくなってしまいます。catch とはエラーハンドリングの意味ですか?それとも、非同期処理において、エラー処理における catch に対応するものという意味ですか?do - defer (このキーワードが適切かは微妙です)で await 前のスレッドに戻ってノンブロッキングな処理を表すのがいいんじゃないかと思ってます。// `do` / `defer` for `await` outside `async` functions func onClick() { do { let selectedIndex = await actionSheet([...]) ... } defer // Non-blocking }repeat - while に while ブロックがないように、 do - defer には defer ブロックがない想定です。await だと、変数間の依存関係も考慮されているみたいだけど、それも含む? func foo(url: URL) async throws -> Foo { let data = await try download(url) let modified = await asyncConvert(data) return Foo(data: modified) }async Task<string> AsyncMethod2(Uri uri) { using (var client = new HttpClient()) // <- 本当はHttpClientをusingで使っちゃダメ { var response = await client.GetAsync(uri); // <- 「GETせよ」のタスクを開始し、その完了を待機する var text = await response.Content.ReadAsStringAsync(); // 「レスポンスからその本文をstringとして読み出す」タスクを開始し、その完了を待機する return text; // 読み出したtextを返す } } // という「一つのタスク(Task<string>)」を表す。 (edited)response が返ってくるのを待ってから response.Content.ReadAsStringAsync() を呼んでる?try や await は flatMap に対応するのでPromise の then は flatMap と等価なので)await を 2 回書くということは then をチェーンして繋いでるのと同じです。async / await で、 Promise に対する( Haskell の) do のように振る舞えるはずです。async / await と throws / try を組み合わせれば、純粋な非同期処理と純粋なエラー処理に分離できるはずです。async throws -> T な関数は、 Promise<Result<T>> を返すようなものですね。Promise ベースで考えてたので、 await 以降がどこのスレッドで実行されるかは async な関数を実装する側次第と考えてましたが、 Promise を return するのと同じ自由度でそれを書くにはどうするのかよく考えてませんでしたね。catch じゃなくて try で、じゃないですか? catch の方は Error ですよね?
async になって、どれを使うかによって実現されることになると思います。
func pureInt() -> Int { do { return try throwAble() } catch { //Error処理 return someValue } }func makeAsync<T>(_: ((T) -> ()) -> ()) async -> Tfunc foo() async -> Int { return await makeAsync { emit in DispatchQueue.main.asyncAfter(deadline: .now + 5.0) { emit(42) } } } (edited)func makeAsync<T>(_: ((T) -> ()) throws -> ()) async rethrows -> Tdo - defer 相当のものは同期化というのがあり得る気がしてるんですが、現実的にはノンブロッキング化する方が必要だろうなと。func pureInt() -> Int { do { return await asyncInt() } wait }catch によく対応してるような気はします。func doAsync(_: () async -> ()) みたいな。 (edited)func onClick() { do { let selectedIndex = await actionSheet([...]) ... } }throws / try と同様に) onClick が async でないとコンパイルエラーがいいと思うんですよね。async がついたメソッドは await 付きで呼ばなければならず、 await を呼ぶメソッドは do {} で同期化しない限り async としなければいけない。throws と try と同じ感じか。throws -> T は -> Result<T> と等価で、 try は flatMap と等価だから、 async -> T と -> Promise<T> にも同じ関係が成り立つはずなんですよね。 Result も Promise も同じくモナドなので。await で非同期実行が始まるのは、スコープ内で await 以降に await と無関係なコードが現れた時、って感じかな。// a(), b() は () async -> Int let a = await foo.a() let b = await bar.b() let sum = a + b ... は // a(), b() は () -> Promise<Int> foo.a().flatMap { a in bar.b().flatmap { b in let sum = a + b ... } } のような感じですね。 (edited)a に代入するところから非同期に行われます。let a = foo.a() let b = bar.b() let aa = await a let bb = await b let sum = aa + bb はあるんですかねsum を返しているわけでなく、後続処理があるイメージです。throws / try の構文かと。Promise使えって話ですが。a と b は独立だから、並列して走ってもいいんだけど let a = await foo.a() let b = await bar.b() let sum = a + b (edited)a が終わってから b が走ってほしい場合とかもあるからPromise モナドは「今は値はない、けどいずれ手に入る」を表して非同期的にイミュータブルに振る舞うだけだから、a() と b() が並列に実行されようが順番に実行されようが結果の変わらない世界の話なんだよなぁ。let bar = await foo.bar() let baz = await bar.baz() だと順番に走るんですよね?Promise.all的な関数を用意してもらえばそれで良い気がする。// a(), b() は () async -> Int let a = await foo.a() let b = await bar.b() let sum = a + b ... は // a(), b() は () -> Promise<Int> let a = foo.a() let b = bar.b() a.flatMap { a in b.flatMap { b in let sum = a + b ... } } 相当になりますね。awaitって書いてあるところで待ってないという気持ち悪さが残るだけですね。let bar = await foo.bar() let baz = await bar.baz() ... の場合は foo.bar().flatMap { bar in bar.baz().flatMap { baz in ... } }Array<Optional<T>> だけに extension 書くとかってかけます?extension Array where Element == Optional まで書いて、型パラメータが書けなくて固まった・・・error: reference to generic type 'Optional' requires arguments in <...> extension Array where Element == Optional { ^ <Any> (edited)<Any>はともかく<Wrapped>はできるんですかね?typealias ArrayO<T> = Array<Optional<T>> extension ArrayO { func foo() -> Bool { return reduce(true) { $0 && ($1 != nil) } } } ↑は書けたけど、普通に Array の extension になってる・・・Optional の Wrapped は型指定出来無さそう 1> extension Array where Element == Optional<Any> { 2. func foo() -> Bool { 3. return reduce(true) { 4. $0 && ($1 != nil) 5. } 6. } 7. } 8> let a: [Int?] = [2, 3, 5] 9. print(a.foo()) error: repl.swift:9:7: error: '[Int?]' is not convertible to 'Array<Optional<Any>>' print(a.foo()) ^Optional<T>にextension生やしてそれを呼ぶとかでは? 処理によりますがreduceか。reduceはだめそうですねArray ですらなくて、 Promise<Optional<T>> についてのみの extension を書きたいのです・・・where T == Foo が書けるようになって、演算子を一掃できると思ったんだけど・・・。protocol HasWrappedType { associatedtype WrappedType } extension Optional: HasWrappedType { typealias WrappedType = Wrapped } extension Array where Element: HasWrappedType { func foo() -> Bool { return reduce(true) { $0 && ($1 != nil) } } } let a: [Int?] = [2, 3, 5] print(a.foo()) let b: [Int] = [2, 3, 5] //print(b.foo()) // error: type 'Int' does not conform to protocol 'HasWrappedType' (edited)protocol を外部に露出しないといけないですが、仕方ないですね・・・String が BidirectionalCollection に変わるので joined() の型も変わってしまう。 var str = [ "Hello, playground" ].joined() type(of: str) // 3.1: String.Type, 4.0: FlattenBidirectionalCollection<Array<String>>.TypeArray にするのか lazy な型にするのかって難しいですよねぇ・・・extension Array where Element == String { public func joined(separator: String = default) -> String } より extension Array where Element : BidirectionalCollection { public func joined() -> FlattenBidirectionalCollection<Array<Element>> } が優先されてる。warning: 'flatMap' is deprecated: This call uses implicit promotion to optional. Please use map instead. とか言われてビビる。let a = [1,2,3].flatMap { $0 + 1 } こういうやつ。closure の返値が いったん Optional になるから、効率が + で連結するとビルドが遅くなる問題って、まだ直ってないですよね。allTests の定義で throws ではないメソッドを返す時にエラーが出る様になった。 extension ResolverTests { static var allTests: [(String, (ResolverTests) -> () throws -> Void)] { return [ ("testBasic", testBasic), ("testDefault", testDefault) ] // .map { entry in (entry.0, { entry.1($0) }) } // workaround } }
… error: cannot convert value of type '(ResolverTests) -> () -> ()' to expected element type '(ResolverTests) -> () throws -> Void' ("testBasic", testBasic), ^~~~~~~~~ (edited)Encoder を作ろうとしての感想です。 SE-0167で実装された JSONEncoder と PlistEncoder をそのまま使うぶんには良いのかもしれません。Encoder / Decoder 実装がうまくいかないと意味がないと思うんですよね。 JSON とかだけでなく、汎用的な仕組みとして作られているのがおもしろいところだと思うので。 (edited)Encoder にするにはどうしたら良いのか?を前提にコードを眺めていました。JSONEncoder は JSONSerialization に渡すための NSMutableDictionary を生成すればいいけど、 Yams 用のインプットを Encoder の仕組みで組み立てるのが難しいとかですか?Node っていうのが Yams での値/コンテナなのですが、これを enum と struct のペイロードで作ってしまっているので、逐次シリアライズした Node を KeyedEncodingContainerProtocol とかの内部情報として持てなくなってしまいました。JSONEncoder と PlistEncoder はどちらも内部形式は NSMutableArray と NSMutableDictionary で、入れ物を親のコンテナに入れてから参照してる。Node を逐次シリアライズするのではなく、 _JSONEncoder が NSMutableDictionary を組み立てるのと同じように、コンテナ経由で Node を組み立てて、最後にシリアライズではうまくいきませんか?[AnyHashable: Any] を得るために、PropertyListEncoder とほぼ同じコードを再実装しないといけない感じです。PropertyListEncoder が Data ではなく [AnyHashable: Any] を吐き出す仕組みがあると、幸せになれそう。 (edited)Encodable で表現できるデータ構造って似たようなものだから、 Dictionary 化するヘルパー Encoder みたいなのがあればその後が楽そうな気もしますね。ちょっとまだ自分で実装してないのでイメージがちゃんとできてないかもですが。 (edited)Dictionary を経由することでパフォーマンスを損ねるケースもあるので、 Encoder が提供しているような直接組み立てていくための仕組みは必須ですが。Node を作ればそれなりにいけそうな気もしてきました。async / await の話、 Swift 5 についての議論が始まったら swift-evolution に投稿してみようかと思うんですが、↓みたいな感じでどう思います?わかりづらいところとか変なところとかあれば。 https://gist.github.com/koher/3e04b4f1b8adbbf0379d38c0ad83a3ea ノンブロッキング化する方法についても書いた方が良さそう。async throws な関数をコールして catch だけするとどうなるのかということですか? (edited)catch が非同期化されますね。downloadFooSync がそうなってました。また、 nonblock について書き足し、その中で catch しかしない例を追加しました。async と throws はどの順に書いても async が外側扱いがいいんじゃないかと思っていますが、そのあたりの詳細は ML で議論されればいいのかなと思います。あまり詳細に踏み込むと読むのが大変なのでとりあえず提案を投げるにはこれくらいのボリュームがいいのかなぁと。 (edited)enum MyEnum { case foo(Int) case bar(String) } func someAction(elements: [MyEnum]) { elements.flatMap { $0.foo } // ← [Int]が欲しい } elements.map { guard case let .foo(foo) = $0 else { fatalError() } return foo }computed var foo: Int? でflatMapが妥当ですかねぇ、しょうがないか elements.flatMap { guard case let .foo(foo) = $0 else { [] } return [foo] } (edited)public enum Output { case dataSources([Model]) case loading(Bool) } こういうのを書くとvar foo: Foo? とかをそれぞれ作るしかない気がしますねー。case .foo(return) ?? nil みたいな書き方ができればいいんですが。パターンマッチング部分を抽象化できれば関数にできるんですけどね。x と y を持った Int と Double という定数にそれぞれ 1 と 2 が代入されててInt です)let (x: Int, y: Double): (Int, Int) = (1, 2) let s = Int + Double 1> let (x: Int, y: Double) = (1, 2) 2. let s = Int + Double Int: Int = 1 Double: Int = 2 s: Int = 3 1> let (x: Int, y: Double): (Int, Int) = (1, 2) 2. let s = Int + Double error: repl.swift:1:6: error: tuple pattern element label 'x' must be '_' let (x: Int, y: Double): (Int, Int) = (1, 2) ^let (x:Int,y:Double)←これが型宣言ではないのがポイントっぽいlet (x, y): (Int, Double) = (1, 2) が正しいんでしょうが、ラベル付きタプルを宣言して代入という構文も、何のためにラベルがあるのか意味不明なので、 let (x: Int, y: Double) = (1, 2) とできてもいい気がしますね。let (x:y,z:w) =(1,1)でも通るって事ですよね 1> let (a: b, c: d) = (1, 2) b: Int = 1 d: Int = 2let Int=1 let Double=2 _=(x: Int, y: Double) 実際にはこれと等価typealias Foo=(x: Int, y: Double)と混ざって混乱するlet (foo: x, bar: y) = ... のラベルを書けることじゃないですか?コンパイルエラーでいい気が。let (x,y)=(1,2)これタプルじゃなくて、xとyに1と2を代入、ですねlet (x, y) = (1, 2) // x is equal to 1, and y is equal to 2async / await について Ray さんが添削してくれたんですが、めっちゃ勉強になりますね。これがネイティブの英語力かぁぁ・・・。原文がほとんど残ってないw https://gist.github.com/rayfix/b5429a061a0fe34fa9326fe358dfdbe7/revisionsEncoder & Decoderサポートのコードはこんな感じになりました。 https://github.com/jpsim/Yams/pull/43/commits/68c34b1ec8912688cfb1b0d23049e31ab9daf507 (edited)Mirror とかでシリアライズを作るよりはずっとマシ、ってところかな。reduce について書きました。 http://qiita.com/koher/items/17636e95e18e529e5b9breduce は次のようなシグネチャでした。 ```swift func reduce( initial: T, combine: (T, Element) throws -> T) rethrows -...init(minimumCapacity:) で作るとかした方が良いと思いました。for ループを使った場合との比較なのでキャパシティの話を混ぜるとわかりづらいかなぁと。inoutだと再割り当てが確実に発生しないのはメリットに思えます。reduce へ渡す空の辞書を、生成されるであろう要素数を元に容量確保しておいても、最初のCoW発生時に辞書内の書き込み済み要素数を元に新しい辞書の容量が再計算されている様に見えます。 (edited)inout のおかげで初期値をキャパシティ指定して渡すことの意味があるというのはその通りだと思うので、その点追記しておきます。minimulCapacity の件、追記しました! http://qiita.com/koher/items/17636e95e18e529e5b9b/revisions/1?type=source (edited)struct Cat { var age: Int = 3 var po: Int { mutating get { age = 9 return age } nonmutating set { print(newValue) } } } こんな意味不明な事できたnonmutating 、 Swift が登場してすぐのときに Array の CoW がおかしくて、その関係で調査してたときに一度だけ使ったことある。map は [Element] を返すとか一貫性なくないですか?そして、 map についても Mapped を作ろうとしたら、 higher-kinded type がないといけないという・・・。 https://github.com/apple/swift-evolution/blob/master/proposals/0174-filter-range-replaceable.mdIt could be worthwhile to make a similar change to map, but this is beyond the capabilities of the current generics system because map does not preserve the element type-enforce-exclusivity=checked のやつか。extension View: HasImpl { typealias Impl=Int } ↑これだと、Intしか実装がない。なので、IntかStringを使おうとすると↓ extension View: HasImpl { typealias Impl=Int|String } ↑こういうのが欲しくなる (*) x (X) とか (A) x (X) とか (A/B) x (*) の場合における実装を定義したい? (edited)protocol P { associatedtype AT } struct SP<T> : P { typealias AT = T } extension P where AT == Int { func po() { print("AT == Int") } } extension P where AT == String { func po() { print("AT == String") } } let intsp = SP<Int>() intsp.po() let strsp = SP<String>() strsp.po()protocol P { associatedtype AT } protocol HasStringProtocol {} protocol HasIntProtocol {} extension P where AT: HasStringProtocol { func po() -> String { return "string" } } extension P where AT: HasIntProtocol { func po() -> Int { return 1 } } struct StringAndInt: HasStringProtocol, HasIntProtocol {} struct S: P { typealias AT = StringAndInt } let s = S() let string = s.po() as String // "string" let int = s.po() as Int // 1protocol P { associatedtype T func hoge(t: T) } class MyClass {} extension MyClass: P { typealias T = Int func hoge(t: Int) {} } extension MyClass: P { typealias T = String func hoge(t: String) {} } func foo<MyP: P>(_ arg: MyP) where MyP.P == String {} // <- ここにMyClassを func bar<MyP: P>(_ arg: MyP) where MyP.P == Int {} // <- どっちでも入れれるようにしたいInt|Stringで宣言して多分思い通りのものができそうInt|CountabelRange<Int>みたいなのをやろうとして、 結局ContableRangeをprotocolに従わせつつ関数側で型チェックってのになってしまったので Unitonがあると嬉しいですね。subscript が identifier になるらしい。init みたいにメソッドとして参照できる様になるのかな。 foo.subscript ができるようになるのはうれしいですね。struct もすでにあるんですが。func foo() -> Int { ... } func foo() -> Double { ... } // 今 let f: () -> Int = foo // () -> Int の foo が代入される // Intersection があったら let f: (() -> Int)&(() -> Double) = foo let g = foo // ↑と同じ let h: () -> Int = foo // この場合 h の実体は何? () -> Int の foo ?それとも f や g と同じ? (edited)func foo() throws BarError|BazError -> Foo ができるので複数エラー投げられることになってしまって台無しに・・・。(() -> Int) & (() -> String) って () -> (Int | String) と等価か?(Int|String) -> () と ((Int) -> ())&((String)->()) は同じに見えるけど (Int|String) -> (Int|String) と ((Int) -> Int)&((String) -> String) は違う。(Int|String) -> (Int|String) と ((Int) -> Int)&((String) -> String) これはわかる、引数で入れた型が返り値で出てくるっていう依存性が消えてるから違う() -> Int&String は let f: () -> Int&String = ... let r: Int&String = f() ができるけど、 (() -> Int)&(() -> String) は↓のどっちかしかできない。 let f: (() -> Int)&(() -> String) = ... let r1: Int = f() let r2: String = f()(() -> Int)&(() -> String) を 2 回コールしないとダメでしょ。let f: (() -> Int)&(() -> String) = ... let r: Int&String = f() // 2 回コールされるr が二つのインスタンスの合成というのも変(() -> Int)&(() -> String) この型は () -> Int なんだから、一回呼び出せばIntが返るけど、 それと同時に () -> String なんだから、一回呼び出せば Stringが返るはずで、 それは () -> (Int & String) って事じゃないのかな () -> (Int & String) なら 1回呼び出せばIntが返るとも言えるし 同時に1回呼び出せば Stringが返るとも言える(() -> Int)&(() -> String) はただのオーバーロード。((Int) -> ())&((String) -> ()) だと考えてみたら自明じゃない?foo(42) か foo("xyz") ができるだけ。((Int) -> ())&((String) -> ()) == (Int | String) -> () だと思う((Int) -> Int)&((String) -> String) でもいいけど。& はオーバーロードを表すことを示してるのでは?
(A -> B) & (A -> C) == (A) -> (B & C) と (A -> B) & ( C -> B) == (A | C) -> B の 2つだけが適用できるlet a: Int&String = 42&"xyz"a が Int を要求するところや String を要求するところ 両方にかけてコンパイルできるstruct IntAndString { var i: Int var s: String } (edited).i と .s のメンバアクセスをコンパイラが自動注入すればprotocol Receiver { associatedtype Arguments func foo(_ arguments: Arguments) } protocol Sender { associatedtype Returns func bar() -> Returns } この二つの型を合成して使うことを考える、 Receiver.Argnumentsと、Sender.Returnsが一致していれば合成可能、故に合成関数は次の定義 func combine<R: Reciever, S: Sender>(reciever: R, sender: S) where R.Argnuments==S.ReturnsCat is Animal 則を満たす時に暗黙の調整処理が挿入されるのと同じ話だと思いますsubscript が内部的に単なる identifier としてモデリングされていたおかげで、 TypeCheckerで obj.subscript で参照できてしまい、SILではそんなこと意図されてなかったのでクラッシュしていたのが、この修正により 'Foo' has no member 'subscript' としてエラー出せるようになるっていうだけの話なのです。 https://bugs.swift.org/browse/SR-2575
struct Foo { subscript(i: Int) -> Int { return i } func `subscript`(_ i: Int) -> Int { return i + 1 } }
9> Foo().subscript(42) error: repl.swift:9:1: error: ambiguous use of 'subscript' Foo().subscript(42) ^ repl.swift:2:5: note: found this candidate subscript(i: Int) -> Int { ^ repl.swift:5:10: note: found this candidate func `subscript`(_ i: Int) -> Int { ^
9> Foo().`subscript`(42) error: repl.swift:9:1: error: ambiguous use of 'subscript' Foo().`subscript`(42) ^ repl.swift:2:5: note: found this candidate subscript(i: Int) -> Int { ^ repl.swift:5:10: note: found this candidate func `subscript`(_ i: Int) -> Int { ^
9> Foo()[42] error: repl.swift:9:1: error: ambiguous use of 'subscript' Foo()[42] ^ repl.swift:2:5: note: found this candidate subscript(i: Int) -> Int { ^ repl.swift:5:10: note: found this candidate func `subscript`(_ i: Int) -> Int { ^ (edited)class Foo { func `deinit`() {} } が出来なかったのが出来るようになったりするかもしれないけど、その程度。foo.subscript は今でもできるのかと思ったけど・・・。 1> struct Foo { 2. subscript(i: Int) -> Int { 3. return i 4. } 5. } 6> Foo().subscript(42) Segmentation fault: 11 1> struct Foo { 2. func `subscript`(_ i: Int) -> Int { 3. return i 4. } 5. } 6> Foo().subscript(42) $R0: Int = 42 7> Foo()[42] Segmentation fault: 11 (edited)func subscript と subscript がしっかり区別されるようになり、前者は foo.subscript 後者は foo[...]` でしか参照できなくなります。foo.subscript で subscript が参照できないと、今の Foo.init とかができるのと一貫性がないような気がします。subscript はプロパティであるっていうので現状になっている感じがします。throws もできるようしたらメソッド側に寄せられますが・・・。foo.subscript できるようにするという議論された形跡みつからず func combine<R: Reciever, S: Sender>(reciever: R, sender: S) where R.Argnuments==S.Returns { receiver.foo(sender.bar()) }func combine<R: Reciever, S: Sender>(reciever: R, sender: S) where R.Argnuments==S.Returns { receiver.foo(convertReceiverType(sender.bar())) }enum Either2<A, B> { case a(A), b(B) } class MyReciever: Reciever { typealias Arguments = Either2<String, Int> } // このままだとStringを吐き出すSenderは使えない class MySender: Sender { typealias Returns = String } // Either変換を含めた魔改造type-erasureを作る class Sender2A<R1, R2> { typealias Returns = Either<R1, R2> init<S: Sender>(_ sender: S) where S.Returns == R1 } class Sender2B<R1, R2> { typealias Returns = Either<R1, R2> init<S: Sender>(_ sender: S) where S.Returns == R2 } // 変換オペレーターを差し込む prefix operator ~ prefix func ~<S: Sender, R>(_ sender: S) -> Sender2A<S.Returns, R> { return .init(sender) } prefix func ~<S: Sender, R>(_ sender: S) -> Sender2B<R, S.Returns> { return .init(sender) } combine(MyReciever(), ~MySender()) // OK!connect(IntProvider(), IntOrStringConsumer()) { .lift($0) }~じゃなくて、.converted()でも良い~で解決する癖がついてきた…TWITTER_CONSUMER_SECRET がコミットされてるけど大丈夫ですか? https://github.com/tarunon/Hiyoko/blame/cf0f137321ef26d20a2940dd8d76de598012d207/Hiyoko/AppDelegate.swift#L13swift-DEVELOPMENT-SNAPSHOT-2017-05-09-a パッケージングのCIが完走しそう。 https://ci.swift.org/view/Packages/job/oss-swift-package-osx/3351/console
swift-DEVELOPMENT-SNAPSHOT-2017-05-09-a きた https://swift.org/download/#snapshotsxcodebuildやxcrunは -toolchain オプションがあったり、TOOLCHAINS環境変数を使ったり。xcrun の -sdk は割りとつかいます$ pkgutil --pkgs|grep org.swift org.swift.3020170509a org.swift.31120170421a でインストールしてある swift.org からのスナップショットのIDを探せるので、それを TOOLCHAINS=org.swift.3020170509a swift や xcodebuild -toolchain org.swift.3020170509a … みたいにして使います。 (edited)$ xcrun -toolchain org.swift.3020170509a swift Welcome to Apple Swift version 4.0-dev (LLVM 6a9a7bf93b, Clang 288cf0b5d5, Swift 2e09c17818). Type :help for assistance. 1> (edited) if i % 5 == 0 { result += (result.isEmpty ? "" : " ") + "Buzz" }guard があるせいで else をちゃんとかくってのはありますねぇvar がどうなってるか覚えながら読まないといけないよねsiwtch (/*必要なもの全部ここにドーンwww*/) { case /*なんか条件いっぱい*/: return /*結果*/ /*以下繰り返し*/func fizzBuzz(_ numberOfTurns: Int) { for i in 1...numberOfTurns { var fizzOrBuzz = false if i % 3 == 0 { print("Fizz", terminator: "") fizzOrBuzz = true } if i % 5 == 0 { print((fizzOrBuzz ? " " : "") + "Buzz", terminator: "") fizzOrBuzz = true } if !fizzOrBuzz { print(i, terminator: "") } print() } }result += (result.isEmpty ? "" : " ") + "Buzz" はさすがにひどい#if swift(>=4.0) で enum case 追加みたいなのがないので、微妙なんですが、 https://github.com/apple/swift/blob/master/stdlib/public/core/HashedCollections.swift.gyb#L4348-L4349 の Linux には存在しないはずの case cocoa(CocoaBuffer) の扱いをみてると泣きたくなったので実装しちゃいました。I'm in favor, certainly. I'd personally say this wouldn't even need to go through the full evolution process, but I'm not a core team member.Seems reasonable to me. って言ってるしイケそう。Arrayをポインタで走査したい場合にCoWを走らせる方法って無いですかね? isKnownUniquelyReferencedで分岐できると良いんですが使えないようで。var a = [Int](repeating: 0, count: 10) var b = a let p = UnsafeMutablePointer<Int>(mutating: b) p.pointee = 100 // aも書き換わるvar a = [Int](repeating: 0, count: 10) var b = Array(a) let p = UnsafeMutablePointer<Int>(mutating: b) p.pointee = 100 print(a) print(b)
[100, 0, 0, 0, 0, 0, 0, 0, 0, 0] [100, 0, 0, 0, 0, 0, 0, 0, 0, 0]Array(a[0..<a.count])でもコピーできてないんでした。ArraySliceが全体を指してる場合のみの振る舞いっぽいですねa.withUnsafeMutableBufferPointer は? public mutating func withUnsafeMutableBufferPointer<R>(_ body: (inout UnsafeMutableBufferPointer<Element>) throws -> R) rethrows -> R var ary = [1,2,3] ary.withUnsafeMutableBufferPointer { buf in print(ary.count) // -> 0 } この挙動おもしろいな。swift-DEVELOPMENT-SNAPSHOT-2017-05-09-a 壊れまくりな感じ… swift-DEVELOPMENT-SNAPSHOT-2017-05-10-a で直ってた。
(edited)API resilience describes the changes one can make to a public API without breaking its ABI. Does this proposal introduce features that would become part of a public API? If so, what kinds of changes can be made without breaking ABI? Can this feature be added/removed without breaking ABI? For more information about the resilience model, see the library evolution document in the Swift repository.struct Hoge { var fuga: Int { return fuga } } let hoge = Hoge.init() print(hoge.fuga) // <- 無限ループで死private let _event: PublishSubject<Event> var event: Observable<Event> { return event.asObservable() }original ブランチを作って、そこに原文つっこんでoriginal → master でマージして master の今のバージョンをそのまま採用してswift-4.0-DEVELOPMENT-SNAPSHOT-2017-05-09-a が出てる。swift-4.0-DEVELOPMENT-SNAPSHOT-2017-05-11-a だった。 func run(_ options: NoOptions<SourceKittenError>) -> Result<(), SourceKittenError> { print(version) - return .success() + return .success(()) }func f11(x: () -> ()) {} func f12(x: () -> Void) {} func f13(x: () -> (Void)) {} func f14(x: () -> ((Void))) {} func f15(x: () -> (((Void)))) {} func f21(x: (Void) -> ()) {} func f22(x: (Void) -> Void) {} func f23(x: (Void) -> (Void)) {} func f24(x: (Void) -> ((Void))) {} func f25(x: (Void) -> (((Void)))) {} func f31(x: ((Void)) -> ()) {} func f32(x: ((Void)) -> Void) {} func f33(x: ((Void)) -> (Void)) {} func f34(x: ((Void)) -> ((Void))) {} func f35(x: ((Void)) -> (((Void)))) {}[omochi@omochi-MB swift-ownership-jp (master=)]$ git merge original fatal: refusing to merge unrelated histories--allow-unrelated-histories つけてもダメでした?require が absolute よりも predictable であることを欲するよって$ git log --graph --all --decorate * commit 8959b3248ca9f6264f36a08d67d47e1cd1271d6f (HEAD -> master, origin/master) |\ Merge: 5494a14 773e8de | | Author: Yuta Koshizawa <koher@koherent.org> | | Date: Fri May 12 16:35:58 2017 +0900 | | | | Merge branch 'original' | | | * commit 773e8defca014cefed7d4aade63b9b22255772f5 (origin/original, original) | Author: Yuta Koshizawa <koher@koherent.org> | Date: Fri May 12 16:34:23 2017 +0900 | | Original | * commit 5494a1445902fcfa7aeaf3708a3f9c939f807647 Author: Yuta Koshizawa <koher@koherent.org> Date: Fri May 12 16:33:23 2017 +0900 Initial commit$ git diff original master diff --git a/a.txt b/a.txt index 1802a74..c4f3b1d 100644 --- a/a.txt +++ b/a.txt @@ -1,3 +1,6 @@ aaa +111 bbb +222 ccc +333Void に変えようと試したら、ビルドできなかった。 error: member 'success' in 'Result<Void, SourceKittenError>' (aka 'Result<(), SourceKittenError>') produces result of type 'Result<T, Error>', but context expects 'Result<Void, SourceKittenError>' (aka 'Result<(), SourceKittenError>') return .success(Void) ^
(edited)Void はあくまで型なので、そのインスタンスは () しかだめですね。return .success(Void()) で通る。Void って typealias じゃないの?typealias A = (a: Int, b: Int) let a = A(1,2) もできる。A(a: 1, b: 2) ではないんだ 4> typealias A = (a: Int, b: Int) 5> A(a: 2, b: 3) $R0: (a: Int, b: Int) = { a = 2 b = 3 } 6> A.init(a: 2, b: 3) error: repl.swift:6:1: error: type 'A' (aka '(a: Int, b: Int)') has no member 'init' A.init(a: 2, b: 3) ^ ~~~~ 6> let createA: (Int, Int) -> A = A error: repl.swift:6:32: error: cannot convert value of type 'A.Type' (aka '(a: Int, b: Int).Type') to specified type '(Int, Int) -> A' let createA: (Int, Int) -> A = A ^.init もダメだし、変数に入れることはできないか・・・struct がいいと思います。
(edited)typealias A = (a: Int, b: Int) let a = A(a: 1, 2) let b: (x: Int, y: Int) = (1,y: 2) これが出来るのとか含めて、タプルは特別扱いすぎて本当に。Void に変えるのはやめようtrue や false のノリで void があってもいい気もする。 Void 型のインスタンスが () なのはわかりづらい・・・。() 型のインスタンスが () なのも、値と型の区別がつきづらいけど・・・Void のインスタンスを扱わなければならないとき(ジェネリクスの型パラを Void で埋めたときなど)は Void 型のインスタンスを扱う必要があって、そうすると Void が () の typealias であることを知っている必要があって・・・と考えると、 Void より () と書いている方がいい気がしてきました。Void はそもそも省略できるから書かないし。() を無駄に取る事の無い版を付け足すのか 6> let a: Int = (((42))) a: Int = 42 7> let b: (((Int))) = a b: (((Int))) = { _value = 42 } 8> b + 1 $R1: Int = 43 (edited)() -> () と (()) -> () は異なるのに () -> (()) は同じってちょっと気持ち悪い感じが・・・。((( ))) -> RetTy |-----| param list |---| paren |-| tuple って感じですね。 (edited)() なのよくないよなぁ。やっぱ @tarunon さんの言うように人類には括弧が足りなかった・・・<, > も演算子と共用なのがヤバイですしね。「」←彼らをデビューさせましょう(ない)『』, 【】 もいけますねwArray【Int】 とか、可読性だけならアリそう。func testA() { let size = 10_000_000 measure { // 0.013sec let array = [Float](repeating: 0, count: size) } } func testB() { let size = 10_000_000 measure { // 0.034sec let dst = UnsafeMutablePointer<Float>.allocate(capacity: size) defer { dst.deallocate(capacity: size) } let array = [Float](UnsafeBufferPointer(start: dst, count: size)) } }deferで開放されるわけですしUnsafeBufferPointer自体をそのまま作ることはできないので開放タイミングがどうすればいいのかさっぱり分からないというUnsafeBufferPointerの持ち主のdeinitで開放させるとかになるんですかねUnsafeBufferPointer instance is a view into memory and does not own the memory /// that it references.func testB() { let size = 10_000_000 measure { // 0.034sec let dst = UnsafeMutablePointer<Float>.allocate(capacity: size) defer { dst.deallocate(capacity: size) } let array = UnsafeBufferPointer(start: dst, count: size) } }ManagedBuffer のほうが良いと思いますよ。ManagedBuffer のオブジェクトの実体の直後に tail allocate されるので、ちょっとだけ効率が良いはず。deinit呼ぶ必要があるのでは?
Float などの trivial な値だったらそのままでも大丈夫かと。ContiguousArray 使えばいいのでは?と思ってしまう。Arrayの初期化コストを削減したいということなのですArray の初期化コストが hot spot なのですか?func testA() { let size = 10_000_000 let src = [Float](repeating: 0, count: size) var one: Float = 1 measure { // 0.020sec var dst = [Float](repeating: 0, count: size) vDSP_vsadd(src, 1, &one, &dst, 1, vDSP_Length(size)) } } func testB() { let size = 10_000_000 let src = [Float](repeating: 0, count: size) var one: Float = 1 measure { // 0.017sec let dst = UnsafeMutablePointer<Float>.allocate(capacity: size) defer { dst.deallocate(capacity: size) } vDSP_vsadd(src, 1, &one, dst, 1, vDSP_Length(size)) } } ほとんど差ないですねfunc testA() { let size = 10_000 let src = [Float](repeating: 0, count: size) var one: Float = 1 measure { // 0.021sec for _ in 0..<size { var dst = [Float](repeating: 0, count: size) vDSP_vsadd(src, 1, &one, &dst, 1, vDSP_Length(size)) } } } func testB() { let size = 10_000 let src = [Float](repeating: 0, count: size) var one: Float = 1 measure { // 0.012sec for _ in 0..<size { let dst = UnsafeMutablePointer<Float>.allocate(capacity: size) defer { dst.deallocate(capacity: size) } vDSP_vsadd(src, 1, &one, dst, 1, vDSP_Length(size)) } } } これだと倍近い差がManagedBuffer を使った型ではないのね。 var dst = ContiguousArray<Float>(repeating: 0, count: size) dst.withUnsafeMutableBufferPointer { dst in vDSP_vsadd(src, 1, &one, dst.baseAddress!, 1, vDSP_Length(size)) } でもUnsafeMutablePointerとほぼ同じになるぽい。 (edited)measure の結果は遅くなるのに。!535 は 535 utils/build-script --skip-ios --skip-tvos --skip-watchos --jobs 2 --skip-test-osx trueutils/update-checkout --scheme swift-4.0-branch --tag swift-4.0-DEVELOPMENT-SNAPSHOT-2017-05-11-a でチェックアウトutils/update-checkout を実行した結果がどうなるかは知らないです。/Users/omochi/work/swift-source/swift/lib/Basic/Version.cpp:334:5: error: static_assert failed "getCurrentLanguageVersion is no longer correct here" static_assert(SWIFT_VERSION_MAJOR == 4, ^ $ utils/update-checkout --clone --scheme master とりあえず master 前提で進めると、これで関連リポジトリ含めて全て clone してきます。 (edited)$ utils/build-script --clean ... のように --clean オプション付けて build-script 実行swift-4.0-DEVELOPMENT-SNAPSHOT-2017-05-13-a が来そうな感じ class A<X> { } class B: A<B.X> { struct X {} } print(B())(lldb) bt * thread #1, name = 'test', stop reason = signal SIGSTOP * frame #0: 0x00007ffff6a72a9f libpthread.so.0`__pthread_once_slow + 95 frame #1: 0x00007ffff7c7f96f libswiftCore.so`swift_once + 95 frame #2: 0x0000000000400fef test`type metadata accessor for test.B + 47 frame #3: 0x0000000000401531 test`___lldb_unnamed_symbol7$$test + 17 frame #4: 0x00007ffff6a72ae9 libpthread.so.0`__pthread_once_slow + 169 frame #5: 0x00007ffff7c7f96f libswiftCore.so`swift_once + 95 frame #6: 0x00000000004013df test`type metadata accessor for test.B.X + 47 frame #7: 0x000000000040138e test`type metadata accessor for test.A<test.B.X> + 30 frame #8: 0x0000000000401341 test`___lldb_unnamed_symbol5$$test + 17 frame #9: 0x00007ffff6a72ae9 libpthread.so.0`__pthread_once_slow + 169 frame #10: 0x00007ffff7c7f96f libswiftCore.so`swift_once + 95 frame #11: 0x0000000000400fef test`type metadata accessor for test.B + 47 frame #12: 0x0000000000400f31 test`main + 65 frame #13: 0x00007ffff6ca1830 libc.so.6`__libc_start_main + 240 frame #14: 0x0000000000400e09 test`_start + 41swift/utils/build-toolchain を使いました。このジョブと同じ内容。 https://ci.swift.org/view/Packages/job/oss-swift-package-osx/ (edited)swift/utils/build-toolchain はすべてのプラットフォームのテストを実行するため、めっちゃ時間がかかります。(僕のMacで11時間以上かかった)Job config: swift/utils/build-script --preset="buildbot_osx_package" \ install_destdir="${SWIFT_INSTALL_DIR}" \ installable_package="${SWIFT_INSTALLABLE_PACKAGE}" \ install_toolchain_dir="${SWIFT_TOOLCHAIN_DIR}" \ install_symroot="${SWIFT_INSTALL_SYMROOT}" \ symbols_package="${SYMBOLS_PACKAGE}" \ darwin_toolchain_bundle_identifier="${BUNDLE_IDENTIFIER}" \ darwin_toolchain_display_name="${DISPLAY_NAME}" \ darwin_toolchain_xctoolchain_name="${TOOLCHAIN_NAME}" \ darwin_toolchain_version="${DARWIN_TOOLCHAIN_VERSION}--skip-test-* なんとかをつけまくれば良いと思います。>テスト (edited)--skip-test-lldb をつけるとさらに短縮されるかな。--skip-test-lldb で出てるはず。struct Hoge<T> { } extension Hoge where T == [Any] { func fuga() -> T.Element { // <- Error: 'Element' is not a member type of 'T' fatalError() } }Any って書けば?struct Hoge<T> { } extension Hoge where T: Sequence { func fuga() -> T.Iterator.Element { // <- Error: 'Element' is not a member type of 'T' fatalError() } } これは通るねHoge<[Int]> にはこのextensionだめ?struct Hoge<T> { } struct Nested { struct MoreNested { } } extension Hoge where T == Nested { func fuga() -> T.MoreNested { // これもだめだった。 fatalError() } }struct Hoge<T> { } extension Hoge where T == Array<Any> { func fuga() { print("fuga!") } } let x = Hoge<[Int]>() x.fuga()Playground execution failed: error: HogeGround.playground:5:1: error: 'Hoge<[Int]>' (aka 'Hoge<Array<Int>>') is not convertible to 'Hoge<Array<Any>>' x.fuga() -> T. まで打つと NestedType を補完してくるんだよなprotocol HasElement { associatedtype Element } extension Array : HasElement {} struct Hoge<T> { } extension Hoge where T: HasElement { func fuga() -> T.Element { // 通る fatalError() } } (edited)extension<T> Array where Element == T? { var someValues: [T] { var result = [T]() for opt in self { if let value = opt { result.append(value) } } return result } }extension Array where Element == Int { ... } を extension Array<Int> { ... } のように書けるようにするのには何か技術的な難しさがあるの?って質問(ちょっとニュアンス違うけど)。 https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170508/036599.html (edited)--- Installing swift --- + env DESTDIR=/Users/omochi/work/swift-install/ /usr/local/bin/cmake --build /Users/omochi/work/swift-source/build/build-dir/swift-macosx-x86_64 -- install ninja: error: unknown target 'install', did you mean 'test/all'? utils/build-script: fatal error: command terminated with a non-zero exit status 1, abortingstruct Hoge<T> { let value: T } extension Hoge where T: BidirectionalCollection { func fuga() -> T.Iterator.Element { return value.first! } } Hoge(value: [1, 2, 3]).fuga() // 1