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 b
b
は 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 = 3
let a = 3
class 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 GB
time
コマンドの real
を張ってる。1回しかやってないし他の作業も止めてないからだいぶガバガバだけど。 (edited)~ (๑˃̵ᴗ˂̵)ﻭ < time swiftc compile.swift -o compile swiftc compile.swift -o compile 15.78s user 0.30s system 99% cpu 16.137 total
this
が使えないためサブクラスのフィールドを埋める前に親クラスのコンストラクタが呼ばれる 厳しさ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: T
CatInt, 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 errors
a
を 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 X
Never
が 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.self
class 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/a
let 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_msgSend
swift_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の類義語探すだけになりそう そうなのよw
switch 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: %19
cats
で 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: U
extension 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)) = a
let c: (Int, (String, Animal)) -> () = { _, _ in } let d: (Int, (String, Cat)) -> () = c
let 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 Boilerplate
swift_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 // OK
class 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: FooFatal
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_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 -> T
intOpt ?? 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_.Bar
Base
が 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 -> T
func 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 -> T
do
- 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>>.Type
Array
にするのか 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 = 2
let 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 2
async
/ 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 // 1
protocol 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.Returns
Cat 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 +333
Void
に変えようと試したら、ビルドできなかった。 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 + 41
swift/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, aborting
struct 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
extension Hoge where T: RangeReplaceableCollection { }
と書いておけば、その中でT.initが使えるようになるBidirectionalCollection
はよく使うんだけどなんだったかな、last
が欲しいので使ってた気がする。$utils/build-script <options A> -- <options B>
こうなってて、Aはbuild-scriptのやつ、 Bはbuild-script-implのやつか?--- 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, aborting
だめだwbuild-script
へ渡すオプションの組み合わせはプリセットとして swift/utils/build-presets.ini
の中に記述されています。例えば OSS - Swift Package - OS X (master) で使われている buildbot_osx_package
プリセットはこれ。 https://github.com/apple/swift/blob/master/utils/build-presets.ini#L955 (edited)/Users/buildnode/jenkins/workspace/oss-swift-4.0-package-osx/swift/utils/build-script: note: using preset 'buildbot_osx_package', which expands to
swift/utils/build-presets.ini
の代わりに自分で用意したものも --preset-file=…
で使えます。 (edited)