func hoge<Foo: Protocol>(foo: Foo)
と、fucn (foo: Protocol)
だとstruct API { private init() { } struct Request { private init() { } struct GetDayOfWeekStories: APIRequest {
(edited)case
なし enum
だとどうやってもインスタンス化できないので、 private init 書く必要ないから いいんじゃないかと思ってます。private init() { fatalError() }
くらいにした方がいいかなと思ってました)/// Namespace for diagnostics enum diag {} extension diag { // メンバー群 ...
実際にはすべてのメンバーを extension に実装することにより、 case
を書けなくするということをやっています。 (edited)??
って、もしかしてコンパイルすごい遅いんでしょうか func apiErrorWithPromise(_ errorMsg: String? = nil, _ httpNumber: Int? = nil) -> Promise<Void>{ let errorMessage = "エラーメッセージ:\n"+(errorMsg ?? "不明なエラー(iMast)")+" ("+String(httpNumber ?? -1)+")\n\nエラーメッセージに従っても解決しない場合は、アプリを再起動してみてください。" return alertWithPromise( title: "APIエラー", message: errorMessage ) }
var errorMessage:String = "" errorMessage = "エラーメッセージ:\n" errorMessage += errorMsg ?? "不明なエラー(iMast)" errorMessage += " (" errorMessage += String(httpNumber ?? -1) errorMessage += ")\n\nエラーメッセージに従っても解決しない場合は、アプリを再起動してみてください。"
のようにしたら早くなりました、ありがとうございます\()
どうも個人的に読みにくいんですよねlet errorMessage
に +で連結して代入 let errorMsg2 = errorMsg ?? "不明なエラー(iMast)" let httpNumber2 = httpNumber ?? -1
String.localizedStringWithFormat("", a, b)
) 今回の場合、これだけで速くなりそう。 (edited) typealias DataSearchFlags : oneof { None, Backward, Anchored }
[default: ]
を指定するのは、値の存在が保証されてない場面では??dict[key]! += 1
ってできたっけ?dict[key] += 1
ができるかどうかはわからないけど、 それができないからといってdict[key, default: never()] += 1
こう?dict[key, default: undefined()] += 1
var x: [String: Int] = [:] x["aaa"] = 3 x["aaa"]! += 1 print(x["aaa"])
Optional(4)
!
演算子はオペランドが左辺値の場合、左辺値のままにしてくれるのか。dict[key]! += 1
で良いってことになるのか・・・?dict[key] ?? defaultValue += 1
dict[key] ||= 3
rubyだとこういうのよく見る (edited)func doubleQuestion( left: (read: ()->T?, write: (T)->Void), right: (read: ()->T, write: (T)->Void) ) -> (read: () -> T, write: (T) -> Void)
(edited)Neverがボトムになれba まどろっこしい関数用意しなくて良くなるんだがな
これおもしろいですね。dict[key, default: fatalError()] += 1
(edited)Never
がボトムタイプでない現状だと、 func never<T>(_ message: String = "") -> T { fatalError(message) }
みたいなのがいると。Never
がボトムタイプにならないのって誰も Proposal 書かないから?An uninhabited type can be seen as a subtype of any other type ... This can be considered as a separate proposal.
enum Never {}
がボトムってどうなの?とか、他の enum Foo {}
はどうなるの?とか、色々ややこしいから後回しにされてるのでは。+1
みたいなリプライあるけどwsomeFunc(AnyProtocol, parameter...)
的なのを考えてたんですが型で判別できるから、ありかどうかで迷ってる感じですdownload
は Alamofire.download
ですよね 正式にはSwift.min
ですdownload
でアクセスできるので 結局そこがどうなのかって話なわけですよねcom.omochimetaru.Alamofire.download
とかなってシンドイけど Alamofire.download
ならまあ別に平気だし、だいたいは引数の型でも区別可能だし。download
が出てきてごちゃごちゃしてきたときはfunc alamofireDownload() { .. }
とかを自作してラップするのが良いんじゃないでしょうかimport ... as ...
的なやつですかprotocol APIRequestable { func load<R: Request>(request: R) -> R.Response }
って感じですかね?requests<R: Request>(adapter: RequestAdapter=DefaultRequestAdapter()) -> (request: R) -> R.Response
みたいにしようかで悩んでました (edited)swiftc
が生成したhello_world.bc
のターゲットがx86_64-apple-macosx10.9
になってるからダメだよ、となってる。swiftc
でtarget
がasmjs-unknown-emscripten
な.bc
を生成できないとダメなんじゃないかな。emscripten
のissueには「asmjs-unknown-emscripten
はWebAssembly
(wasm32
)とほぼ同じだよね?」って話してる人がいて、同じ人がSwiftをWebAssemblyへクロスコンパイルする話題をswift-devに投げてる。 https://lists.swift.org/pipermail/swift-dev/Week-of-Mon-20170626/004860.html (edited)Promise
みたいに非同期処理とエラー処理をまとめて扱うような設計が嫌いで、非同期処理なら非同期処理、エラー処理ならエラー処理と責務を分解しておくべきだと考えて、エラー処理を含まない Promise
↓を作ってました。 https://github.com/koher/PromiseK/tree/dev-3.0Promise
と Result
が対応してるなと思って、それらを throws
, try
と (edited)async
, await
に対応させれば、自由にまぜて使えるよなぁと考えたものです。Promise
にエラー処理を担当させちゃうと、 catch
忘れがおこっちゃうんですよねぇ。Promise
と Result
を一緒に使うとモナドパズルになっちゃうんですよねぇ。Result<Promise<Result<Foo>>>
を Promise<Result<Foo>>
にしたいとか。Array<Promise<Result<Foo>>>
を Primise<Result<Array<Foo>>>
にしたいとか。let a: Promise<Int> = ... let b: Promise<() throws -> Int> = a.map { try foo($0) }
みたいに、 map
等の中で throw
される場合は戻り値の型パラメータを () throws -> Foo
に変換する API を考えてます。async
, await
ができれば無用の長物ですが。typealias Promise<Value> = (@escaping (Value) -> ()) -> ()
とする Promisure (= Promise + Closure) というライブラリも作ってましたw// Wrapping let a: Promise<Int> = { $0(3) } // like `Promise.resolve(3)` in JS // Promisifying a callback let b: Promise<Int> = promise { resolve in // Gets 5 after 1.0 seconds DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { resolve({ $0(5) }) } } // Operators let sum: Promise<Int> = a >>- { a in b >>- { b in { $0(a + b) } } } // flatMap let square: Promise<Int> = { $0 * $0 } <^> a // map let vector: Promise<Vector2> = curry(Vector2.init) <^> { $0(2.0) } <*> { $0(3.0) } // apply
Observable
にエラーが組み込まれてるのも僕は好みじゃないんですが、どうにかならないものでしょうか。throws
, try
みたいな特殊構文用意するよりも、モナドに対して do
記法用意するとかの方が汎用性はありますよねぇ。Result
と Promise
なら Promise
が外側にいてほしいとか、モナド感での precedence みたいなものが考えられる気がして、Monad
型に対して演算子みたいな precedence
を指定できてsort
関数みたいに、それを使って入れ子を関数が解決する。let a: Result<Promise<Int>> = ... let b: Promise<Result<Int>> = magic(a) do { let c: Int <-- b // 多段アンラップ let d: Result<Int> <- b // 一段アンラップ }
try
とかキーワード足さなくても自作モナドを組み込みモナドと同じように便利に使える。then
が map
と flatMap
になってるんですけど、ネストしてくると読みづらいんですよねぇ・・・。Result
を作らなかったから thorws
, try
を別の型でラップしたい場合に Promise<() throws -> Int>
とかなるのはちょっとつらいですよね。Observable
とかでやろうとしたらできないですよね?=>
レベルだと演算子の方が可読性高そうだけど。Any
でもダメで、任意の型パラじゃないといけないから辛い・・・extension Any { func `let`<T>(_ f: (Any) -> (T)) -> T { ... } }
Any
になっちゃってSelf
にする extension
ってできるんだっけ?public func =><T, U>(lhs: T, rhs: (T) throws -> U) rethrows -> U { return try rhs(lhs) }
class Animal {} class Cat : Animal { func nya() { print("nyaa") } } extension Animal { func exec(f: (Self) -> Void) { f(self) } } let cat = Cat() cat.exec { $0.nya() } error: TempGround.playground:11:12: error: value of type 'Animal' has no member 'nya' cat.exec { $0.nya() } ^~ ~~~
extension SomeProtocol where Self: SomeClass {}
(edited)extension Any where Self: SomeClass {}
protocol Anything {} extension Anything { func `let`<T>(_ f: (Self) throws -> T) rethrows -> T { return try f(self) } } extension Double: Anything {} (42.0).`let` { $0 + 1.0 / $0 }
protocol Proto {} class Cat : Proto { func nya() { print("nyaa") } } extension Proto { func exec2(f: (Self) -> Void) { f(self) } } let cat = Cat() cat.exec2 { $0.nya() }
=>
の議論からするとそれは問題ないのでは=>
の実装をオペレータからメソッドにできるかどうかだけを今考えていてAny
が nominal でないってことだけなわけだ。Self
を f
に渡す形で実装はできる。Any
じゃなくてLettable
という protocol
のメソッドとして作って.let
を使いたい型については extension Cat : Lettable {}
=>
の方がいいと思う。<$>
は順番が逆転しちゃう問題もありますしねぇ・・・Promise
のチェーンはpromise.flatMap { ... }.flatMap { ... }.flatMap { ... }
primise >>- { ... } >>- { ... } >>- { ... }
=>
は標準ライブラリに入れてほしい・・・。r'''
出せなかったし嘘だと思うr'''
は正規表現じゃなくて生マルチライン文字列Swift >>-
で検索したら、一つ目は https://www.apple.com/jp/swift/ だけど、二つ目は typelift/Operadics で、三つ目は thoughtbot/Runes だった。<^>
も駄目っぽいですよ>>=
は重複してるから >>-
に、 <$>
は言語仕様上の制約で <^>
になってる。haskell <$>
は https://stackoverflow.com/questions/37286376/what-does-mean-in-haskell が出たからEither<T, Either<U, V>>
public enum Either2<A, B> { case a(A) case b(B) } public protocol Either2Convertible { associatedtype CaseA associatedtype CaseB var asEither: Either2<CaseA, CaseB> { get } } extension Either2: Either2Convertible { public var asEither: Either2 { return self } }
enum
の抽象化ってことは、 Either2<Int, String>
と Either2<String, Int>
は区別したいってことですよね?Enum2
, Enum2Convertible
は良さそうEnum1
と Enum0
もいらないですか? Box
と Never
Enum3
とかだと CaseA
より Case1
とかの方がよさそうenum Enum2<T0, T1> { case Case0(T0) case Case1(T1) }
EnumN
とか?Houyhnhnm 音節Hou・yhn・hnm 発音記号/hwínəm|húːɪ‐/ 名詞可算名詞 フーイナム 《Swift 作 Gulliver's Travels (ガリバー旅行記)の中の人間的な理性が徹底している馬; 人間の形をした Yahooを支配する》. [馬の鳴き声からのSwiftの造語]
swift package init
したときに面倒$ swift package init --help OVERVIEW: Initialize a new package OPTIONS: --type empty|library|executable|system-module
Yahoo!の名前の由来は英語の「Yet Another Hierarchical Officious Oracle」(さらにもう一つの階層的でお節介な神託)の略だといわれている[57]。また、ファイロとヤンは自分たちのことを「ならずもの」だと考えているので、「粗野な人」という意味がある「Yahoo」(『ガリヴァー旅行記』に登場する野獣の名前が由来)という言葉を選んだと主張している[10]。さらに感嘆符が付いていることに関しては「ヤッホー!」「やったー!」を意味する英語の感動詞「yahoo」と掛けているとも考えられる。
EnumNConvertible
を EnumN
に convert するんじゃないんですか?CustomStringConvertible
とかを考えても EnumNConvertible
とかならおかしくない気も。$ gyb -D Key=Value
でパラメータ渡せるから、できるよpublic func animatedItems<S: AnimatableSectionModelType, O: ObservableType, C0: Reusable, C1: Reusable, C2: Reusable, C3: Reusable, C4: Reusable>(for type0: C0.Type, _ type1: C1.Type, _ type2: C2.Type, _ type3: C3.Type, _ type4: C4.Type) -> (O) -> Disposable where C0: UICollectionViewCell , C1: UICollectionViewCell , C2: UICollectionViewCell , C3: UICollectionViewCell , C4: UICollectionViewCell , S.Item: Enum5Convertible , S.Item.T0 == C0.Dependency , S.Item.T1 == C1.Dependency , S.Item.T2 == C2.Dependency , S.Item.T3 == C3.Dependency , S.Item.T4 == C4.Dependency , O.E == [S] {
使う側がこんな感じの地獄じみた形相になってるから、任意個数サポートできるのはもはや必須の感じがするdataSourceObservable .bind(to: tableView.rx.animatedItems(for: MyCell1.self, MyCell2.self)) .disposed(by: disposeBag)
curry
は昔ジェネリック引数14個(?)でコンパイル終わらなくなる問題がありましたが大丈夫そうですか?--line-directive=
入れないと ###sourceLocation
が各行入るからなんなのかと思った!!
オペレータ。機能は !
と同じ。Codable
を適用すると、encode/decodeを実現するための実装をコンパイラーが生...struct ObservableA<T> { func subscribe(onNext:(T) -> () = { _ in }) { } } ObservableA<(Int, Int)>().subscribe(onNext: { (a, b) in // ok }) struct ObservableB<T> { func subscribe(onNext:((T) -> ())? = nil) { } } ObservableB<(Int, Int)>().subscribe(onNext: { (a, b) in // 死ーん })
[omochi@omochi-iMac bin]$ pwd /Users/omochi/work/swift-source/build/Ninja-RelWithDebInfoAssert/swift-macosx-x86_64/bin [omochi@omochi-iMac bin]$ ./swift --version Swift version 4.0-dev (LLVM a15decabe3, Clang 60a12bf739, Swift fcd389b17e) Target: x86_64-apple-macosx10.9
XCTest
にXFAIL
欲しいlit
はテキストファイルならなんでも良いので、.md
にテストを書いたりできるのが面白いと思った。 https://github.com/apple/swift-integration-tests/blob/master/swift-package-init-exec.mdlit.cfg
で指定すればですね。 https://github.com/apple/swift-integration-tests/blob/master/lit.cfg#L56XCTAssertEqualWithAcuracy
はフィールドごとに確認するので増えるほど書くのがきつくなる stcuct Hoge { val a: Float } let x = Hoge(a: 0) let y = Hoge(a: 0) XCTAssertEqualWithAcuracy(x, y, accuracy: 1e-10)
かといって関数に切り出すとXCodeで停止地点が分かりづらくなる。 XCTAsserEqual
はEquatable
を実装するだけで使えるので 同様にNealyEquatable
みたいなプロトコルを切ってXCTestがそれを使うXCTAssertEqualWithAcuracy
を用意してくれるのがベストかな。swift test
とかで結構密接に結びついてるのでこちらからどうこうもしにくい気が。かといって関数に切り出すとXCodeで停止地点が分かりづらくなる。
切り出した関数に…file: StaticString = #file, line: UInt = #line)
とかつけると良いのでは。QuickSpec
が(間接的に) XCTestCase
を継承してるのか。 https://github.com/Quick/Quick/blob/cd89737d3d5306124e91c357b66cde274a3269b4/Sources/Quick/QuickSpec.swift#L13swift test
もできるのかな?swift test
Package.swift
はdependenciesがなんか複雑になってますね……Quick
を使いたいからじゃない? < 複雑XCTestCase
を継承してる https://github.com/Quick/Quick/blob/cd89737d3d5306124e91c357b66cde274a3269b4/Sources/QuickSpecBase/include/QuickSpecBase.h#L8testDependencies
がなかったので、テストの時だけ使う依存を実現してる。testDependencies
見た気がしてたんだけど使えなくなってるのか・・・Remove testDependencies from PackageDescription This feature was supposed to support dependencies only for the root package but at some point it stopped working however the API still remained open. This patch removes the public API. This is a valid and desired feature which is supposed to come back after it goes through proper review on swift evolution.
https://github.com/apple/swift-package-manager/commit/34b7826cb586b0769ea5f60a7718d7de599ce27fPackage.swift
を用意してたけど、環境変数で切り替えられることをikesyoさんに伝えたら使ってくれた。 (edited)Package
の dependencies
がテストからも使えるのなんか変な気も。> SWIFTPM_TEST_Carthage ああこれはSPMが定義してくれるのか。
Makefileで実行するときに設定してます。 https://github.com/Carthage/Carthage/blob/master/Makefile#L82Package.swift
がサンドボックス内で解釈される際に、SwiftPMがあえて環境変数を引き継ぐ様にしてるので、あながち間違いでもない。$ which -a sandbox-exec /usr/bin/sandbox-exec
DESCRIPTION The sandbox-exec command is DEPRECATED. Developers who wish to sandbox an app should instead adopt the App Sandbox feature described in the App Sandbox Design Guide.
sandbox-exec
を使う様にしたコミットには環境変数がらみが特に書かれてないぽいから「環境変数をあえて渡す」というのは、チャットの中だけの話だったかも。#line
を使うってこれのことですか。 http://masilotti.com/xctest-helpers/ そもそもrecordFailure
の存在を知らなくてログに行番号出るだけじゃ分かりにくいとか思っていました。XCTAssert*()
シリーズにも渡せます。XCTAssert*()
シリーズに渡せるってのは何でしょう? recordFailure
がXCTestCase
のメソッドなのでXCTAssert*()
のようにトップレベルのを定義するにはデフォルト引数で呼び出し元のself
を渡すとかするのかなぁと思ったのですが。self
を渡す話をよく覚えていない……XCTestCase
は引数にないのでどこから渡っているのか謎。 別の仕組みになっているんだろうか。recordFailure
はXCTestCase
のメソッドなんですよ。 で、XCTAssert*()
はトップレベルなのでrecordFailure
が使えない(はず)XCTestCase
のextensionにすればいいんですが XCTAssert*()
と同名を用いると例のバグ?でトップレベルのほうが見えなくなる。 (edited)recordFailure()
ではなく XCTFail()
を使ってました。 https://github.com/realm/SwiftLint/blob/master/Tests/SwiftLintFrameworkTests/IntegrationTests.swift#L35recordFailure
を使うんじゃなくて内部でfile, line指定付きのXCTAssert*()
を使えってことですね。 間違った方向に進んでました。enum Foo { static var foo: Foo { fatalError() } } func bar(_ foo: @autoclosure () -> Foo, ....) { ... } bar(.foo, ....)
これが可能になるFoo.foo
が実際には生成されないのがポイント?delegate.scrollView(scrollView, .didScroll)
とかにいいかも (edited)struct Foo {} let foo = Foo() func bar(foo: Foo, ....) { ... } bar(foo, ....)
そもそもこれじゃ駄目な理由は?struct Foo { static var foo = Foo() }
ならまあ差はそれほど無いのかもしれない。.foo
で書けるねstruct BarOverloads { static let foo = BarFoo() static let poo = BarPoo() } func bar(_ overload: BarFoo, ...) func bar(_ overload: BarPoo, ...) bar(.foo, ...) // できない bar(.poo, ...)
(edited)struct Bar { struct Foo { static let foo = Foo() } struct Poo { static let poo = Poo() } } func bar(_ overload: Bar.Foo, ...) func bar(_ overload: Bar.Poo, ...) bar(.foo, ...) bar(.poo, ...)
(edited)\
を使う感じで。 https://github.com/apple/swift-evolution/blob/master/proposals/0182-newline-escape-in-strings.md (edited)let s = """ ... In Windows you have paths like C:\ ... """
\
を \\
に直さないといけないけど、新使用だとコンパイルエラーにならないから問題だと。特に """
だからといって文字列コピペしてきたときとかに問題起こりそう。c:\news
とかもそうなんで。ちょっと弱い。Optionalのclosureでtupleが分解できない問題治してもらえた。はやいw
swift-4.0-DEVELOPMENT-SNAPSHOT-2017-07-11-a
以降で直ってるぽいですね。struct
でもサイズが大きいと勝手に最適化されたりするんでしょうか?どこかで触れられてましたっけ? https://developer.apple.com/videos/play/wwdc2017/402/std::string
は確か COW だったけど COW 止めたんよね?Array
等の場合はマルチスレッドをサポートしないことで問題を回避している??var a = [2, 3, 5, 7] // スレッドA a[2] = 4 print(a) // スレッドB a[3] = 8 print(a)
(edited)startThread( closure: () -> Void )
var a = [2, 3, 5, 7] a[2] = 4 startThread { a[3] = 8 }
func startThread(f: @escaping () -> Void) { f() } func main() { var a = [2, 3, 5] a[0] = 88 startThread { a[1] = 99 } print(a) // [88, 99, 5] } main()
struct
である Array
に包まれてるからvar a = 2 let foo: () -> () = { a += 1 } foo() print(a) // 3
@escaping
が@nonescaping
なときはキャプチャされていてもvar a = 42 if random() < 0.0001 { foo = { print(a) } }
foo
がエスケープしてないからならない (edited)a
はスタック上には無いと思いますvar foo: () -> () = {} func bar() { var a = 42 if random() < 0.0001 { foo = { print(a) } } } for _ in 1...10000000 { bar() }
bar
のコールのほとんどではスタックで済ませられるはずだけど、a[0] = 99
に、バッファストレージインスタンスの参照カウンタを見て、1ならそのまま書き換える、2以上ならディープコピーする、だから・・・a
のスコープ自体がヒープに確保されてるから a
のバッファへの参照カウントは常に 1 になりそう。 var a = [2, 3, 5, 7] // スレッドA startThread { a[2] = 4 print(a) } // スレッドB startThread { a[3] = 8 print(a) }
a
の実体が1つだけあってa[2] = 4
とかを、ユーザ側で ロックしないとバグりそう?a
の実体が消えて、その先のストレージも消える。Array
がスレッドアンセーフなのと、 COW がスレッドセーフかどうかと、参照カウンタがスレッドセーフなことは独立な気がする。Array
がスレッドアンセーフな時点で Array
の COW もスレッドセーフである必要はない?それとも、 Array がスレッドアンセーフな時点で Array の COW もスレッドセーフである必要はない?
これがYESだと思います。Array
自体がスレッドアンセーフな時点で、 ArrayのCOWだけのスレッドセーフティーを考える意味がなくて、それもアンセーフArray
のCOWに同期のオーバーヘッドはないと。std::string
自体はスレッドセーフじゃないと思うんだよなあArray
をロックして使ってれっば問題は起こらない気がする。std::string
が COW でなくなったのは別の理由なのかな?std::string
と COW だった頃の std::string
はまた別かもしれない・・・std::thread
が入るときにこの規格がちゃんと整理されたって話がこの記事に同時に書いてあるのでstd::string
としては、2つに見えてるんだ。ユーザには。std::string
一個単位で readonly safe ってことしか聞いてないから (というかコピーをまたいだグループでロックを取るなんで不可能)Array
の COW はスレッドアンセーフでいい話と矛盾してない?var a = [2, 3, 5] // スレッドA a[2] = 4 // スレッドB var b = a b[2] = 999
a
と b
で同期とるとか無理でしょってことか。var a = [2, 3, 5] // スレッドA startThread { a[2] = 4 } // スレッドB startThread { var b = a b[2] = 999 }
Array
自体はスレッドアンセーフでも COW はスレッドセーフでないといけないってこと?a[2] = 4
と var b = a
の2行を、ユーザがロックすべきだと思う。b = a
の代入の最中に、 a[2] = 4
の処理が走り始めて内部状態が壊れる可能性があるはず。a[2] = 4
が書き込み操作で、 b = a
の右辺はreadだから、競合してるのでロックが要るって事になるはず (edited)int
の書き込みは atomic で同時なんてないんじゃないの? Q4. 基本型intはスレッドセーフですか? A4. 「同時アクセスが全て読み込み操作であれば安全」というスレッドセーフ性レベルが保証される。
http://yohhoy.hatenablog.jp/entry/2013/12/15/204116// 同一変数に対して片方が変更操作 int y = 2; void th1() { int r2 = y; // NG: データ競合 } void th2() { y = 42; // NG: データ競合 }
th1
と th2
の中でロックしてても不定じゃない?struct Counter { var count = 0 mutating func countUp() { count += 1 } mutating func reset() { count = 0 } }
(edited)struct
の場合CoWで実体分かれて問題ないんではreset
の write の方struct
だからといって CoW は自動的には起こりません。// 同一変数に対して片方が変更操作 int y = 2; void th1() { int r2 = y; // NG: データ競合 } void th2() { y = 42; // NG: データ競合 }
int y = 2; void th1() { y = 99; } void th2() { y = 42; }
の代入が atomic なら↑も OK となりそうだけど・・・。int
の代入は atomic なのかint
の代入がatomicでないから、ってことやんね?疑問は二つで、 - C++ において int の代入は atomic なのか - atomic だと仮定して↑はスレッドセーフなのか
int
にたいしてどれが適用されるかよくわからない。long
と double
以外のプリミティブや参照の読み書きは atomic っぽいから、 int
を同時に読み書きすること自体には問題なさそう。 For the purposes of the Java programming language memory model, a single write to a non-volatile long or double value is treated as two separate writes: one to each 32-bit half. This can result in a situation where a thread sees the first 32 bits of a 64-bit value from one write, and the second 32 bits from another write. Writes and reads of volatile long and double values are always atomic. Writes to and reads of references are always atomic, regardless of whether they are implemented as 32-bit or 64-bit values.
http://docs.oracle.com/javase/specs/jls/se8/html/jls-17.htmlint
の読み書きが atomic かどうかを調べて atomic だと知って安心した記憶があるんだけど、 Java の話だったのかなぁ。その感覚で int
の読み書きを atomic だと思っていたから↓がおかしいんじゃないかと思ったけど、 // 同一変数に対して片方が変更操作 int y = 2; void th1() { int r2 = y; // NG: データ競合 } void th2() { y = 42; // NG: データ競合 }
C++ では規格上 atomic でないからたとえそれを atomic に行う CPU 向けにコンパイルしたとしてもどのように最適化されるかわからず未定義動作なので↑は正しい、と。var a = 3 var b = 2 a = 4 b = 1 print("a=\(a), b=\(b)")
(edited)Int
等の代入や、参照型のアドレスの代入が atomic なのか気になる。a = 3
や b = 2
の時間帯は削除されるんじゃないかなあ。Int
やアドレスの代入が atomic でないなら、結構気を付けてプログラム書かないといけないなぁInt
の read / write ですら atomic ではない?.swift
か。Int
じゃ駄目 (edited)Int
であってもlet a = _stdlib_AtomicInt(42)
let a = _stdlib_AtomicInt(42) print(a.load()) // 42 a.store(999) print(a.load()) // 999
_stdlib_AtomicInt
とかも atomic であるところまでの保証であって「「Intの代入がatomic」だとしても」は同じじゃないの?var x = 3 x = 2
func a() -> Int { var a = 3 a = 2 return a }
func a
の例で言うなら、これってfunc a() -> Int { return 2 }
と最適化されるかもしれないfunc a(x: inout Int) -> Int { x = 3 x = 2 return x }
(edited)func a(x: inout Int) -> Int { return 2 }
(edited)std::atomic<int>
に対してはstore
命令の削除も禁止されるはず。x
→ a
だったら inout
だから x
への代入は必須じゃない?func a(x: inout Int) -> Int { x = 2 return 2 }
(edited)x = 3
の瞬間が削除されていることとreturn x
じゃなくて return 2
になっていることがポイントx=3
が観測できないし、 どんだけ x
に書き込んでも、 固定で 2
が返ってくるx = 3
が削除されるのは問題になりうる。a
が atomic な挙動をしているだけだと思うんだけど、 (edited)int data = 0; volatile int flag = 0; // 生産側スレッド void producer_thread() { data = 42; // [A] flag = 1; // [B] ??? } // 消費側スレッド void consumer_thread() { while ( !flag ) {} // [C] assert(data == 42); // [D] ??? }
(edited)func a() { lock.sync { atomicFoo(42) } } func b() { lock.sync { atomicFoo(999) } }
の lock
はいらないよね?ということでdata
を読んだ時に、0か42以外の中途半端にビットが書き換わった変な数字になったり、CPUがぶっ壊れたりしない、としてもfunc a() { lock.sync { atomicFoo(42) } } func b() { lock.sync { atomicFoo(999) } }
これ自体はlockはいらない。Int
を同時に更新する(だけ)みたいなのでも同期が必要となると想定していないケースが多そうということです。lock
が不要だったらうれしい。 var x: Int = 42 func a() { lock.sync { x = 999 } } func b() { lock.sync { x = 888 } }
(edited)let x = LargeSizeValue() f1(x) f2(x) f3(x)
let
だからそのまま渡せるのかfunc consume1(_ b: BigStruct) { consume2(b) } func consume2(_ b: BigStruct) { consume3(b) } func consume3(_ b: BigStruct) { consume4(b) } func consume4(_ b: BigStruct) { print(b) }
極端だけどこういう場合。 (edited)func consume1(_ b: P) { consume2(b) } func consume2(_ b: P) { consume3(b) } func consume3(_ b: P) { consume4(b) } func consume4(_ b: P) { print(b) } extension BigStruct: P {}
こうしたほうが速そう。結局のところ Swift4 の Existential CoW はヒープに 25 バイト以上のデカい構造体を alloc/initialize/dealloc するより参照カウンタ操作の方が速いってだけなのかな?
は Swift 3 vs Swift 4 の話ではない??func consume1<T: P>(_ b: T) { consume2(b) } func consume2<T: P>(_ b: T) { consume3(b) } func consume3<T: P>(_ b: T) { consume4(b) } func consume4<T: P>(_ b: T) { print(b) } extension BigStruct: P {}
// 1.swift protocol Hogeable { func hoge() -> Int } struct HogeCat: Hogeable { func hoge() -> Int { return 1111 } } func callHogeableHoge(hogeable: Hogeable) -> Int { return hogeable.hoge() } func callCatHoge(cat: HogeCat) -> Int { return callHogeableHoge(cat) } print(callCatHoge(HogeCat()))
callHogeableHoge
nofunc foo(_ a: P, _ b: P) { ... } extension Int: P {} extension String: P {} foo(2, 3) // スペシャライズされる foo(2, "abc") // スペシャライズされない
@_specialize
付けなくてもスペシャライズって起こるんだっけ?func consume1(_ b: P) { consume2(b) } func consume2(_ b: P) { consume3(b) } func consume3(_ b: P) { consume4(b) } func consume4(_ b: P) { print(b) } extension BigStruct: P {} こうしたほうが速そう。
↑これでいけそうですfunc consume1(_ b: shared BigStruct) { }
void consume1(const BigStruct & b)
と同じ意味func consume1(_ b: inout BigStruct) { consume2(&b) } func consume2(_ b: inout BigStruct) { consume3(&b) } func consume3(_ b: inout BigStruct) { consume4(&b) } func consume4(_ b: inout BigStruct) { print(b) } extension BigStruct: P {}
(edited)var x = BigStruct() compose(consume1(&x), consume1(&x))
std::atomic
で実現されてました。 struct HeapObject に フィールド InlineRefCounts refCounts がある。 https://github.com/apple/swift/blob/b7d78853112c1279fc7bc5b85853779040f13703/stdlib/public/SwiftShims/HeapObject.h InlineRefCounts は RefCounts<InlineRefCountBits> のエイリアス class RefCounts<T> は フィールド std::atomic<T> を持ってる。 デクリメント処理はなんかいろいろあるけど doDecrement
が基本的なやつっぽくて、 分岐もいろいろ複雑なんだけどstd::atomicのcompare_exchange_weakを呼び出してたりする。 InlineRefCountBits は RefCountBitsT<RefCountIsInline> のエイリアス RefCountIsInline は true な定数 RefCountBitsTはカウンタに加えて動作に関するビットが5こぐらいくっついたよくわからんやつ。 https://github.com/apple/swift/blob/b7d78853112c1279fc7bc5b85853779040f13703/stdlib/public/SwiftShims/RefCount.hthe-sharing-economy
wSwift Static Analysis@Apple Cupertino, CA
https://twitter.com/CodaFi_Math@CMU 2019
どういうこと?未来人??val
( Swift の let
に相当)で interface
のプロパティ宣言して、具象クラス側で Computed property にできるよね・・・。mutating
を一つももたないクラスはイミュータブルクラスになる。 mutable class Foo { func bar() -> Bar {} mutating func baz() -> Baz {} }
(edited)mutating
を作ろうとするとコンパイルエラー。mutating
みたときは、これはもしかして?と思ったけどちょっと違った。けど、結局値型中心で考える方がセンスがいいと思う。pure
について言及されてて、 D 言語はよく知らないですが、、 pure
な方がデフォルトであるのがいいと思うのと、これを型にも広げられないんだったら効果半減だと思います。let
なプロパティを Computed Property としてオーバーライドできないという制約はあるから、「もともと let な stored property だったものを、後から computed property の getter に差し替えても」動くとはいえ意図的に区別して制約が課されてるんじゃないかな?interface A { val value: Int } class A1: A { override val value: Int get() = A1.getCurrent() companion object { var value: Int = 0 fun getCurrent(): Int { value += 1 return value } } } fun main(args : Array<String>) { val a1 = A1() println(a1.value) println(a1.value) }
let
in protocols https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170619/037676.htmlprotocol
で nested type 作れないのって何か理由があるんですっけ?名前空間的に、その protocol
でしか使わない型をネストしたい・・・。protocol Foo { var bar: Bar { get } struct Bar { ... } }
みたいな (edited)protocol
の内側に static func
をかいたとき、それは、 Foo.hoge()
と呼び出せるわけじゃなくてFoo
に関連したいくつかのパラメータをまとめた Bar
を作りたいけど、 Bar
は Foo
から独立したら意味を持たない型なのでネストしたいって感じです。struct Bar<F: Foo>
を作るのが筋良さそうprotocol Foo { typealias Bar = FooBar var a: Bar { get } } struct FooBar { } struct FooImpl: Foo { var a: Foo.Bar }
Foo
の異なる具象型間で Bar
をやりとりできないですよね?_FooBar
にしておけばありかもしれないなぁ。 1> protocol Foo { 2. typealias Bar = FooBar 3. var a: Bar { get } 4. } 5. 6. struct FooBar { 7. 8. } 9> let bar: Foo.Bar = Foo.Bar() error: repl.swift:9:27: error: cannot call value of non-function type 'Foo.Bar' (aka 'FooBar') let bar: Foo.Bar = Foo.Bar() ~~~~~~~^~
typealias
はデフォルトではないのでは?associatedtype
にしてデフォルト設定するんじゃないっけ? =
で指定しておいた型になるんじゃなかったっけstruct FooBar {} protocol Foo { associatedtype Bar } extension Foo { typealias Bar = FooBar }
struct FooBar {} protocol Foo { typealias Bar = FooBar }
struct P0Param {} protocol P0 { typealias Param = P0Param var a: Param { get set } } var a = P0.Param() print(a)
1> protocol Foo { 2. typealias Bar = FooBar 3. var a: Bar { get } 4. } 5. 6. struct FooBar { 7. 8. } 9> let bar: Foo.Bar = Foo.Bar()
typealias
in protocol
swift-4.0-branch-07-11-2017
https://github.com/apple/swift/tree/swift-4.0-branch-07-11-2017 みたいなブランチからビルドされてたぽいだけど、beta 5はどこからビルドされているのだろう? (edited)swift-4.0-branch-07-11-2017
みたいなスナップショットが出ると、discordで報告していて、swift-4.0-DEVELOPMENT-SNAPSHOT-2017-08-02-a
以降 swift-4.0-DEVELOPMENT-SNAPSHOT-2017-08-04-a
より前 ぽい。 (edited)Copy-On-Write (🐮) types like Array and String are sharable
リファレンスカウントとCOWはスレッドセーフだけど Array
そのものの操作はスレッドセーフではない?async
, await
出す前に来てしまった・・・。Concurrency is a broad and sweeping concept that can cover a wide range of topics. To help scope this down a bit, here are some non-goals for this proposal: - We are focusing on task based concurrency, not data parallelism. This is why we focus on GCD and threads as the baseline, while completely ignoring SIMD vectorization, data parallel for loops, etc. - In the systems programming context, it is important for Swift developers to have low-level opt-in access to something like the C or C++ memory consistency model. This is definitely interesting to push forward, but is orthogonal to this work. - We are not discussing APIs to improve existing concurrency patterns (e.g. atomic integers, better GCD APIs, etc).
UIImage(named:)
が挙げられてるんだけど、このレベルの API から非同期化するつもりなのかな? C# の世界みたいになりそう。async
が良さそう。throws
って言ってるのと同じ気がする。can of worms
って出てきてなんだ?と思ったら↓のような意味の表現らしい。 UIImage(named:)
にまで踏み込むなら、 pure Swift UI ライブラリもワンチャンあるかも?you should only have to teach your types how to serialize/🐟 themselves
fish
なんだよなあSpeaking of reliable systems, introducing an actor model is a good opportunity and excuse to introduce a mechanism for handling and partially recovering from runtime failures (like failed force-unwrap operations, out-of-bounds array accesses, etc). We explore several options that are possible to implement and make a recommendation that we think will be a good for for UI and server applications.
async
/ await
まで来た。async
と、呼び出しの await は (Int) -> Int // #1: Normal function (Int) throws -> Int // #2: Throwing function (Int) async -> Int // #3: Asynchronous function (Int) async throws -> Int // #4: Asynchronous function, can also throw.
reasync
がなさそうだから swift-evolution に書いておくか。await!
もほしいな。!
を使うのが良いのか自信がない。 actor TableModel { let mainActor : TheMainActor var theList : [String] = [] { didSet { mainActor.updateTableView(theList) } } init(mainActor: TheMainActor) { self.mainActor = mainActor } // this checks to see if all the entries in the list are capitalized: // if so, it capitalize the string before returning it to encourage // capitalization consistency in the list. func prettify(_ x : String) -> String { // ... details omitted, it just pokes theList directly ... } actor func add(entry: String) { theList.append(prettify(entry)) } }
reliable actor Notifier { ... } reliable actor class Notifier { ... }
distributed actor MyDistributedCache { ... } distributed actor class MyDistributedCache { ... }
func queueHopping() async -> Void { doSomeStuff() await DispatchQueue.main.syncCoroutine() doSomeStuffOnMainThread() await backgroundQueue.asyncCoroutine() doSomeStuffInBackground() }
/// Begins an asynchronous coroutine, transferring control to `body` until it /// either suspends itself for the first time with `suspendAsync` or completes, /// at which point `beginAsync` returns. If the async process completes by /// throwing an error before suspending itself, `beginAsync` rethrows the error. func beginAsync(_ body: () async throws -> Void) rethrows -> Void
↑の戻り値ってなんで T
じゃないの?@IBAction func buttonDidClick(sender:AnyObject) { // 1 beginAsync { // 2 let image = await processImage() imageView.image = image } // 3 }
rethrows
はどこで活躍するの?If the async process completes by throwing an error before suspending itself, `beginAsync` rethrows the error.
suspendAsync
は func suspendAsync<T>( _ body: (_ continuation: @escaping (T) throws -> ()) -> () ) async rethrows -> T
じゃないんだ??throws
の位置がおかしいかfunc suspendAsync<T>( _ body: (_ continuation: @escaping (T) -> ()) throws -> () ) async rethrows -> T
// Legacy callback-based API func getStuff(completion: (Stuff) -> Void) { ... } // Swift wrapper func getStuff() async -> Stuff { return await suspendAsync { continuation in getStuff(completion: continuation) } }
asynchronize
が間違ってるっぽいな。func suspendAsync<T>( _ body: (_ continuation: @escaping (T) -> ()) -> ()) async -> T func asynchronize(_ operation: ((T) throws -> ()) -> ()) async rethrows -> T // ラベル等を消すと func suspendAsync<T>( _ body: ((T) -> ()) -> ()) async -> T
(edited)(T) throws -> ()
があるけど、() throws -> T
じゃないと。func asynchronize(_ operation: ((() throws -> T) -> ()) -> ()) async rethrows -> T
func suspendAsync<T>( _ body: (_ continuation: @escaping (() throws -> T) -> ()) -> ()) async -> T
return await suspendAsync { continuation, error in awaiters.append({ switch $0 { case .error(let e): error(e) case .value(let v): continuation(v) } }) }
が return await suspendAsync { continuation in awaiters.append({ switch $0 { case .error(let e): continuation { throw e } case .value(let v): continuation { v } } }) }
になる。pass
みたい。async
await
じゃなくて yields
と yield
にするって選択肢についても書かれてますねasync
/ await
は必ずしも意味が正しくないんよね。async(nonthrowing)
を導入するasync(nonthrowing)
より async nonthrows
とかの方がいいな。 nonthrows
は英語的におかしそうだけど。nothorw
があるよthrows
がよくなかった気がするな。 Java のせいだけど。throwing func
とか async func
とかの方が英語的によかったかも。 (edited)nonthrowing func
だったら nonmutating func
とかとも整合するし。do { let a = await foo() let b = await bar(a) ... } wait
reasync
await!
もいいけど、まとめてブロックも必要かと。Blocking calls Affordances could be added to better call blocking APIs from async functions and to hard wait for an async function to complete. There are significant tradeoffs and wide open design space to explore here, and none of it is necessary for the base proposal.
let a = await foo() let b = await bar()
のときに foo
と bar
を並列に走らせるのか直列に走らせるのかはどうだろう?func processImageData1a() async -> Image { let dataResource = Future { await loadWebResource("dataprofile.txt") } let imageResource = Future { await loadWebResource("imagedata.dat") } // ... other stuff can go here to cover load latency... let imageTmp = await decodeImage(dataResource.get(), imageResource.get()) let imageResult = await dewarpAndCleanupImage(imageTmp) return imageResult }
beginAsync
していてget() async throws -> T
なのでasync/awai
に続いて Typed throws も。 Error
が existential だからパフォーマンスが、ってことが書かれていて興味深い。One thing that I’m personally very concerned about is in the systems programming domain. Systems code is sort of the classic example of code that is low-level enough and finely specified enough that there are lots of knowable things, including the failure modes. Beyond expressivity though, our current model involves boxing thrown values into an Error existential, something that forces an implicit memory allocation when the value is large. Unless this is fixed, I’m very concerned that we’ll end up with a situation where certain kinds of systems code (i.e., that which cares about real time guarantees) will not be able to use error handling at all.
JohnMC has some ideas on how to change code generation for ‘throws’ to avoid this problem, but I don’t understand his ideas enough to know if they are practical and likely to happen or not.
で、 Chris Lattner のこのメールに John McCall が返信してるから、それ見たらわかるかも。This combination of requirements means that all operations must be implicitly "unwindable" starting from almost any call site it makes. For the stability of the system, this unwinding process must restore any invariants that might have been temporarily violated; but the compiler cannot assist the programmer in this. The programmer must consciously recognize that an error is possible while an invariant is broken, and they must do this proactively --- that, or track it down when they inevitably forget. This requires thinking quite rigorously about one's code, both to foresee all the error sites and to recognize that an important invariant is in flux. How much of a problem this poses depends quite a lot on the code being written. There are some styles of programming that make it pretty innocuous. For example, a highly functional program which conscientiously kept mutation and side-effects to its outermost loops would naturally have very few points where any invariants were in flux; propagating an error out of an arbitrary place within an operation would simply abandon all the work done up to that point. However, this happy state falls apart quite quickly the more that mutation and other side-effects come into play. Complex mutations cannot be trivially reversed. Packets cannot be unsent. And it would be quite amazing for us to assert that code shouldn't be written that way, understanding nothing else about it. As long as programmers do face these issues, the language has some responsibility to help them.
More generally, by modeling both `throws` and `async` as effects on function types, we can eventually provide common abstraction tools to abstract over both effects in protocols and generic code
https://gist.github.com/lattner/429b9070918248274f25b714dcfc7619#rethrows-could-be-generalized-to-support-potentially-async-operationseffects
ってのが専門用語を匂わせてる気がするawait try
と書いてたけど、プロポーザル通り try await
じゃないといけない気がしてきた。try
も await
も flatMap
と等価でモナドを剥がすわけだけど、 async throws
は Promise
が外側だからまず Promise
を剥がさないといけず、その後 Result
を剥がすと考えると try await
じゃないとおかしい。beginAsync
の rethrows
と body
の throws
ってやっぱダメじゃない?I agree. I think `rethorws` for `beginAsync` is problematic. For example, what happens when the `foo` in the following code throws an `Error` asynchronously? func foo() async throws { ... } beginAsync(foo) `foo` is acceptable as `beginAsync`'s `body` by its type. However its error might be thrown asynchronously and it is impossible to rethrow it. So the error must be ignored or treated as an universal error by untyped propagation. It breaks type safety about error handling. So I think the signature of `beginAsync` should be the following one. func beginAsync(_ body: () async -> Void) -> Void
beginAsync
rethrows the error.await!
についても違う方向で話されてたから blocking のことに言及してみた。 https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170814/039096.htmlasync(nonthrowing)
おもしろいけど、それをやっちゃうと throws
, async
に続く第三のエフェクトを導入したときに整合性をとるのに困ると思う。async/await
の Proposal と同じような内容が話されてる。 https://gist.github.com/koher/5cd16adac7a62b6d3eb0b910ccc13534import Accelerate extension Array where Element: Comparable { mutating func clip(low: Element, high: Element) { print("normal version") for i in 0..<self.count { self[i] = Swift.max(Swift.min(self[i], high), low) } } @_specialize(Float) func clipped(low: Element, high: Element) -> [Element] { var ret = self ret.clip(low: low, high: high) return ret } } extension Array where Element == Float { mutating func clip(low: Float, high: Float) { print("accelerate version") var low = low var high = high self.withUnsafeMutableBufferPointer { bp in let p = bp.baseAddress! vDSP_vclip(p, 1, &low, &high, p, 1, vDSP_Length(bp.count)) } } } var int = (0..<10).map { Int($0) } int.clipped(low: 3, high: 5) // normal version int.clip(low: 3, high: 5) // normal version var x = (0..<10).map { Float($0) } x.clipped(low: 3, high: 5) // normal version x.clip(low: 3, high: 5) // acceerate version
Float
用のclipped
を多重実装せずにaccelerate versionを呼べないかと思ってるんですが@_specialize
でもだめっぽい…… (edited)@_specialize
ってそのメソッドや関数の型パラメータに利くんじゃないっけ?private func
化して@_specialize
付けるとか?protocol ArrayClippable
を用意してprotocol ArrayClippable { static func clipArray(_ array: inout Array<Self>, min: Self, max: Self) } extension ArrayClippable { static func clippedArray(_ array: Array<Self>, min: Self, max: Self) -> Array<Self> { var ret = array Self.clipArray(&ret, min: min, max: max) return ret } } extension Array where Element : ArrayClippable { mutating func clip(min: Element, max: Element) { Element.clipArray(&self, min: min, max: max) } func clipped(min: Element, max: Element) -> Array<Element> { return Element.clippedArray(self, min: min, max: max) } }
extension Comparable : ArrayClippable { static func clipArray(_ array: inout Array<Self>, min: Self, max: Self) { // ... } }
@_specialize
で呼び分けるのは無理なんじゃないかな?Playground execution failed: error: MyPlayground.playground:10:1: error: extension of protocol 'Comparable' cannot have an inheritance clause extension Comparable: ArrayClippable { ^ ~~~~~~~~~~~~~~
つけられない?@_specialize について、 _ で始まるものは本当に使わないほうがいいです。意図的にやっているのかっていうくらい頻繁に仕様が変わります。
by @rintarostruct S<T> { var x: T @_specialize(where T == Int, U == Float) mutating func exchangeSecond<U>(_ u: U, _ t: T) -> (U, T) { x = t return (u, x) } }
_
に限らず破壊的変更がどのみち入るから(struct S<T> { var x: T mutating func exchangeSecond<U>(_ u: U, _ t: T) -> (U, T) { x = t return (u, x) } } extension S where T == Float { mutating func exchangeSecond(_ u: Int, _ t: Float) -> (Int, Float){ x = t return (u, x) } }
@_specialize
をなくせば動きはするしね。@_specialize
では無理だと思う。MyArray
とMyArray2
なんですが、同じテストコードでモジュール外にあるMyArray
の方が数百倍遅くて原因が分かりません。 モジュールまたぐ時ってwhole module optimization以外何かありましたっけ?makeIterator
はCollection
に生えているのが使えるのでMyArray
とおなじところにMyFloatArray
を作ってためしましたArray
に詰めたいけれど型が不定だと初期値をどうするのやらFloat
に対して付けるんじゃないの?import Foundation var data = Data(bytes: [0x50, 0x4B, 0x01, 0x02, 0x41, 0x61]) data.removeFirst() print(data.startIndex) // swift-3.1: "0\n", swift-4.0: "1\n" data.customMirror // crash on swift-4.0 https://bugs.swift.org/browse/SR-5811
(edited)self[0..<nBytes]
ってやってるからw https://github.com/apple/swift/blob/master/stdlib/public/SDK/Foundation/Data.swift#L1773 (edited)Data
の件、 Array
と挙動が違って混乱を招くかも? Welcome to Apple Swift version 4.0 (swiftlang-900.0.59 clang-900.0.34.2). Type :help for assistance. 1> var array = [2, 3, 5] array: [Int] = 3 values { [0] = 2 [1] = 3 [2] = 5 } 2> print(array.startIndex) 0 3> array.removeFirst() $R0: Int = 2 4> print(array.startIndex) 0
subscript
の index
は startIndex
が最初の要素を指すよ。 1> import Foundation 2> var data = Data(bytes: [2, 3, 5]) 3> print(data.startIndex) 0 4> data.removeFirst() $R0: UInt8 = 2 5> print(data.startIndex) 1 6> print(data[1]) 3
(edited)Array
は必ず startIndex
が 0
で endIndex
が count - 1
として、わざわざ ArraySlice
という型を設けて分離しているのに対して Data
は一つの型でやってしまっていることとremoveFirst
が startIndex
に影響を及ぼすのか及ぼさないのかという仕様の違いをどっちも混ぜてしまったのが問題では。 1> var ns: ArraySlice<Int> = [2, 3, 5] ns: ArraySlice<Int> = 3 values { [0] = 2 [1] = 3 [2] = 5 } 2> print(ns.startIndex) 0 3> ns.removeFirst() $R0: Int = 2 4> print(ns.startIndex) 1
ArraySlice
とは一貫してるのかData
は最初からスライスだと考えれば良いのか。Data
はそういうのとは違うからInt
で適切だと思う。String
より遅いけど、計算量のオーダーは同じ。String
インスタンスを作るのと大して変わらない。String
から構築してるからString
がヒープに確保してるでっかい領域をCharacter
が参照してるだけになるのでは?String
から characters
を取り出したときに内部的にどうなってるか詳しいことはしらない。String
より EasyText の Text
の方が速そう。String
がややこしいこと考えずに書記素クラスタで扱えるのはとても良いと思う。$ swift Welcome to Apple Swift version 4.0 (swiftlang-900.0.63.10 clang-900.0.36). Type :help for assistance. 1> : (lldb) script Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D. >>> [x * x for x in range(10)] [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] >>>
[omochi@omochi-iMac SwiftSyntax (master *=)]$ swift Welcome to Apple Swift version 4.0 (swiftlang-900.0.63.10 clang-900.0.36). Type :help for assistance. 1> : (lldb) script Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D. >>> 3 + 3 6 >>> exit (lldb) ^D 1> ^D
>>> ^D (lldb) ^D 1> ^D $
var exit: Never
みたいなの生やせばexitで抜けれるようになるかしら$ swift Welcome to Apple Swift version 4.0 (swiftlang-900.0.63.10 clang-900.0.36). Type :help for assistance. 1> import Darwin 2> exit(0) REPL requires a running target process. error: REPL process is no longer alive, exiting REPL
なら抜けられる。 (edited)struct Hoge { var foo: Int = 0 var bar: Int = 0 } var hoge: Hoge = Hoge() { didSet { print("didSet") } }
みたいな、監視されている struct 値を更新するときに hoge.foo = 12 hoge.bar = 13
(edited) _ = { $0.foo = 12 $0.bar = 13 }(&hoge)
っていう方法よりシンプルでわかりやすいのってありますか?(hoge.foo, hoge.bar) = (12, 13)
これもだめ hoge.mutate
メソッドを生やしたら少し分かりやすいかも?protocol Mutable { } extension Mutable { mutating func mutate(_ f: (inout Self)->Void) { f(&self) } } struct Hoge: Mutable { var foo: Int = 0 var bar: Int = 0 }
(edited) hoge.mutate { $0.foo = 12 $0.bar = 13 }
いいかも、使わせていただきまっす!Mutable
プロトコルは名前が不自然なのでそこだけ変えて下さいwRxSwift.Variable
に使いたかっただけなのでこんな感じにしました。 extension RxSwift.Variable { func mutateValue(fn: (inout Element) -> Void) { fn(&value) } }
variable.value.foo = xxx
をマルチスレッドでやらかすと死ねるdidSet
の場合もですけど冪等に作っておいて多重実行は気にしないのが良いんですかね……extension RxSwift.Variable { func mutateValue(fn: (inout Element) -> Void) { _lock.lock() fn(&value) _lock.unlock() } }
できるかな?こんな感じが良さそう。[T1: BinaryFloatingPoint]
を[T2: BinaryInteger]
に変換するメソッドが書けるようになって喜んでたら [T1: BinaryInteger]
を[T2: BinaryFloatingPoint]
に変換するほうができなかったSignedInteger
とUnsignedInteger
に分けてそれぞれInt64
, UInt64
を経由して変換するというろくでもない方法に落ち着いてしまったfatal error: Array<Foo> does not conform to Encodable because Pedestrian does not conform to Encodable.:
(edited)Countable...Range
を一掃できるのもうれしい。Codable
のエラーメッセージがどうなってるかは知らないけど、原理的にはパスをたどれそうな気がする。エラーが throw
されてきたら素通しにせず、一度 catch
してからエラーメッセージにパスを追記して throw
しなおせばいいんじゃない?そうなってなかったら swift リポジトリへの PR チャンスかも?Encoder
, Decoder
のエラーに含まれるパスは「とりあえずあるレベル」だと記憶。 (edited)Decoder
につけなきゃいけないのか。=>
の inout
版がほしい気がしてきた。func =><T>(lhs: T, rhs: (inout T) throws -> ()) rethrows -> T { var value = lhs try rhs(&value) return value }
(edited)func =><T, U>(lhs: T, rhs: (T) throws -> U) rethrows -> U { return try rhs(lhs) }
var teamToCount: [String: Int] = [:] for user in users { let team = user.team if let count = teamToCount[team] { teamToCount[team] = count + 1 } else { teamToCount[team] = 1 } }
を、もし inout
版の =>
があれば reduce(into:_:)
を使わなくても let teamToCount: [String: Int] = [:] => { teamToCount in for user in users { teamToCount[user.team, default: 0] += 1 } }
って書けそうだなぁと。Codable
など劇的にコーディングが楽になる新機能だと思いますが、ちょっとした便利な小技もあります。 そんな、 Swift 4 の小技の魅力の一面を 3 行...infix operator => : SwifletPrecedence precedencegroup SwifletPrecedence { higherThan: AssignmentPrecedence associativity: left } func =><T>(lhs: T, rhs: (inout T) throws -> ()) rethrows -> T { var value = lhs try rhs(&value) return value } print([Int]() => { (a: [Int]) -> () in a.append(42) })
$ swift inout-let.swift inout-let.swift:14:40: error: value of type 'Any' has no member 'append' print([Int]() => { (a: [Int]) -> () in a.append(42) }) ^ ~~~~~~ inout-let.swift:14:40: note: cast 'Any' to 'AnyObject' or use 'as!' to force downcast to a more specific type to access members print([Int]() => { (a: [Int]) -> () in a.append(42) }) ^ ( as AnyObject)
(edited){ (a: inout [Int]) -> () in a.append(42) }
クロージャパラメータに inout が必要inout
がいるんですね・・・。考えてみれば当たり前だ。infix operator => : SwifletPrecedence precedencegroup SwifletPrecedence { higherThan: AssignmentPrecedence associativity: left } func =><T>(lhs: T, rhs: (inout T) throws -> ()) rethrows -> T { var value = lhs try rhs(&value) return value } print([Int]() => { (a: inout [Int]) -> () in a.append(42) }) print([Int]() => { a in a.append(42) }) print([Int]() => { $0.append(42) })
$ swift inout-let.swift inout-let.swift:15:25: error: value of type 'Any' has no member 'append' print([Int]() => { a in a.append(42) }) ^ ~~~~~~ inout-let.swift:15:25: note: cast 'Any' to 'AnyObject' or use 'as!' to force downcast to a more specific type to access members print([Int]() => { a in a.append(42) }) ^ ( as AnyObject) inout-let.swift:16:20: error: value of type 'Any' has no member 'append' print([Int]() => { $0.append(42) }) ^~ ~~~~~~ inout-let.swift:16:20: note: cast 'Any' to 'AnyObject' or use 'as!' to force downcast to a more specific type to access members print([Int]() => { $0.append(42) }) ^ ( as AnyObject)
$ swift --version Apple Swift version 4.0 (swiftlang-900.0.63.10 clang-900.0.36) Target: x86_64-apple-macosx10.9
reduce(into:_:)
だとうまく推論できたのも謎。// 型の準備 struct User { var team: String } // 値の準備 let users = [ User(team: "A"), User(team: "B"), User(team: "B"), User(team: "A"), User(team: "C"), User(team: "A"), User(team: "C"), User(team: "B"), User(team: "D"), User(team: "A"), ] // 集計 let teamToCount: [String: Int] = users.reduce(into: [:]) { teamToCount, user in teamToCount[user.team, default: 0] += 1 } // 出力 for (team, count) in (teamToCount.sorted { $0.key < $1.key }) { print("\(team): \(count)") }
teamToCount
が inout
なんですが、問題なく通ります。reduce(into:_:)
と違うのは inout
の後の第二引数があるかないかくらいな気がするけど・・・ func parseImportDecl(tokens: ArraySlice<TokenSyntax>) throws -> (decl: ImportDecl, rest: ArraySlice<TokenSyntax>)? { var index = tokens.startIndex ... return (decl: ImportDecl(keywordIndex: keywordIndex - tokens.startIndex, nameIndex: nameIndex - tokens.startIndex, tokens: Array(tokens[..<index])), rest: tokens[index...]) }
(edited)echo 'Dictionary(uniqueKeysWithValues: ["a","b","c"].enumerated())'|TOOLCHAINS=swift swiftc -
でswiftc
がクラッシュする。export TOOLCHAINS=org.swift.3020170918a
Dictionary(uniqueKeysWithValues: ["a","b","c"].enumerated().filter { $1 != "a" })
もクラッシュ。Dictionary(uniqueKeysWithValues: ["a","b","c"].enumerated().filter { $1 != "a" }.map { ($0, $1) })
でクラッシュ回避。.map { $0 }
でもいけますね 3> Dictionary(uniqueKeysWithValues: [(offset: 0, element: "a")]) $R2: [Int : String] = 1 key/value pair { [0] = { key = 0 value = "a" } }
Dictionary(uniqueKeysWithValues: ["a","b","c"].enumerated().lazy)
は別の形でクラッシュecho 'Dictionary(uniqueKeysWithValues: ["a","b","c"].enumerated())'|TOOLCHAINS=swift swiftc -でswiftcがクラッシュする。
swift-DEVELOPMENT-SNAPSHOT-2017-09-28-a
で直った。[swift-evolution] Idea: Public Access Modifier Respected in Type Definition The core team would only consider a refinement or change to access control if there were something actively broken that mattered for ABI stability. -Chris
$ swift Welcome to Apple Swift version 4.0 (swiftlang-900.0.63.10 clang-900.0.36). Type :help for assistance. 1> class Animal {} 2> class Cat: Animal {} 3> let a: () -> Cat = { Cat () } a: () -> Cat = 0x00000001000c5590 $__lldb_expr7`closure #1 () -> __lldb_expr_3.Cat in __lldb_expr_6 at repl.swift:3 4> let b: () -> Animal = a b: () -> Animal = 0x00000001000c5590 $__lldb_expr7`closure #1 () -> __lldb_expr_3.Cat in __lldb_expr_6 at repl.swift:3 5> let c: () -> [Cat] = { [Cat()] } c: () -> [Cat] = 0x00000001000c5680 $__lldb_expr11`closure #1 () -> Swift.Array<__lldb_expr_3.Cat> in __lldb_expr_10 at repl.swift:5 6> let d: () -> [Animal] = c error: repl.swift:6:25: error: cannot convert value of type '() -> [Cat]' to specified type '() -> [Animal]' let d: () -> [Animal] = c ^ 6> let e: [Cat] = [Cat()] e: [Cat] = 1 value { [0] = { __lldb_expr_1.Animal = {} } } 7> e is [Animal] $R0: Bool = true
is
は 真になるのに、関数型に組み込まれたときはその互換性が発揮されないclass Animal {} class Cat: Animal {} let a: () -> Cat = { Cat () } let b: () -> Animal = a // OK let c: () -> [Cat] = { [Cat()] } let d: () -> [Animal] = c // NG: error: cannot convert value of type '() -> [Cat]' to specified type '() -> [Animal]' let e: [Cat] = [Cat()] e is [Animal] // true
let f: () -> Cat? = { Cat() } let g: () -> Animal? = f // OK
こっちはできたwis
の振る舞いってdo { let a: (Animal) -> () = { _ in } let b: (Cat) -> () = a // OK } do { let a: ([Animal]) -> () = { _ in } let b: ([Cat]) -> () = a // error: cannot convert value of type '([Animal]) -> ()' to specified type } do { let a: (Animal?) -> () = { _ in } let b: (Cat?) -> () = a // OK }
do { let a: () -> () -> Cat = { { Cat() } } let b: () -> () -> Animal = a // OK } do { let a: () -> () -> [Cat] = { { [Cat()] } } let b: () -> () -> [Animal] = a // error: cannot convert value of type '() -> () -> [Cat]' to specified type '() -> () -> [Animal]' } do { let a: () -> () -> Cat? = { { Cat() } } let b: () -> () -> Animal? = a // OK }
Array
だけ壊れてるみたいdo { let a: [String: Cat] = ["": Cat()] let b: [String: Animal] = a // OK } do { let a: [String: [Cat]] = ["": [Cat()]] let b: [String: [Animal]] = a // OK } do { let a: [String: Cat?] = ["": Cat()] let b: [String: Animal?] = a // OK }
as
, is
をoperatorにしてユーザーが定義できる様にして欲しくなる話だね。do { let a: () -> [String: Cat] = { ["": Cat()] } let b: () -> [String: Animal] = a // error: cannot convert value of type '() -> [String : Cat]' to specified type '() -> [String : Animal]' }
代入文の型検査時は静的だから書き換えたisが評価できない
func as(lhs: A) -> B
の有無で決まるとか? (edited)func as<T, U>(_ v: My<T>) -> My<U> where U: T
こういうの。無くても出来るかな?class Box<out T>
とかやるのが楽だしわかりやすいとは思うけどstruct Box<T> { let value: T }
T
についての変性をどう扱うのかが気になってます。rintaro - 04/18/2017 この辺の話(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) らしいのですが、どういうケースなんでしょう?
protocool Foo: class
はできるけど、逆は出来ない。[Int]
とかってboxingしないメモリレイアウトじゃないんか??unsafeBitCast([Int](), [String].self)
これ動きそう 1> var a: [Int] = [0,1,2,3] a: [Int] = 4 values { [0] = 0 [1] = 1 [2] = 2 [3] = 3 } 2> var b: [String] = a as! [String] Could not cast value of type 'Swift.Int' (0x1013e0430) to 'Swift.String' (0x1013e36f8). 2017-10-06 11:35:18.511301+0900 repl_swift[28561:24355268] Could not cast value of type 'Swift.Int' (0x1013e0430) to 'Swift.String' (0x1013e36f8). b: [String] = <extracting data from value failed> Execution interrupted. Enter code to recover and continue. Enter LLDB commands to investigate (type :help for assistance.) Process 28561 stopped * thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGABRT frame #0: 0x00007fffc4cf5d42 libsystem_kernel.dylib`__pthread_kill + 10 libsystem_kernel.dylib`__pthread_kill: -> 0x7fffc4cf5d42 <+10>: jae 0x7fffc4cf5d4c ; <+20> 0x7fffc4cf5d44 <+12>: movq %rax, %rdi 0x7fffc4cf5d47 <+15>: jmp 0x7fffc4ceecaf ; cerror_nocancel 0x7fffc4cf5d4c <+20>: retq Target 0: (repl_swift) stopped.
class Animal {} class Cat: Animal {} let a: [[Cat]] = [[Cat()]] a is [[Animal]] // true
true
になるんだっけis
の検査と as
の成功が一致してないといけないのか。is
はあくまでインスタンスをチェックしてるだけで式の型を調べているわけではないと。 (edited) 1> let a: [Int] = [] a: [Int] = 0 values 2> type(of: a) $R0: [Int].Type = [Int]
1> let a: [Int] = [] a: [Int] = 0 values 2> type(of: a) $R0: [Int].Type = [Int] 3> func foo<T>(_ value: T) { 4. print(type(of: value)) 5. } 6> foo(a) Array<Int>
let cats: [Cat] = [Cat()] let animals: [Animal] = cats
一瞬、↑みたいなケースで cats
は animals
にコピーされないからインスタンスの型という概念が成り立たないかと思ったけど、コピーされないのはあくまでバッファであって、インスタンス自体の領域は別だからやっぱりインスタンスの型で判断できる気がする。animals
から cats
に as
で戻せなくなるのか。 (edited)Optional
の is
や as
もややこしくなるな・・・。final class _EmptyArrayStorage : _ContiguousArrayStorageBase { } final class _ContiguousArrayStorage<Element> : _ContiguousArrayStorageBase { }
// rawValue is passed inout to _isUnique. Although its value // is unchanged, it must appear mutable to the optimizer. @_versioned internal var rawValue: Builtin.BridgeObject
@_inlineable // FIXME(sil-serialize-all) public // @testable var nativeInstance: Native { @inline(__always) get { _sanityCheck(isNative) return Builtin.castReferenceFromBridgeObject(rawValue) } }
var objCInstance: ObjC { @inline(__always) get { _sanityCheck(isObjC) return Builtin.castReferenceFromBridgeObject(rawValue) } }
internal typealias _ArrayBridgeStorage = _BridgeStorage<_ContiguousArrayStorageBase, _NSArrayCore>
で、左側が さっきの pure swift のときの Storage の _ContiguousArrayStorageBase だから、as
とかでObjC側にブリッジしたりするときにめんどくさいことが起こるんだろう・・・[Animal] as? [Cat]
これを実現するためには、1要素毎にキャストして成功したらOKみたいな処理にする必要があってvar a: [Int] = [] var b: [String] = [] print(a == b)
これで結論が出ると思ったらコンパイルエラーだったwfunc foo(x: Any) { switch x { case let strings as [String]: print("strings \(strings)") case let integers as [Int]: print("integers \(integers)") default: print("unknwon") } } let ints: [Int] = [] foo(x: ints)
これで strings
判定されちゃうことになるので、やっぱキャスト出来ちゃうと駄目だと思います。 (edited)let x = [Int?.none, Int?.none, Int?.none] let y = x as? [String?] // [nil, nil, nil]
これもなかなか。func foo<T>(value: T, type: T.Type) { switch type { case is Array<String>.Type: print("strings \(value as! Array<String>)") case is Array<Int>.Type: print("integers \(value as! Array<Int>)") default: print("unknwon") } } let ints: [Int] = [] foo(value: ints, type: type(of: ints)) // integers []
(edited)func cast<T, U>(from: U) -> T? { return from as? T } let z: Int?? = cast(from: String?.none) switch z { case .none: print("a") case .some(.none): print("b") // ココ case .some(.some): print("c") }
で、やはりOptional.noneも同様にキャストが成功している。func foo<T>(value: T) { switch T.self { case is Array<String>.Type: print("strings \(value as! Array<String>)") case is Array<Int>.Type: print("integers \(value as! Array<Int>)") default: print("unknwon") } } let ints: [Int] = [] foo(value: ints)
var a: [Int] = [] var b: [String]? = a as? [String] // Cast from '[Int]' to unrelated type '[String]' always fails
この警告だけ (edited)func foo(_ x: Any) { switch type(of: x) { case is [String].Type: print("strings \(x as! [String])") case is [Int].Type: print("integers \(x as! [Int])") default: print("unknwon") } } var a: [Int] = [] foo(a) // integers []
(edited)as
で出来るのはおかしい。こっちは世界の崩壊を招くlet x = [Int?.none, Int?.none, Int?.none] x is [String?] // true type(of: x) is [String?].Type // false
let x = [Int??.none, Int??.none, Int??.none] let y = x as? [Int?] // [nil, nil, nil]
let x = [Int?.none, Int?.none, Int?.none] type(of: x) == [Int?].self // true
==
でも書けるね、継承を区別したいときはこれが必要になる (edited)as?
の考え方が違うってだけだと思う/// If the dynamic type of `obj` doesn't implement a `getIntegerValue()` /// method, the system returns a runtime error when you initialize /// `certainValue`. /// /// Alternatively, if you need to test whether `obj.getIntegerValue()` exists, /// use optional binding before calling the method. /// /// if let f = obj.getIntegerValue { /// print("The value of 'obj' is \(f())") /// } else { /// print("'obj' does not have a 'getIntegerValue()' method") /// } /// // Prints "The value of 'obj' is 100" public typealias AnyObject
(edited)public typealias AnyObject = Builtin.AnyObject public typealias AnyClass = AnyObject.Type
typealias Any = protocol<>
が実際にあったけど、 &
記法になったタイミングで Any
がキーワードになり、Parser で特別扱いになりました。typealias Any = Builtin.Any
になるかもしれないですね。let x = Int??.none as? Int? let y = Int?.none as? Int?? switch x { case .none: print("print") case .some: print("-") } switch y { case .none: print("-") case .some: print("print") }
(edited)let x = [Int?.none] as? [Int??] switch x?.first! { case .none: print("x") // !! case .some(.none): print("y") case .some(.some): print("z") } let y = [Int?.none] as [Int??] switch y.first! { case .none: print("x") case .some(.none): print("y") // !! case .some(.some): print("z") }
(edited)as?
の使用に対して警告だしながら > Conditional cast from '[Optional<Int>]' to '[Int??]' always succeedsEncoder
, Decoder
はサポートする型により、Codable
自身のコーディング表現をオーバーライドする様になってます。URL
をURL
自身にエンコードさせると、["relative":"http://apple.com"]
みたいな辞書表現になります。On implementing Codable conformance, if it uses container.encode(_:…) instead of container.encodeIfPresent(_:…), container.encode(url, forKey: .url) produces dictionary. But, `JSONDecoder` tries to decode Optional<URL> from string.
JSONEncoder
は"http://apple.com"
として扱いたいので、Encodable
がURL
だったらこうする、と特別扱いします。 } else if T.self == URL.self { // Encode URLs as single strings. return self.box((value as! URL).absoluteString)
Optional
, Set
, Array
にこれらの型が入っていた場合にも特別扱いしなければいけないのですが、Conditional Conformanceがないため、Decodable
のコードが素直にかけませんでした。extension Optional : Decodable
extension Optional : Decodable /* where Wrapped : Decodable */ { @_inlineable // FIXME(sil-serialize-all) public init(from decoder: Decoder) throws { // Initialize self here so we can get type(of: self). self = .none assertTypeIsDecodable(Wrapped.self, in: type(of: self)) let container = try decoder.singleValueContainer() if !container.decodeNil() { let metaType = (Wrapped.self as! Decodable.Type) let element = try metaType.init(from: container) self = .some(element as! Wrapped) } } }
(Swift 4.0のコードに変更) (edited)Decoder
の処理を優先して、こう書きたい。 let container = try decoder.singleValueContainer() if !container.decodeNil() { - let metaType = (Wrapped.self as! Decodable.Type) - let element = try metaType.init(__from: container) - self = .some(element as! Wrapped) + self = .some(try container.decode(Wrapped.self)) } } }
(edited)JSONEncoder
とかのCoder
で特別扱いされるURL
の側で「JSONEncoder
だったら辞書表現をやめる」みたいな力技で対応されていました。 https://github.com/apple/swift/pull/10766 (edited)Coder
ではバグっていたのです。Coder
実装がどれくらいあるのか知りませんが…YAML
のCoder
実装は未リリース。これがSwift 4.0.1で直りそう、というお話。
4.0.1に入るかどうか微妙な時期らしい…let results = scheduler.createObserver(Void.self) XCTAssertEqual(results.events, [next(0, ()), next(10, ())])
と書くとコンパイルエラーになってしまいます。 どのように書くと良いのでしょうか…? (そもそもObservable<Void>はTestableObserverでテストを書くべきでは無いのでしょうか…?)() == () // true
func f<X: Equatable>(x: X) {} f(x: ())
public func == (lhs: Recorded<Void>, rhs: Recorded<Void>) -> Bool { return lhs.time == rhs.time }
これその辺に書いたら何とかなりませんかねimport Foundation class A: Encodable { let f1: String init(f1: String) { self.f1 = f1 } } class B: A { let f2: String init(f1: String, f2: String) { self.f2 = f2 super.init(f1: f1) } } let b = B(f1: "f1", f2: "f2") let x = try JSONEncoder().encode(b) String(data: x, encoding: .utf8) // -> { "f1": "f1" }
(edited)protocol C: Encodable { var f3: String { get } } struct D: C { var f3: String } let d: C = D(f3: "f3") let y = try JSONEncoder().encode(d) // ここでコンパイルエラー
(edited)D
として渡すと通りますC
にencode
メソッドを足してD
や各々でエンコードってのが良さそうですかね/// A type that can encode itself to an external representation. public protocol Encodable { /// Encodes this value into the given encoder. /// /// If the value fails to encode anything, `encoder` will encode an empty /// keyed container in its place. /// /// This function throws an error if any values are invalid for the given /// encoder's format. /// /// - Parameter encoder: The encoder to write data to. func encode(to encoder: Encoder) throws }
protocol C: Encodable { var f3: String { get } func encode() throws -> Data } struct D: C { var f3: String func encode() throws -> Data { return try JSONEncoder().encode(self) } } let d: C = D(f3: "f3") let y = try d.encode()
open func encode<T : Encodable>(_ value: T) throws -> Data {
protocol P {} class Cat : P {} func f<X: P>(_ p: X) {} var a: P = Cat() var b: Cat = Cat() f(a) // NG f(b) // OK
C
のextensionにencode
書けばいいのか。protocol C: Encodable { var f3: String { get } func encode() throws -> Data } extension C { func encode() throws -> Data { return try JSONEncoder().encode(self) } } struct D: C { var f3: String } let d: C = D(f3: "f3") let y = try d.encode()
これがいける?toJSON() -> Data
という名前の方が良さそうOptional.none
は常にフィールド自体省略になってnull
にすることができない気が…… fileprivate func box<T : Encodable>(_ value: T) throws -> NSObject { return try self.box_(value) ?? NSDictionary() }
Container上では return try JSONSerialization.data(withJSONObject: topLevel, options: writingOptions)
encode(to:)
だとそうなりますね。Optional
だとencodeIfPresent(_:forKey:)
が使われるコードが生成される。これをencode(_:forKey:)
を使うコードを自分で書けばnull
が使われる。 https://github.com/apple/swift/blob/master/lib/Sema/DerivedConformanceCodable.cpp#L623-L624 (edited)Codable
使う旨味が減っちゃいますねぇ。 Optional.none
のあつかいもstrategyで書けたらいいんじゃないかと思うんですが データ全体じゃなく部分ごとにここは省略したいとかある可能性もあるんで微妙ですかねstruct Foo: Encodable { var optionalInt: Int? private struct FooEncode: Encodable { var optionalInt: KeyedOptional<Int> /* Foo <-> FooEncode 変換書く */ } func encode() throws -> Data { return FooEncode(self).encode() } }
こげな{ "objects": [ { "key": 1, "value": "foo" }, { "key": "2", "value": "bar" } ] }
こういう意地悪すると、 enum Key: Codable { case int(Int) case string(String) }
こんなのが生える{ "objects": [ { "key": 1, "value": "foo" }, { "key": null, "value": "bar" } ] }
で、 struct Object: Codable { let key: Int? let value: String }
(edited)superEncoder
/superDecoder
の利用は必須ではないですね。superclassのデータをキーsuper
に入れるかどうかはユーザー次第になってるかと。public class Comprehensive: Encodable { private let field1: String private let field2: String? private let field3: String? fileprivate init(field1: String, field2: String?, field3: String?) { self.field1 = field1 self.field2 = field2 self.field3 = field3 } } public class Child1: Comprehensive { public init(field1: String, field2: String) { super.init(field1: field1, field2: field2, field3: nil) } } public class Child2: Comprehensive { public init(field1: String, field3: String) { super.init(field1: field1, field2: nil, field3: field3) } }
めちゃくちゃ汚いですがこれでやりたかったことはできそうですpublic class AnyKeyPath {} public class PartialKeyPath<Root> : AnyKeyPath {} public class KeyPath<Root, Value> : PartialKeyPath<Root> {} public class WritableKeyPath<Root, Value> : KeyPath<Root, Value> {} public class ReferenceWritableKeyPath<Root, Value> : WritableKeyPath<Root, Value> {}
(edited)responds(to:)
とか使えるという話import Foundation class Cat { @objc func eat() {} } (Cat() as AnyObject).responds(to: #selector(Cat.eat)) // true
#selector(Cat.eat)
ってやってるけどclass Dog { @objc func eat() {} }
@objc
がついてないと当然Selectorは生えないのでfalseになる- (oneway void)release;
Codable
に準拠した型のlet
プロパティは、エンコードはされるけどデコードされることはないのね。let
プロパティをエンコードされない様にするには、let
プロパティを含まないCodingKeys
を用意すると。let
プロパティだ。NSDictionaryからDataを経由せずに直接デコードしたい…
作った。 https://github.com/norio-nomura/ObjectEncoder[String: Any]
, [Any]
or Any
as payload.import Foundation import ObjectEncoder // single value let string = "Hello, ObjectEncoder" let encodedString = try ObjectEncoder().encode(string) (encodedString as AnyObject).isEqual(to: string) // true let decodedString = try ObjectDecoder().decode(String.self, from: encodedString) // dictionary struct S: Codable { let p1: String } let s = S(p1: "string") guard let encodedS = try ObjectEncoder().encode(s) as? [String: Any] else { fatalError() } encodedS["p1"] // "string" let decodedS = try ObjectDecoder().decode(S.self, from: encodedS) decodedS.p1 // "string" // array let array: [S] = [s, s] guard let encoded = try ObjectEncoder().encode(array) as? [[String: Any]] else { fatalError() } encoded[0]["p1"] // "string" let decoded = try ObjectDecoder().decode([S].self, from: encoded) decoded[0].p1 // "string"
JSONEncoder
やPropertyListEncoder
みたいに、各型についての特殊な処理が一切入っていないCoders
実装になってます。[String: Any
や[Any]
へそのまま突っ込むイメージ。let source = CGImageSourceCreateWithURL(url as CFURL, nil), let properties = CGImageSourceCopyPropertiesAtIndex(source, 0, nil) as NSDictionary? let decoded: ImageProperties = try ObjectDecoder().decode(from: properties)
みたいなAPIからNSDictionary
で返ってきたデータのモデリング。 (edited)JSONEncoder
かPropertyListEncoder
へData
以外も受け付けるAPIを作ってPR出すことも考えたけど、変換部分が邪魔だった。{ “id”: 1, “url”: “” }
というAPIのレスポンスがあったとして、 struct Hoge: Codable { let id: Int let url: URL? }
これでデコードしようとすると、Invalid URL StringということでdataCorrupted扱いになります。このとき、urlをnilで取り扱うためのワークアラウンド、どなたかお持ちですか? (edited)struct Hoge: Codable { let id: Int let jsonUrl: String? var url: URL { get { ... } set { ... } } }
struct Landmark: Codable { var name: String var foundingYear: Int var location: Coordinate var vantagePoints: [Coordinate] enum CodingKeys: String, CodingKey { case name = "title" case foundingYear = "founding_date" case location case vantagePoints } }
struct Hoge: Codable { let id: Int private let jsonUrl: String? var url: URL? { return URL(string: jsonUrl) } enum CodingKeys: String, CodingKey { case id case jsonUrl = "url" } }
(edited)struct Hoge: Codable { let id: Int private let jsonUrl: String? var url: URL? { return jsonUrl.flatMap(URL.init) } enum CodingKeys: String, CodingKey { case id case jsonUrl = "url" } }
(edited)struct Hoge: Codable { let id: Int let url: String? } extension Hoge { var urlurl: URL? {return url.flatMap {URL(string: $0)}} }
Codableがjsonをそのままうつしていると考えればこう (edited)url: String
は image: UIImageView
と同じレベルでやめたいurl
のほうを使わずに urlurl
を使うのが注意点かurl: String
は合理的だと思いますよ。 URL
オブジェクトはデータ構造というよりはユーティリティ。struct _Hoge: Codable { 略 }
と struct Hoge { 略 }
でこいつら相互変換可能に。hoge.カッコイイ名前.url
になるのではHoge
と Hoge.JSON
にするの良さそうCGSize(width: 100, height: 50)
に対応するのは { "width": 100, "height": 50 }
ではなくて [100, 50]
なんですよid: Int
から id String
に変わったとかあるので、外部APIを最初に受けるところはあまり厳格にしてもというのはあります。import Foundation struct Model<Base: Modelable> { var base: Base } protocol Modelable { var model: Model<Self> { get } } extension Modelable { var model: Model<Self> { return Model(base: self) } } struct Hoge: Codable, Modelable { fileprivate var int: Int fileprivate var url: String? } extension Model where Base == Hoge { var int: Int { return base.int } var url: URL? { return base.url.flatMap(URL.init) } } func x(hoge: Hoge) { hoge.model.url // URL? }
よさそうstruct Cat { subscript(ex ex: Void) -> Ex<Cat> { get { return Ex(self) } set { self = newValue.t } } var age: Int = 3 } struct Ex<T> { init(_ t: T) { self.t = t } var t: T } var cat = Cat() cat[ex: ()].t.age = 6 print(cat) // Cat(age: 6)
func M<A: Modelable>(_ arg: A) -> Never { fatalError() }
こいつ作っておけば cat[M].t.age = 6
ってできるんじゃん?cat[Rx].tap.subscribe ...
import Foundation struct Model<Base: Modelable> { var base: Base } protocol Modelable { var model: Model<Self> { get } } extension Modelable { var model: Model<Self> { return Model(base: self) } } struct Hoge: Codable, Modelable { fileprivate var int: Int fileprivate var url: String? var model: Model<Hoge> { get { return Model(base: self) } set { self = newValue.base } } } extension Model where Base == Hoge { var int: Int { get { return base.int } set { base.int = newValue } } var url: URL? { get { return base.url.flatMap(URL.init) } set { base.url = newValue?.absoluteString } } } func x(hoge: Hoge) { hoge.model.int var hoge = hoge hoge.model.url = URL(string: "https://www.google.com") }
いけた。struct Model<Base: Modelable> { var base: Base } protocol Modelable { var model: Model<Self> { get } } extension Modelable { var model: Model<Self> { get { return Model(base: self) } set { self = newValue.base } } } struct Hoge: Codable, Modelable { fileprivate var int: Int fileprivate var url: String? } extension Model where Base == Hoge { var int: Int { get { return base.int } set { base.int = newValue } } var url: URL? { get { return base.url.flatMap(URL.init) } set { base.url = newValue?.absoluteString } } } func x(hoge: Hoge) { hoge.model.int var hoge = hoge hoge.model.url = URL(string: "https://www.google.com") }
Model
に対してJSON<Model>
を作りたい (edited)URLComponents
として保持するのもありなのかも?と思ったけど、これはどういう状態なんだろうか。 import Foundation var comps = URLComponents(string: "")! comps.url! // (no URL)
(edited).url
が作れないって感じ?String
で持つべきだと思います?UUID
にするのはもちろんやるべきですし、私もそう書きます。UUID
で定義するなら、 UUID を String
で持つべきなのはどういうケースですか? (edited)UUID
、サーバから受ける場合は String
?url.flatMap {URL(string: $0)}
を都度書きたくない/// デコードしたStringと、TypedなURLは纏めて独自型に押し込めるほうがいい struct RobustURL: Codable { let rawValue: String var typed: URL? { return URL(string: rawValue) } func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() try container.encode(rawValue) } init(from decoder: Decoder) throws { rawValue = try decoder.singleValueContainer().decode(String.self) } } /// CoreGraphicに依存しない独自型 struct Size: Codable { let width: Double let height: Double } import CoreGraphics extension Size { var asCGSize: CGSize { return CGSize(width: width, height: height) } } struct Fuga: Codable { let url1: RobustURL // 不正なURLが来うることを型として示せる let url2: RobustURL // 不正なURLが来うることを型として示せる let url3: URL // 不正なURLが来ないことを型として示せる let size: Size } let data = """ { "url1": "https://failable.url", "url2": "不正なURL", "url3": "https://ensured.url", "size": { "width": 100, "height": 50 } } """.data(using: .utf8)! let fuga = try! JSONDecoder().decode(Fuga.self, from: data) fuga.url1.typed // https://failable.url fuga.url2.typed // nil fuga.url3 // https://ensured.url fuga.size.asCGSize // {w 100 h 50} let json = try! JSONEncoder().encode(fuga) print(String(data: json, encoding: .utf8)!) // {"size":{"width":100,"height":50},"url3":"https:\/\/ensured.url","url1":"https:\/\/failable.url","url2":"不正なURL"}
ウソもデコードできるURL型を自分で定義
これすねasURL
は欲しくないですねstruct Bar: Codable, RawRepresentable { let rawValue: String init?(rawValue: String) { self.rawValue = rawValue } }
これはエンコードできないな。struct RobustURL: Codable, RawRepresentable { let rawValue: String var typed: URL? { return URL(string: rawValue) } init?(rawValue: String) { self.rawValue = rawValue } }
すっきり{"rawValue": ...}
の階層つくらないんですね、まじか‥init?(rawValue: String)
も要らないんじゃないかな。public
にする時には要るか。internal
なら要らないですね。: class
をつけることが多いんだけどprotocol
と mutating
関連の Proposal なかったっけ?: class
にしてしまっているprotocol Foo: class {} class Bar<X: class> {} Bar<Foo>() // 🙅
:class
ってそこでもつかえる? :AnyObject
にしてた。@objc protocol Foo: class {} class Bar<X: AnyObject> {} Bar<Foo>() // 🙆
@objc
は深入りしたくない・・・互換性のためにいろいろ諦めてそうだしちゃんと考えて無さそう (edited)@optional
なメソッドとかSwift上にそんな概念ないのにちゃんと考慮されたりするし:class
つけなくてもその前提条件だとコンパイルはできるんだけど、 考慮せずぜんぶ func にしてるんだって自覚を表明するためにつけといたほうがマシかなって思ってるAnyObject
って参照型なら OK じゃなくてクラスじゃないとダメなのか。 1> let a: () -> Int = { 42 } 2. let b: AnyObject = a error: repl.swift:2:20: error: value of type '() -> Int' does not conform to specified type 'AnyObject' let b: AnyObject = a ^ as AnyObject
typealias AnyObject
1> let a: () -> Int = { 42 } a: () -> Int = 0x00000001000c5030 $__lldb_expr8`closure #1 () -> Swift.Int in __lldb_expr_7 at repl.swift:1 2> let b = a b: () -> Int = 0x00000001000c5030 $__lldb_expr8`closure #1 () -> Swift.Int in __lldb_expr_7 at repl.swift:1 3> a === b error: repl.swift:3:3: error: cannot check reference equality of functions; operands here have types '() -> Int' and '() -> Int' a === b ~ ^ ~
var f: () -> String = { "hello" } var array: [() -> String] = [] array.append(f) print(array[0] === f)
/Users/omochi/temp/swer/Sources/swer/main.swift:5:16: Cannot check reference equality of functions; operands here have types '() -> String' and '() -> String'===
のオペランドの型が AnyObject
なのかも。let c = { (i: Int) in print("\(i)") } func f(i: Int) { print("\(i)") } (c as AnyObject) === (c as AnyObject) // false (f as AnyObject) === (f as AnyObject) // false
まあそもそもBoxのポインタ比較だと思うんでvar a = 0 let b: () -> Int = { a = a + 1; return a } let c = b print(b()) // 1 print(c()) // 2
@convention()
によって挙動がいろいろですね。c()
は 1
にならないとおかしい。
@convention
は7種類あるらしい - ``@convention(thin)`` indicates a "thin" function reference, which uses the Swift calling convention with no special "self" or "context" parameters. - ``@convention(thick)`` indicates a "thick" function reference, which uses the Swift calling convention and carries a reference-counted context object used to represent captures or other state required by the function. - ``@convention(block)`` indicates an Objective-C compatible block reference. The function value is represented as a reference to the block object, which is an ``id``-compatible Objective-C object that embeds its invocation function within the object. The invocation function uses the C calling convention. - ``@convention(c)`` indicates a C function reference. The function value carries no context and uses the C calling convention. - ``@convention(objc_method)`` indicates an Objective-C method implementation. The function uses the C calling convention, with the SIL-level ``self`` parameter (by SIL convention mapped to the final formal parameter) mapped to the ``self`` and ``_cmd`` arguments of the implementation. - ``@convention(method)`` indicates a Swift instance method implementation. The function uses the Swift calling convention, using the special ``self`` parameter. - ``@convention(witness_method)`` indicates a Swift protocol method implementation. The function's polymorphic convention is emitted in such a way as to guarantee that it is polymorphic across all possible implementors of the protocol.
@convention(thin) indicates a "thin" function reference, which uses the Swift calling convention with no special "self" or "context" parameters.
あー、ここに出てくる、 self と context がミソっぽいなあ 今の話let b: () -> Int = { [x=a] in a = x + 1; return a }
AnyObject
には入らなかった>7種類。class
やめるのダメ?var a = 3 let b: () -> Int = { [x=a] in a = x + 1 return a } print(b()) // 4 print(b()) // 4 print(b()) // 4
id
にはブロックが入った気がするから、AnyObject
!= id
var a = 3 let b: () -> Int = { [x=a] in a = x + 1 return a } let c = b print(b()) print(c()) print(b()) print(c())
4 4 4 4class
使うとか? class Ref<Value> { var value: Value }
&
と *
がほしくなってきた。 struct
と &
と *
の世界、実は良かったのでは? malloc
や free
が面倒だっただけで、そこをリファレンスカウントで勝手にやってくれるなら。&
じゃなくて、実体コピーした上で参照型化かな。struct Foo
を作ったけど、それを共有したいときは Foo *
として取り扱えるとうれしい。 (edited)*
の意味は C と同じになるけど、 &
はちょっと違うから別の記号が良さそう。Box<Foo>
と同じなんだけどbox 1
Optional
や Array
みたいに Box
( Reference
でもいい)のシュガーがあればいいのかも。Foo*
が Reference<Foo>
weak var foo: Foo*?
こうなる? (edited)class Reference<Value> { var value: Value }
prefix func *
もほしいかFoo*
が Reference<Foo>
だとうれしくない?weak var a: Reference<Int>?
で良いんじゃない? (edited)weak var foo: Foo*?
かな?let a: () -> Int = { 42 } let block = a as @convention(block) () -> Int as AnyObject
let a: () -> Int = { 42 } let block = a as AnyObject print(block)
as AnyObject
はそもそもそのままできそうですよlet a: () -> Int = { 42 } print(a as AnyObject === a as AnyObject) // false let b = a as @convention(block) () -> Int print(b as AnyObject === b as AnyObject) // true
() -> Int false @convention(block) () -> Int true
a
は as AnyObject
でボクシングされるけどb
はすでに AnyObject
だからlet a: () -> Int = { 42 } let b = a as AnyObject b === b // true
let a: () -> Int = { 42 } print(type(of: a)) print(a as AnyObject === a as AnyObject) let b: @convention(block) () -> Int = a as @convention(block) () -> Int print(type(of: b)) print(b as AnyObject === b as AnyObject) var x: AnyObject = b // NG: value of type '@convention(block) () -> Int' does not conform to specified type 'AnyObject'
dump(P.method)
もダメだった。var x: AnyObject = b // NG: value of type '@convention(block) () -> Int' does not conform to specified type 'AnyObject'
(edited)po
をやるみたいなの。>dump
(edited)print(b as AnyObject === b as AnyObject) // true var x: AnyObject = b // NG: value of type '@convention(block) () -> Int' does not conform to specified type 'AnyObject'
import Foundation let a = "str"; let b: NSString = a
class Cat {} let a: AnyObject = Cat() print(type(of: a)) // Cat
func f() -> Int { return 42 } let a: AnyObject = f as AnyObject print(type(of: a)) // _SwiftValue
_SwiftValue
なる型になってた。swift-string.swift:3:19: error: cannot convert value of type 'String' to specified type 'NSString' let b: NSString = a ^ as NSString
;
が付いてるas NSString
なら通る。明示的なキャストを言語的に強制してるということです。:tarunon:
絵文字ほしくなってきたなfalse
だから。 import Foundation let a = "str" a as NSString === a as NSString // false
===
が true
になるところimport Foundation let str = "str" let b = str as NSString (b as AnyObject === b as AnyObject) // true
と同じじゃないかと。 (edited)let b: @convention(block) () -> Int = { 42 } b as AnyObject === b as AnyObject // true
import Foundation let str = "str" let b = str as NSString let c: AnyObject = b // OK
let b: @convention(block) () -> Int = { 42 } b as AnyObject === b as AnyObject // true let c: AnyObject = b // ERROR
let b: @convention(block) () -> Int = { 42 } b as AnyObject === b as AnyObject // true b is AnyObject // true let c: AnyObject = b // ERROR
is AnyObject
が true
なのに代入できない・・・import Foundation let a = "aaa" a is NSString let b: NSString = a
is trueだけど代入できないのはよくあるからOptional
も含め@convention(block)
の時点で ObjC の世界に入っているわけだから、 AnyObject にそのまま突っ込めてもいい気はしますね。protocol Proto : AnyObject {} class Box1<X> {} Box1<Proto>() // OK class Box2<X: AnyObject> {} Box2<Proto>() // NG: 'Proto' is not convertible to 'AnyObject'
'Proto' is not convertible to 'AnyObject'
ってエラーメッセージ出てるけど Proto : AnyObject
なんだけどなあprotocol Proto {} struct S: Proto {} func foo<P: Proto>(x: P) {} let p: Proto = S() foo(x: p) // error: cannot invoke 'foo' with an argument list of type '(x: Proto)'
これと同じですね。AnySequence
とか使いたくなるケースの 8 割くらいは実はいらないんじゃないかなぁ。as
とか is
の挙動がReference
と同じように。後は使いやすいシュガーがあれば。protocol
と参照型の相性が良くないような。{ ∃X, X: Animal }
という存在型を略して Animal
型と書くのをやめてぱっと見で存在型だってわかるようにすればもうちょい理解しやすくなりそうですねtypealias AnySequence<Element> = Any<Sequence where .Iterator.Element == Element> let strings: AnySequence<String> = ["a", "b", "c"]
P1 & P2
は Any<T where T: P1, T: P2>
とか?Any<P1 & P2>
が Exitentialになるという仕様になってほしい P1 & P2
はあくまで protocol (edited)protocol<P1, P2>
が P1 & P2
になりました。import UIKit class MyScrollViewDelegate: NSObject, UIScrollViewDelegate { } let myScrollViewDelegate = MyScrollViewDelegate() let tableView = UITableView() let scrollView = tableView as UIScrollView scrollView.delegate = myScrollViewDelegate tableView.delegate is UITableViewDelegate // true myScrollViewDelegate === tableView.delegate // true myScrollViewDelegate is UITableViewDelegate // false
Objc絡むととたんにやばくなるやつunrecognized selector sent to instance 0xXXXXX
いつものだwAnimal
がbark()
メソッドをもってるとして、Any<Animal>
型のanimal
に対して animal.bark()
を呼びだせるのはAny<Animal>: Animal
なわけではなく、 Opening existentials のシンタックスシュガーだって考えればよさそう? let animal: Any<Animal> = Dog() // OK animal.bark() // ↑は以下のシンタックスシュガー // aの型はA。AはAnimalに準拠。 let a = animal openas A a.bark()
struct S { var a: Int = 3, b: Int = 4 }
CGFloat
って Swift 3.1 まで Float
や Double
の typealias
じゃなかったっけ? https://developer.apple.com/documentation/coregraphics/cgfloatstruct
になった?struct
でしたっけ?struct
の方が良いと思います。(環境によって Float
や Double
に切り替わるとやっかいなので)CGFloat
は昔 Double
か Float
の typealias
だったような気が…Obj-Cとの記憶が混乱したのか TimeInterval
と ObjC の両方と混同してたような気がしますCGFloat
のコンパイルが通らなくなる夢を見てた気がしてたんですが、この頃の記憶かも。CoreGraphics
だし import Foundation
しないと使えないし@_fixed_layout public struct CGFloat { #if arch(i386) || arch(arm) /// The native type used to store the CGFloat, which is Float on /// 32-bit architectures and Double on 64-bit architectures. public typealias NativeType = Float #elseif arch(x86_64) || arch(arm64) /// The native type used to store the CGFloat, which is Float on /// 32-bit architectures and Double on 64-bit architectures. public typealias NativeType = Double #endif ... /// The native value. public var native: NativeType }
(edited)NativeType
の typealias
になったね +public struct CGFloat { +#if arch(i386) || arch(arm) + public typealias UnderlyingType = Float +#elseif arch(x86_64) || arch(arm64) + public typealias UnderlyingType = Double +#endif
(edited)昨日話していてそんな気がしたんですが やっぱりOptionalの暗黙変換とOptionalの共変性は矛盾した結果を生むので両方入ってるのは厳しいですね
// Kotlin open class Animal class Cat: Animal() // Rule A // Cat is subtype of Animal run { val cat: Cat = Cat() val animal: Animal = cat } // Rule B // Int is subtype of Int? run { val int: Int = 0 val intOptional: Int? = int // 0 } // Rule C // Optional has covariance run { val catOptional: Cat? = null val animalOptional: Animal? = catOptional // null } // Question // What happen replace `Cat : Animal` to `Int : Int?` run { val intOptional: Int? = null val intOptionalOptional: Int?? = intOptional // null (Int?? == Int?) }
String?.none as? Int? => Int??.some(.none)
は確かにおかしい結果を生むんですが、それ以前に共変性周りが崩壊していることに気がついたInt??
でネストを表現できないですがInt
は Int?
のサブタイプじゃないですからねぇ。Optional<Cat>
が Optional<Animal>
のサブタイプでも、 Int
が Int?
のサブタイプでなければ Optional<Int>
は Optional<Int?>
のサブタイプにならないですし。String?.none as? Int? => Int??.some(.none)
こいつをウソのサブタイプを倒した後でどう説明するのが良いのか、どう言う振る舞いであるべきなのかを考えないといけない気がするCat?.none as Animal?
これが暗黙のmapであるとするのであれば上の結果は正しいということになりますねString?.none as? Int? => Int??.some(.none)
String
→ Int
はパースですか?
String?.none as? Int?
ってやると結果が Int??.some(.none)
になるんですよ。つまりキャストが成功するas?
の ?
を忘れてた。 (edited)[String]() as? [Int]
これは 空配列になる。 1> Int?.none as? Int? $R0: Int?? = nil
(edited) 2> print(Int?.none as? Int?) Optional(nil)
1> dump(Int?.none as? Int?) ▿ Optional(nil) - some: nil $R0: Int?? = nil
String?.none as? Int? // .some(.none)
.none
であるべきだと思います。[String]() as? [Int] // .some([])
(edited).none
であるべきかとAnimal?.none as? Cat?
ではこれは?([String]() as [Any]) as? [Int]
(edited)Animal?.none as? Cat?
ダメな気がしてきたlet cats = [Cat]() let animals: [Animal] = cats // OK let cats2: [Cat] = animals as! [Cat] // これは?
(edited)let animals: [Animal] = cats // OK
↑ここで CoW を効かせたいからなぁ。map
すると先行コピーされちゃう。 (edited)map
でもいい気も?List
は参照型だけど、値型+ジェネリクス+ out
のときどうなるのかなって。interface
しか out
付けれなかった。 using System; namespace HelloWorld { interface IBox<out T> { T Get(); } struct SBox<T> : IBox<T> { private T _value; public SBox(T t) { _value = t; } public T Get() { return _value; } } class CBox<T> : IBox<T> { private T _value; public CBox(T t) { _value = t; } public T Get() { return _value; } } class Animal {} class Cat : Animal {} class Hello { static void Main() { IBox<Cat> sCat = new SBox<Cat>(new Cat()); IBox<Animal> sAnimal = sCat; // OK sCat = (IBox<Cat>)sAnimal; // OK Console.WriteLine(sCat); IBox<Cat> cCat = new CBox<Cat>(new Cat()); IBox<Animal> cAnimal = cCat; // OK cCat = (IBox<Cat>)cAnimal; // OK Console.WriteLine(cCat); } } }
beginAsync
の throws
をなくそうという話への反応が少なくて悲しい。 Chris Lattner と Joe Groff の見解が知りたい。(Foo) async -> Void
の戻り値を受けなくても別に問題ないですよね?await foo() await bar() await baz()
foo
の非同期処理が完了後 bar
が実行され、 bar
が完了後 baz
が実行されるだけで。 (edited)async -> Void
ができなきゃいけないって意味ですね。beginAsync
の throws
について反応がないのはなんでなんだろう?静的チェックの安全性を壊すか壊さないかの重要な話だと思うんですけどねぇ・・・。class Cat { func nya(_ a: Int) -> String { return String(a) } } let nya: (Cat) -> (Int) -> String = Cat.nya let cat = Cat() nya(cat)(3) // "3" Cat.nya(cat)(4) // "4"
- Indices.swift.gyb + Indices.swift
CountableRange
系の削除に期待。CountableRange
消す PR 書くの気持ち良さそう。Codable
とかAPI自体を見直さないとダメそう。>Conditional Conformanceimport Foundation struct S<Wrapped> { var value: Wrapped } extension S: Codable where Wrapped: Codable { enum CodingKeys: String, CodingKey { case value } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) value = try container.decode(Wrapped.self, forKey: .value) } func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(value, forKey: .value) } } let s = S<Int>(value: 1) let encoder = JSONEncoder() let data = try encoder.encode(s) print(String(data: data, encoding: .utf8)!) // {"value":1}
がswift-DEVELOPMENT-SNAPSHOT-2017-11-13-a
で動いた。extension S: Sequence where Wrapped: Sequence { func makeIterator() -> Wrapped.Iterator { return value.makeIterator() } }
はコンパイラクラッシュSequence
は Element
, Iterator
, SubSequence
とあって、それらが関係しているので複雑そうです。Wrapped.Iterator
を自分の Iterator
として解決する辺りとかヤバそう。[Any]
はCodable
では無くなる?extension Array: Codable where Element: Codable {}
かと。Equatable
とかと同様に。[AnyHashable: Any]
も。[String: Any]
の代わりに[String: Codable]
を使っても、Encoder,Decoder側に扱うAPIが無いかも。 Fatal error: Dictionary<String, Decodable & Encodable> does not conform to Encodable because Encodable does not conform to itself. You must use a concrete type to encode or decode.
extension Dictionary: Codable where Value: Codable {}
が必要な気がします。正確には Encodable
と Decodable
別々に。extension Dictionary: Codable where Key == String, Value: Codable {}
こうかな?AnyCodable
みたいなものが必要なんじゃないかな?と。Codable
は associatedtype
も Self
も持たないだたの protocol
だから、 Codable
型として existential になりますよね? struct Foo: Codable {} let foo: Codable = Foo() // OK
protocol P0 { } struct A : P0 {} func f<X: P0>(_ x: X) {} var a: P0 = A() f(a) // error
<T: Encodable>
を受けるAPIはありますがEncodable
を直接受けるAPIは無いです。<T: Encodable>
ではなくEncodable
を直接受け取れば良いのでは?」とコメントしたのですが、受け入れられませんでした。AnySequence
がなくせる話と絡んで、 Any<Codable>
とかできるようになるのかな? 1> let a: Any = 42 a: Int = 42 2> func foo<T: Any>(_ x: T) { print(x) } 3> foo(a) 42
Encodable
ではなく<T: Encodable>
なのは、decode()
側が<T: Decodable>
を使う必要があり、そちらと一貫性を持たせる為だと言われた。よさそうですね! んで、 `Animal` が`bark()` メソッドをもってるとして、`Any<Animal>` 型の`animal` に対して `animal.bark()` を呼びだせるのは`Any<Animal>: Animal` なわけではなく、 Opening existentials のシンタックスシュガーだって考えればよさそう? let animal: Any<Animal> = Dog() // OK animal.bark() // ↑は以下のシンタックスシュガー // aの型はA。AはAnimalに準拠。 let a = animal openas A a.bark()
@ukitaka 前結局理解できなかったのだけどAny<Animal>がAnimalのextentialでなくなる理由とか嬉しい点って何ですか?func foo<T: SomeProtocol>(...)
これに対して、Tの型はかなりカッチリしていてlet a = animal openas A // 将来opening existentialが入るとする
a
の型ってなんですか?test2
の型パラメータの <A> と同じって意味?protocol Animal {} struct Cat: Animal {} func bar<T: Animal>(_ x: T) { print(x) } let b: Animal = Cat() bar(b) // NG
(edited)func foo<T: Sequence>(_ x: T) { print(x) } let a: AnySequence<Int> = AnySequence([2, 3, 5]) foo(a) // OK
(edited)typealias AnySequence<Element> = Any<Sequence where .Iterator.Element == Element>
https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#generalized-existentials (edited)foo
に Any<Sequence where .Iterator.Element == Element>
という Existential Type を渡せるということになります。Animal
が bar
に渡せてもいいように思うのですがいかがでしょう?remove()
実装、1個づつmoveInitialize()
してるけど、まとめて出来るはず。 https://qiita.com/omochimetaru/items/f32d81eaa4e9750293cdremoveSubrange
も O(n) だからいいじゃないかなと思ったりする https://developer.apple.com/documentation/swift/array/2884498-removesubrangemoveInitialize
にしても O(n)
なのは変わらないですね でも、ループを自分でやるより関数に畳み込むほうが最適化も期待できるし、コードはシンプルにできるので、ちゃんと動くなら書き換えたほうが良さそう。remove
系のメソッド全部確認して見たらやはりremoveLast
だけ O(1) だった /// - source: A pointer to the values to copy. The memory region /// `source..<(source + count)` must be initialized. The memory regions /// referenced by `source` and this pointer may overlap.
source and this may overlap
だからExpressibleByRegularExpressionLiteral
を話してる中で Chris Lattner が↓言ってるんですがおもしろくないですか? 2) I’d like to explore the idea of making // syntax be *patterns* instead of simply literals. As a pattern, it should be possible to bind submatches directly into variable declarations, eliminating the need to count parens in matches or other gross things. Here is strawman syntax with a dumb example: if case /([a-zA-Z]+: let firstName) ([a-zA-Z]+: let lastName)/ = getSomeString() { print(firstName, lastName) }
let sortedScores: [Int] = ... if case /([\(0)-\(59)]+: let 不可)([\(60)-\(69)]+: let 可)([\(70)-\(79)]+: 良)([\(80)-\(100)]: let 優)/ = sortedScores { print("優: \(優.count)人") print("良: \(良.count)人") print("可: \(可.count)人") print("不可: \(不可.count)人") }
a = someValue.someMember someValue.someMember = a mutateParameter(&someValue.someMember)
a = someValue[dynamicMember: "someMember"] someValue[dynamicMember: "someMember"] = a mutateParameter(&someValue[dynamicMember: "someMember"])
(edited)a = [2, 3, 5] a.empty?
とか。subscript(dynamicMember:)
内で適宜書き換えてあげないとだめっぽいですね。 (edited)add_trick
のままなだけで、 PyVal
の subscript
で読み替える実装にすれば addTrick
にもできるわけですね。 // import DogModule // import DogModule.Dog as Dog // an alternate let Dog = Python.import("DogModule.Dog") // dog = Dog("Brianna") let dog = Dog("Brianna") // dog.add_trick("Roll over") dog.add_trick("Roll over")
(edited)SOFT HYPHEN(U+00AD)
かな? https://github.com/swift-script/swift-script/pull/18 Apple のドキュメントをコピペすると入ってる時がある。subscript
には @_specialize
が許可されてない? struct Foo { @_specialize(where T == Int) // OK func foo<T>(_ x: T) -> T { return x } @_specialize(where T == Int) // Error subscript<T>(x: T) -> T { return x } }
(edited)subscript
は元々ジェネリックじゃなかったけど、ジェネリックになったときに対応忘れたとか? (edited)_
つきだから、 stdlib で使用する要求が無いと実装されないかもしれないですね。@_specialize
と言えば、昨日過去最多の @_specialize
をつけました・・・。 https://github.com/koher/EasyImagy/blob/dev-0.4.0/Sources/EasyImagy/ImageSpecialized.swift#L2-L677@_specialize
の付いてるコードは見つけられないかもしれないwRGBA
で倍増して、それを組み合わせたのでこんなことに・・・。 (edited)@inlineable
って @_inlineable
として既に実装されているような?_
を外して正規仕様にするために提案を整理してるけど内容は現状あるやつ@inlineable
ではできないけど、現状 @_versioned
でできてるから、これは別の提案で出す、とか。@_versioned
はわかりにくいから別の名前が良いって意見があった@_inlineable
も最初 @_fragile
だった。いずれにしてもパッとは分からないですねー。 1> let a = [2, 3, 5] a: [Int] = 3 values { [0] = 2 [1] = 3 [2] = 5 } 2> let f: (Int) -> Int = a.subscript Segmentation fault: 11
error: value of type '[Int]' has no member 'subscript' let f: (Int) -> Int = a.subscript ^ ~~~~~~~~~
Rintaro Ishizaki added a comment - 15 Sep 2016 4:51 AM Minimum repro: class C { subscript(x: Int) -> Void { return } } _ = C().subscript
subscript
のリファレンスを取る方法は封じられたんでしたっけ? (edited)class C { subscript(x: Int) -> Void { print(x) } } let idx = 12 let kp = \C.[idx] C()[keyPath: kp]
keypath はインデックス固定のリファレンスと見れなくもないか? やりたいこと逆ですがw(Int) -> Element
として高階関数に渡したいのでpublic class Disposable: DisposableConvertible
にしてユーザー側ではサブクラス作れないようにする (edited)Disposables.create
になっているけど、Disposable.init()
にしたかったんだよね // this is kind of ugly I know :( // Swift compiler reports "Not supported yet" when trying to override protocol extensions, so ¯\_(ツ)_/¯ /// Optimizations for map operator internal func composeMap<R>(_ transform: @escaping (Element) throws -> R) -> Observable<R> { return _map(source: self, transform: transform) }
_map
ってどこに定義されてるんだ?public class Disposable { public init() { // ここはクラスクラスタ } } private class CompositeDisposable: Disposable {} // ... その他諸々 protocol DisposableConvertible { var asDisposable: Disposable { get } } public extension Disposable: DisposableConvertible { var asDisposable: Disposable { return self } }
_NSArrayCore
ふくめ、このファイルの型は Foundation なしの stdlib で Foundation 系の型を扱うためのもの。みたいな感じだと思ってます。 (edited) func bind0<X: EventSourceProtocol>(modelStream: X) where X.Event == Model func bind1(modelStream: EventSource<Model>)
(edited)bind1(modelStream: .of(3))
とか書ける事もあって便利bind1(modelStream: Property(3).asEventSource())
変換が必要EventSource is EventSourceProtocol
だから、曖昧なんだけどEventSourceProtocol.of
と EventSource.of
が曖昧になりそうだ .of()
だけ書いてある場合 (edited)protocol MyProtocol { static var foo: Self { get } static var bar: Self { get } } final class MyClass: MyProtocol { static var foo: MyClass { return MyClass() } static var bar: MyClass { return MyClass() } } func func1<X: MyProtocol>(_ arg: X) {} func func1(_ arg: MyClass) {} func1(.foo)
おもちprotocolは
と解釈したprotocol AnimalProtocol { static func makeNya() -> Cat }
↑は Cat.makeNya() や Dog.makeNya() が呼べる事を示す定義であって、 AnimalProtocol.makeNya() という式で呼べる関数を定義するわけじゃないからいいけどprotocol AnimalProtocol {} class Cat : AnimalProtocol {} extension AnimalProtocol { static func makeNya() -> Cat { return Cat() } }
こういう話ではなくて?Float
使いますか? Double
使いますか? Java だと double
が普通だと思うんですが。Double
ですかね?そもそも指定がなかったらデフォルトで Double
使われますし…Double
のみ(もしくは Float
のみ)の API ってありますっけ? 1> let a: Float = -3.14 a: Float = -3.1400001 2> abs(a) $R0: Float = 3.1400001
var
と func
と init(
で数検索して見たけど func
だけFloatが1個少なくて軽く見て見たらFloatのページにだけ abs
がなかったけどドキュメント作った人のせいかCGFloat
なんですよねぇ。CGFloat
は標準ライブラリーで使えなかったっけ?let a = 0.12 print(type(of: a)) // Double
HashMap
の loadFactor
みたいなのないかと思ったけど、 https://docs.oracle.com/javase/jp/9/docs/api/java/util/HashMap.html#HashMap-int-float-Dictionary
にはなかった・・・。 https://developer.apple.com/documentation/swift/dictionaryDouble
を優先して使うのがいいのかな。
char
が一遍に8バイト処理できる計算になるけどそんな話聞いたことないですね(聞いたことないだけかもしれないが
Float
優先で使ってたんだろうと考えてみたけど、Float
になっていることがUITouch
の分解能ってどれくらいなんだろう? (edited)UITouch
の分解能が低いなら Float
でも合理的か。CGFloat
だから、 64bit 環境では 64bit 浮動小数点数になってると思う。Float
とか普通かと。GLK_INLINE GLKMatrix4 GLKMatrix4Add(GLKMatrix4 matrixLeft, GLKMatrix4 matrixRight) { #if defined(__ARM_NEON__) float32x4x4_t iMatrixLeft = *(float32x4x4_t *)&matrixLeft; float32x4x4_t iMatrixRight = *(float32x4x4_t *)&matrixRight; float32x4x4_t m; m.val[0] = vaddq_f32(iMatrixLeft.val[0], iMatrixRight.val[0]); m.val[1] = vaddq_f32(iMatrixLeft.val[1], iMatrixRight.val[1]); m.val[2] = vaddq_f32(iMatrixLeft.val[2], iMatrixRight.val[2]); m.val[3] = vaddq_f32(iMatrixLeft.val[3], iMatrixRight.val[3]); return *(GLKMatrix4 *)&m;
Float
と Double
のどちらが使われてるのかということですね。let a = 0.12
の場合 a
が Double
なので Double
の方が一般的かと思いますね Float
使ってたのかを考えると、昔の iOS アプリ開発から惰性でそうしてるだけな気がしてきました。 (edited)public struct CGFloat { /// The native type used to store the CGFloat, which is Float on /// 32-bit architectures and Double on 64-bit architectures. public typealias NativeType = Double
これ好きFloat
ではなく字面の意味通りのFloatだから(震え声public typealias Float64 = Double
なのでセーフFloat
と Double
って名前に統一感ないですよね。せめて Single
と Double
にするか、 Float32
と Float64
にするかしてほしい。 Swift が悪いわけじゃないけど。Float32
と Float64
作って、 Int
みたいな位置の Float
ほしい。Unsafe*Pointer<Int32>
受ける関数とかありますけどね。 そもそもInt
のサイズがネイティブに依存するメリットがいまいち分かっていないです。Int32
だろうが Int64
だろうが成り立つことがほとんどで、Int
って書いてるときはオーバーフローは Logic failure だし、バイト数で壊れるようなコードはそもそも Int
で書いちゃいけないかと。 (edited)Int32
って書いたコードは未来に Int128
が当たり前になった世界でも Int32
のままになっちゃうよ。Int64
とか Int32
使って、普通の環境は Int
でよしなりにプラットフォームに合わせて使わせてくれる方が嬉しいかな派ですねInt32
でも Int64
でも変わらないでしょう派()Int
が色々なビット数で動いてくれるとうれしいとは思う。Int32
で足りないシチュエーションって相当レアですよね…int
が 32 bit 固定だけど、今の 64 bit 当たり前の時代でも 32 bit に縛られちゃってるのでは?int
を long
にするとか無理では。List
を出したのは例であって、一般的に整数の意味合いで使われてる int
がずっと 32 bit のままが辛いということです。int
が 32 ビットのまま変わらず 20 年使われてますよ。UITableView
のセルの数&インデックスは Int32
だけど Array
の要素数&インデックスは Int64
で境界で全部明示的変換が必要ですとか辛くないですか?ArrayList
的なものを想定してると思うけど、 LinkedList
とかを考えると話が変わってくるのでは? List
は一般的なインタフェースだし。List
が動的に要素を計算するとかあり得るのでは?( List
のアップデート系のメソッドはオプションのはず)Int
から Int32
とかに変換するわけで、その境界で気付くんじゃないかな?普段は Int
として扱っていて、ビット数を気にする処理をする際に IntXX
に変換で十分だと思うけどなぁ。Int32
とか Int64
とか色分けするのは変だと思うし、それが 32 ビット(に限らない XX ビット)に取り残される原因を生むと思う。size
は int
なんです。int
を全部 long
にしましょうとか無茶でしょ?int
を 64 ビットにします(もしくは int
で書かれてた API の大部分を long
にします)とかやったら世界崩壊しそうな気が。 (edited)Int
はプリミティブすぎて影響範囲が他よりめちゃくちゃ大きいんじゃないかなぁ。long
を使ってたものが、 64 bit の世界では普通にとりあえ使えるようになってるのに、古い仕様にひきずられて永久に面倒な取り扱いを強要されるの辛そう。 (edited)fseek
はそんな事になってますねlong
なんだけど long が32bitの環境があるので64bit用のオーバーロードがOSによってはオリジナルで提供されているlong
は Java の64 bit 整数の意図ね。wchar_t
は 2バイト以上」っていうのも同じ問題をおこしましたよlong
でポインタをハードキャストしてるところをまた直さないといけないのか・・・IntXX
と Int
でキレイに分かれてたらそんなにひどいことにはならない気が。Int
、固定したいケースは IntXX
でうまくいくと思うんだけどなぁ。UITableView
のセル数は概念として一般的な整数だと思うんですよね。ユースケースを考えたら 99% のケースではそれが Int32
に収まるとしても。 (edited)Int32
になって、概念を写し取っているべきだとすると Int
になるんじゃないでしょうか。Int
っていうのはほとんどのケースには便利だけど、、、という感じですね。Int32
等にすることに(僕が)違和感を感じるのかもしれません。FooProtocol
か Foo
の foo
の実装をコメントアウトすれば動きます。少なくともエラーメッセージはおかしいと思います。 protocol FooProtocol { func foo(_ f: (inout Int) -> ()) } extension FooProtocol { func foo(_ f: (inout Int) -> ()) { var x = 0 f(&x) print(x) } } struct Foo : FooProtocol { func foo(_ f: (inout Int) -> ()) { var x = 42 f(&x) print(x) } } let a = Foo() a.foo { $0 += 1 }
inout-hof.swift:22:9: error: passing value of type 'Int' to an inout parameter requires explicit '&' a.foo { $0 += 1 } ^ &
(edited)a.foo { $0 += 1; () }
でも動きます。public typealias ArraySlice<T> = Slice<[T]>
にするPR (edited)Slice
を導入するのは大きな変更では?typealias Substring = Slice<String>
(edited)ImageSlice
の名前どうしよ。できるだけ ArraySlice
を踏襲するようにしてたのに。ImageProtocol
を導入して Image
と ImageSlice
で共通の実装を持たせるとこが今朝大分できたのに・・・。Slice
にできないと思う。ArraySlice
の名前が残るならそれでもいいけど、Subimage
にするか ImageSlice
にするかで迷って、 ArraySlice
的なアップデートができるからそっちに寄せて ImageSlice
にした。ArraySlice
おもしろくて、↓みたいな挙動する。 let a = [2, 3, 5, 7, 11] let b: ArraySlice<Int> = a[1...3] // [3, 5, 7] let c: ArraySlice<Int> = [3, 5, 7] b[1] // 3 c[0] // 3 b == c // true
9> b[b.startIndex..<b.endIndex] $R2: ArraySlice<Int> = 3 values { [1] = 3 [2] = 5 [3] = 7 } 10> c[c.startIndex..<c.endIndex] $R3: ArraySlice<Int> = 3 values { [0] = 3 [1] = 5 [2] = 7 }
let a = Image<Int>(width: 4, height: 3, pixels: [ 0, 0, 0, 0, 0, 8, 9, 0, 0, 0, 0, 0, ]) let b: ImageSlice<Int> = image[1...2, 1...1] // [[8, 9]] let c = ImageSlice<Int>(width: 2, height: 1, pixels: [8, 9]) b[1, 1] // 8 c[0, 0] // 8 b == c // true
(edited)Slice<T> is T
みたいなサブタイピングが追加されそうな予感The downside of having two types is the inconvenience of sometimes having a Substring when you need a String, and vice-versa. It is likely this would be a significantly bigger problem than with Array and ArraySlice, as slicing of String is such a common operation. It is especially relevant to existing code that assumes String is the currency type -- that is, the default string type used for everyday exchange between APIs. To ease the pain of type mismatches, Substring should be a subtype of String in the same way that Int is a subtype of Optional<Int>. This would give users an implicit conversion from Substring to String, as well as the usual implicit conversions such as [Substring] to [String] that other subtype relationships receive.
Optional
だけでなくさらなる黒魔術を導入しようとしてるのか?Substring
is a String
無理だと思うんだけどな。let s = "abc" let t: Substring = s[s.index(s.startIndex, offsetBy: 1)...] // "bc" let i = t.startIndex print(t[i]) // "b" let u = String(t) print(u[i]) // "c"
Optional
はもう一歩踏み込んでいて、↓ができる。 class A { func foo() -> Int? { return nil } } class B : A { override func foo() -> Int { return 42 } }
String
と Substring
は今はできない。Int
も Int?
のサブタイプにはなってなくて、↓はエラー。 9> let a: Int? = 42 a: Int? = 42 10> a.map { $0 * 2 } $R0: Int? = 84 11> let b: Int = 42 b: Int = 42 12> b.map { $0 * 2 } error: repl.swift:12:1: error: value of type 'Int' has no member 'map' b.map { $0 * 2 } ^ ~~~
String
は UnsafePointer<UInt8>
に渡せるし。Substring should be a subtype of String in the same way that Int is a subtype of Optional<Int>.
let str: String = "hello" strlen(str) // これはだめにして strlen(^str) // こうするみたいな。
(edited)UnsafePointer
周りは &
がその役割してるのでは?in the same way that Int is a subtype of Optional<Int>.
はもっと強い意味だけど、 the default string type used for everyday exchange between APIs.
を解決するのにサブタイプは必要ないんじゃないか?っていう意見です。&
も構文失敗してる気がする。↓ややこしい。 func f(_ p: UnsafePointer<Int>) { print(p[0]) } func g(_ p: UnsafePointer<[Int]>) { print(p[0].count) } var a = 42 var b = [2, 3, 5] f(&a) f(&b) g(&b)
f(&b)
が良くないinternal
な後置演算子作って変換すればいいし^
で変換、今もできる。 prefix operator ^ prefix func ^(value: Substring) -> String { return String(value) } let s = "abc" let t: Substring = s[...] let u: String = ^t print(u)
strlen(str) // 元のコード // 変換先のコード str.withUnsafeBufferPointer { strlen($0) }
strlen(^substr) // 元のコード // 変換先のコード (^substr).withUnsafeBufferPointer { strlen($0) }
になるのではなく? (edited)var ary = [2, 3, 5] func f(_ p: UnsafePointer<Int>) { } f(ary) // は ary.withUnsafeBufferPointer { f($0.baseAddress!) } // の sugar
(edited)Array
の内部のポインタをそのまま取り回せないようにするのがその意図なんじゃない?( Array
をぶっ壊したり、ライフサイクルを超えて取り回したりできてしまうから)
This contrasts with Array, which can store its elements in either a contiguous region of memory or an NSArray instance if its Element type is a class or @objc protocol.
import Foundation prefix operator ^ prefix func ^(value: Substring) -> String { return String(value) } let s = "abc" let t: Substring = s[...] let u: String = ^t print(u) print(strlen(u)) // OK: 3 print(strlen(^t)) // OK: 3
ArraySlice
→ Array
にせよ、変換してから渡すから問題ないのでは?mutating
じゃないといけないときはダメだけど。import UIKit protocol ProtocolA {} class CustomCell: UITableViewCell, ProtocolA {} func hoge<T>(cellType: T.Type) where T: UITableViewCell & ProtocolA {} let typeA: (UITableViewCell & ProtocolA).Type = CustomCell.self let typeB: CustomCell.Type = CustomCell.self hoge(cellType: typeA) // error: generic parameter 'T' could not be inferred hoge(cellType: typeB) // ok
こういうもんなのかfunc fuga(cellType: (UITableViewCell & ProtocolA).Type) {} fuga(cellType: typeA) // ok fuga(cellType: typeB) // ok
ジェネリクスじゃなくしたら行けた。hoge(cellType: CustomCell.self)
[UITableViewCell & ProtocolA).Type]
に詰めてforEachで全部処理しようとしたら詰まったという感じですAny<Error>
が許されるようになれば T: Error
に Any<Error>
を入れられるようになるのかな??typealias AnySequence<Element> = Any<Sequence where .Iterator.Element == Element>
が成り立たないか。AnySequence
等の個別の実装をなくせない)だし、 typealias AnySequence<Element> = Any<Sequence where .Iterator.Element == Element>
でもそのために早期 ABI 安定化ができないのだとすると、どちらかを諦めるしかなさそうですね。Any<FooProtocol>
の形に統一するのがいいんじゃないかと思ってます。Self
や associatefdtype
を持つプロトコルは型として使えないのに、一部のプロトコルが型として使えることに気持ち悪さを感じてます。protocol
は interface
ではないので。protocol Functor { associatedtype A func fmap<FB where FB ~= Self>(f: A -> FB.A) -> FB }
protocol<P1, P2>
が Any<P1, P2>
ではなく P1 & P2
に置き換えられちゃったみたいだけど、 generalized existential と整合がとれなくなっちゃってる気がするんだけどどうするんだろう・・・。 https://github.com/apple/swift-evolution/blob/master/proposals/0095-any-as-existential.mdAny<P1, P2>
という表記で提案されていたのが最終的に P1 & P2
に変更されて採用されてるんです。The principle problem identified by community about the proposal is that "Any<T1, T2>” implies very strongly an “any of T1 OR T2” relationship
https://lists.swift.org/pipermail/swift-evolution-announce/2016-June/000182.htmlAny<P1 & P2 where ...>
になるんじゃないかと思います。P1 & P2
は廃止される?Any<P1 & P2>
の sugar として残る(残さざるおえない)んじゃないかなー。P1 & P2
is P1
になるってことですよね?まあゆるくなるだけだから互換性はありますが・・・。Any<P>
よりも P
が使われそうなのが微妙・・・P
を型として書くのは existential であることを意識しないで使ってしまうので廃止してほしい。P
を Any<P>
と書かないといけなければ、 func foo<T : P>(_ x: T)
が望ましいものが func foo(_ x: P)
と書かれるケースが減りそう。 func foo(_ x: Any<P>)
だと気持ち悪さがあるので。 (edited)class UITableView { var delegate: Any<UITableViewDelegate>? }
これは受け入れられるのだろうかid<UITableViewDelegate>
って書いてたんだよねprotocol
と interface
が概念的に違うことについて、公式ドキュメントでちゃんとした説明が必要だ・・・ (edited)Sequence<where Element == Int>
みたいな 構文になる可能性もありますね。P1<where ...> & P2<where ...>
Sequence<Int>
にしないのかみたいな話を誘発しそうです・・・
protocol
の static func
は必要では? Argo の Decodable
とかそれなしに成立しないし。 init
は static func
と同じだし。static func
を持てるのは制約を表すために普通に必要だと思うけどなぁ。たとえば↓とか。 protocol Group { // 群 static func •(lhs: Self, rhs: Self) -> Self // 結合法則を満たす演算 static var identity: Self { get } // 単位元 var inverse: Self { get } // 逆元 }
(edited)class Eq a where (==), (/=) :: a -> a -> Bool x /= y = not (x == y)
interface
は protocol
とは別の概念だから異なってていいのでは? (edited)Sequence<Element>
じゃないの?ってとこだろうし。Sequence<Element>
はでも結局不可能でSequence<where Element == Int>
にしたとして、なんで Sequence<Int>
じゃないの?ってなってSequence<Int, _, _>
みたいにできるが…?protocol Sequence<Element> { ... }
とはできないからやっぱり混乱するだけじゃないかなぁ。<>
が出てくるから似た機能のGenericsが想起されて混乱する (edited)[ ]
はArrayに使っちゃったしなあSequence[where .Element == Int]
let array: [Sequence[where Element == Int].Type] = [Sequence[where Element == Int].self]
んー、なんとかいけるか?let a: Int[] = [1]
は未だに Fix-it 出してくれるという親切さ。Int[]
の時代とかありましたね。 Java から来るとわかりやすかったけど、今となっては何がよかったのか・・・AnyIterator
は struct
なんだけど、値型捨て過ぎなのでもう class
になった方がいいのでは? let a = [2, 3, 5] let i = AnyIterator(a.makeIterator()) let j = i print(i.next()) // Optional(2) print(j.next()) // Optional(3)
struct
なのに let
で next
できてることからも。next
が mutating func
じゃないという潔さ。class
にしなかった意味がよくわからない。beginAsync
has the following signature. func beginAsync(_ body: () async throws -> Void) rethrows -> Void However, I think it is better to forbid body
to throw errors, that is to say, to change its signature to the followi...async -> Never
? Theoretically, async -> Void
means you're awaiting a result with only one possible value, but if you're not waiting at all, then there is truly no result, yes? ··· On Sun, Nov 12, 2017 at 9:27 AM, Yuta Koshizawa via swift-evolution < swift-evolution@swift.org> wrote: Sorry, I had got s...Norio_Nomura
になってしまってモヤモヤする…Username Yuta_Koshizawa People can mention you as @Yuta_Koshizawa
omochimetaru
なんですけどomochi.metaru
になっていて@
の左の omochi.metaru
になった。username
変更しちゃうと今までの @
と紐付かなくて困るって話です? (edited)Problems happen when someone who have posted mails to the ML in the past sign up using GitHub authentication. They hope to change their username, but cannot do it after once their accounts were created. I wish there were some additional explaination in the sign up screen, and to get a chance to change the username even if signup is done using github authentication.
norio_nomura
にしておこうかな…joined
にリネームされました。 [[2, 3], [5, 7, 11]].joined()
joined()
の文字見た気がするのに、無視してました...Array
を用いるケース自体が稀な気がしますlet array: [Any] = [1, 2, 3, [4, 5, 6], [7, [8, 9]]]
JSONSerialization
でパースすれば↑のような Array
が得られるでしょうが、どのようにネストされているか不定なネストした Array
を処理するようなことは実用上ほぼないんじゃないでしょうか。Array
をすべてつぶして flatten
したいようなケースはあると思います。[[[1], [2, 3]], [[4, 5, 6]]]
→ [1, 2, 3, 4, 5, 6]
とか。これならキレイに書く方法がありそうです。Data
の write(to:options:)
に倣って名詞を後ろにおいてもいいだろうということで write(to:formatting:)
→ write(to:format:)
としました。ありがとうございました。 (edited)extrapolatedBy:
を付与することで、 x
, y
が画像の範囲外にはみ出てしまった場合でも外挿してくれる API を提供しています。 let red = RGBA<UInt8>(red: 255, green: 0, blue: 0, alpha: 255) let pixel = image[x, y, extrapolatedBy: .filling(red)] // 例えば x = -1, y = -1 なら red が返される
(edited)extrapolatedBy
に与えているのは ExtrapolationMethod
型の値なのですが、次のように宣言されています。 enum ExtrapolationMethod<Pixel> { case filling(Pixel) // 画像の外側を与えられた値で埋める case edging // 画像の外側を最も近いエッジのピクセルで埋める case repeating // 画像の外側を画像の繰り返しで埋める case reflecting // 画像の外側を画像を鏡写しに折り返して埋める }
(edited)edge
, repeat
, reflection
に変えた方がいい気がしてるんですがいかがでしょうか。 (edited)edging
を縁取り的な意図で使ってるんですが、無限の大きさを持った縁なので 縁取りのイメージと合わない気が。一方で、今のままだと -ing
の統一感はあります。clampingToEdge
とかになると思うんですがちょっと長すぎかなと。extrapolatedBy
につながるので、 edge
でも意味は通るかなぁとは思うのですが、悩ましいですね・・・。 repeating
と reflecting
は repeat
, reflection
にします。 filling
は -ing
でも変じゃないですよね? (edited)repeat
が予約語だったから repeating
にしたんだった・・・。loop
とかかなぁ。.repeat
では済むのか。repeat
の方が一般的かな? CSS や GL も repeat だし。.repeat
にします。GL_TEXTURE_WRAP_S Sets the wrap parameter for texture coordinate ss to either GL_CLAMP_TO_EDGE, GL_CLAMP_TO_BORDER, GL_MIRRORED_REPEAT, GL_REPEAT, or GL_MIRROR_CLAMP_TO_EDGE.
constant
かぁ。確かに filling(Pixel)
→ constant(Pixel)
にしてもいいかも?extrapolatedBy: .constant(red)
とか。 (edited)ExtrapolationMethod
がconstant
だとちょっと違和感ある気がしますね。 Padding
がconstant
だとしっくりくるんですがextrapolatedBy
を paddingBy
にした方がいいかな?interpolatedBy
とそろえたかったんだけど。paddedBy
かな?interpolatedBy
は .nearestNeighbor
とか .bilinear
とかが続く。padding
というタームは浸透してるから paddingBy
がいいけど、そうすると interpolatingBy
も検討しないといけない・・・。resizedTo(width: ..., height: ..., interpolatedBy: ...)
とかもあるからなぁ。enum ExtrapolationMethod<Pixel> { case filling(Pixel) // 画像の外側を与えられた値で埋める case edging // 画像の外側を最も近いエッジのピクセルで埋める case repeating // 画像の外側を画像の繰り返しで埋める case reflecting // 画像の外側を画像を鏡写しに折り返して埋める }
InterpolationMethod
です。subscript(x: Double, y: Double, interpolatedBy interpolationMethod: InterpolationMethod, extrapolatedBy extrapolationMethod: ExtrapolationMethod<Pixel>) -> Pixel
subscript
のラベルは名詞を並べるだけで良さそうだから https://developer.apple.com/documentation/swift/dictionary/2894528-subscriptsubscript(x: Double, y: Double, interpolation: InterpolationMethod, extrapolation: ExtrapolationMethod<Pixel>) -> Pixel
とか、 extrapolation
→ padding
とかでいいかもだけどExtrapolationMethod
を改造かなと思ってる。ExtrapolationMethod
の case
にも .repeat
とかを用意しておいて .all(.repeat)
の意味になるとか。で、 .all(.all(...))
とかはダメだから、 .repeat
だけを分離した型も必要になる。.bilinear
で横は nearestNeighbor
で、とかあり得るよね。resizedTo
の話ね。 (edited)InterpolationMethod
と ExtrapolationMethod
はそのままで、必要に応じて DirectedInterpolationMethod
とかを追加するのが良さそう。 .both(.bilinerar)
, .each(x: .nearestNeighbor, y: .bicubic)
とか。Dictionary
の subscript[_:default:]
に倣うなら subscript[_:_:interpolation:extrapolation:]
とかかなぁ。resizedTo(width:height:)
のラベルが難しい・・・DirectedInterpolationMethod
でカバーできる想定で。enum
じゃなくて sealed class
だったら階層的にサブタイピングでうまいことわけられるんだけどね。InterpolationMethod SimpleInterpolationMethod NearestNeighbor Bilinear Bicubic DirectedInterpolationMethod Both(SimpleInterpolationMethod) Each(SimpleInterpolationMethod, SimpleInterpolationMethod)
enum
よりはキレイに整理できそう。open
でない public
なクラスを使えば Swift でも同じようなことはできる。resizedTo(width:height:interpolation:)
は変な気がするけどなぁ。 interpolatedBy
とかじゃなくても、 write(to:format:)
と同じで別に気にしなくていい? (edited)To
の後に width
, height
, interpolation
が並列に並ぶのも気持ち悪い。resized(to: Size, interpolatedBy: InterpolationMethod)
とすることもできるけど、そうすると Size
の扱いが面倒。(Int, Int)
の点に対して補間するだけでは?.filling
はダメとか。さらに階層が増える・・・。.repeat
とかと概念的に違うんだよなぁ。Bool
とか)は .nearestNeighbor
の境界上と同じようにどちらかに寄せるとかかな。.custom
も考えてる。image[-100...100, -100...100, extrapolatedBy: .custom(...)]
InterpolationMethod
とかに case custom
を追加する話じゃないの? (edited).custom((Double, Double) -> Pixel)
と .custom((Int, Int) -> Pixel)
を追加するだけなので大変ではない。.custom((Double, Double, (Int, Int) -> Pixel) -> Pixel)
にしないとダメそう。(Int, Int) -> Pixel
が要らないんだよな。.custom
は保留しよう・・・(Int, Int) -> (Int, Int)
にできるしね。.filling
以外はこれで表現できる。.filling
のために ExtrapolationMethod
がジェネリックになってるのもややこしいといえばややこしい。interpolation
との組み合わせ爆発もするし。enum
じゃ階層にしてすべて ExtrapolationMethod
のサブタイプとかもできないしね。Int
だったら 0
とかそういうこと?protocol
を public
にしないといけない・・・。enum Foo { case foo case bar case piyo(String) case fuga(Int) static var specificFuga1 = Foo.fuga(1) } Foo.specificFuga1
こんな感じかなPixel
プロトコルを作ってしまうとUInt8
とか Float
にプロトコルを後付しないといけないしRGBA<Channel>
とかは付けれないし RGBA<UInt8>
とかだけに付けるには conditional conformance がいる。_Summable
っていうプロトコルを持っていて_Summable
が zero
みたいなのを持っててroteated(by:)
では斜めになったときの背景を zero
で埋めてる。( gyb で各型ごとに extrapolatedBy: .zero)
を付与して呼ぶメソッドを大量生成してる。)rotated(by:)
は使えなくてrotated(by:extrapolatedBy:)
じゃないと使えない。rotated
の interpolatedBy
省略で .bilinear
が使われるけど、それ以外では .nearestNeighbor
が使われるとかなってる。.nearestNeighbor
ですらなくて、それ相当の計算だけど。 InterpolationMethod
が使えるのは _Summable
だけだから。( Bool
に .bilinear
しようがない) (edited)Numeric
でもいけなくて、 UInt8
とか普通に足して平均とったらオーバーフローするからInt
や Double
に変換する処理とかがあって、そのあたりが全部 _Summable
で抽象化されてる。複雑・・・。AnyImage
も元は要らなかったんだけど、 image[-100...100, -100...100, extrapolatedBy: ...]
の結果を ImageSlice
で返そうとすると、 ImageSlice
が内部に持つのが Image
だけじゃダメになって、 ImageSlice
が AnyImage
を持つ必要に迫られた。internal
なメソッドでも @abiPublic
でインライン化できるのか。let double: Double = 3.123456 // 3.123456 var dec1 = Decimal(double) // 3.123456000000000512 var dec2: Decimal = Decimal() NSDecimalRound(&dec2, &dec1, 4, .bankers) dec2 // 3.1235
隠蔽してみたextension Decimal { func rounded(exponent: Int, roundingMode: RoundingMode = .bankers) -> Decimal { var me = self var result = Decimal() NSDecimalRound(&result, &me, exponent, .bankers) return result } } dec1 // 3.123456000000000512 dec1.rounded(exponent: 4) // 3.1235
NSDecimalNumber, an immutable subclass of NSNumber, provides an object-oriented wrapper for doing base-10 arithmetic. An instance can represent any number that can be expressed as mantissa x 10^exponent where mantissa is a decimal integer up to 38 digits long, and exponent is an integer from –128 through 127.
Decimal
は NSDecimal
で c 構造体 みたいです。let dec1 = Decimal(double) // 3.123456000000000512 let n = (dec1 as AnyObject) type(of: n) // __ObjC.NSDecimalNumber.Type
_ObjectiveCBridgeable
っていう ReferenceConvertible
の一個下のレイヤーに準拠してますね。let double1: Double = 123456789000000000 let double2: Double = 1 print(String(format: "%.20f", double1)) print(String(format: "%.20f", double2)) print(String(format: "%.20f", double1 + double2)) let decimal1 = Decimal(string: "123456789000000000")! let decimal2 = Decimal(string: "1")! print(decimal1) print(decimal2) print(decimal1 + decimal2)
123456789000000000.00000000000000000000 1.00000000000000000000 123456789000000000.00000000000000000000 123456789000000000 1 123456789000000001
let decimal1 = Decimal(string: "123456789012345678901234567890")! let decimal2 = Decimal(string: "0.0000000000000000000000000001")! print(decimal1) // 123456789012345678901234567890 print(decimal2) // 0.0000000000000000000000000001 print(decimal1 + decimal2) // 123456789012345678901234567890
let decimal1 = Decimal(string: "123456789012345678901234567890")! let decimal2 = Decimal(string: "0.0000000000000000000000000001")! print(decimal1) // 123456789012345678901234567890 print(decimal2) // 0.0000000000000000000000000001 let decimal3 = decimal1 + decimal2 print(decimal3) // 123456789012345678901234567890 print(decimal1 == decimal3) // true!
let decimal1 = Decimal(string: "1234567890123456789012345678901234567890")! let decimal2 = Decimal(string: "1")! print(decimal1) // 1234567890123456789012345678901234567890 print(decimal2) // 1 let decimal3 = decimal1 + decimal2 print(decimal3) // 1234567890123456789012345678901234567890 print(decimal1 == decimal3) // true!
fileprivate var __exponent: Int8 fileprivate var __lengthAndFlags: UInt8 fileprivate var __reserved: UInt16 public var _mantissa: (UInt16, UInt16, UInt16, UInt16, UInt16, UInt16, UInt16, UInt16)
160bitimport Foundation print(MemoryLayout<Decimal>.size) // 20
let decimal = Decimal(string: "1234567890")! decimal._exponent // 1 decimal._length // 2 decimal._isNegative // 0 decimal._isCompact // 1 decimal._reserved // 0 decimal._mantissa // (.0 52501, .1 1883, .2 0, .3 0, .4 0, .5 0, .6 0, .7 0)
Decimal.greatestFiniteMagnitude // 3402823669209384634633746074317682114550000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 Decimal.greatestFiniteMagnitude._mantissa // (.0 65535, .1 65535, .2 65535, .3 65535, .4 65535, .5 65535, .6 65535, .7 65535) Decimal.leastNonzeroMagnitude // 0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 Decimal.leastNonzeroMagnitude._mantissa // (.0 1, .1 0, .2 0, .3 0, .4 0, .5 0, .6 0, .7 0)
(edited)func truelyLeastDecimal() -> Decimal { var x = Decimal(string: "0.1")! var r = Decimal() NSDecimalPower(&r, &x, 128, .plain) return r } func p(_ d: Decimal) { print("=====") print(d) print(d._mantissa) print(d._exponent) } p(Decimal.leastNormalMagnitude) p(truelyLeastDecimal()) /* ===== 0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 (1, 0, 0, 0, 0, 0, 0, 0) -127 ===== 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 (1, 0, 0, 0, 0, 0, 0, 0) -128 */
Decimalには定義みあたらないけど、NSDecimalNumberのexponentは Decimal.leastNormalMagnitude > truelyLeastDecimal()
こうなってしまうのでCustomStringConvertible
じゃないものでも文字列に埋め込めるの良くなくないですか?何でもとりあえず文字列にしたいニーズはあるとして、それはデバッグ用にそういう関数を用意すれば良いだけに思います。 https://qiita.com/koher/items/6c855ddbda8797af4605CustomDebugStringConvertible
を分けてる意味がなくなっちゃってる気が。 print
が Any
をとれるのも微妙。Optional
は CustomDebugStringConvertible
だったと思うからString.init(describing: Any)
だったはずなんでString.init(describing: x)
って書けばいいんじゃねえかと"\debug() "
みたいなのでもいいけど 1> let a: Int? = 42 a: Int? = 42 2> a.debugDescription $R0: String = "Optional(42)" 3> a is CustomStringConvertible $R1: Bool = true
4> a is CustomDebugStringConvertible $R2: Bool = true
5> a.description error: repl.swift:5:1: error: value of optional type 'Int?' not unwrapped; did you mean to use '!' or '?'? a.description ^ ?
5> func debugPrint<T: CustomDebugStringConvertible>(_ value: T) { print(value) } 6> debugPrint(a) Optional(42)
7> func safePrint<T: CustomStringConvertible>(_ value: T) { print(value) } 8> safePrint(a) error: repl.swift:8:11: error: value of optional type 'Int?' not unwrapped; did you mean to use '!' or '?'? safePrint(a) ^
(edited)Optional
は CustomStringConvertible
ではないけど CustomDebugStringConvertible
ではある(↑)。 (edited)CustomDebugStringConvertible
だけ書いてある。 https://developer.apple.com/documentation/swift/optional (edited)extension Optional : CustomDebugStringConvertible where Wrapped : CustomDebugStringConvertible { ... }
String.init(describing)
で変換すればいいのか。 (edited)public init<T: TextOutputStreamable> (stringInterpolationSegment expr: T) public init<T: CustomStringConvertible> (stringInterpolationSegment expr: T) public init<T: TextOutputStreamable & CustomStringConvertible> (stringInterpolationSegment expr: T)
(edited) public init<T>(stringInterpolationSegment expr: T) { self = String(describing: expr) }
CustomDebugStringConvertibleのケースはこれに行きそう (edited)is
で true
はバグな気がする。 8> let b: CustomStringConvertible = a error: repl.swift:8:34: error: value of optional type 'Int?' not unwrapped; did you mean to use '!' or '?'? let b: CustomStringConvertible = a ^ ! 8> let c: CustomDebugStringConvertible = a c: CustomDebugStringConvertible = { payload_data_0 = 0x000000000000002a payload_data_1 = 0x0000000000000000 payload_data_2 = 0x0000000000000000 instance_type = 0x0000000101416700 libswiftCore.dylib`InitialAllocationPool + 80 protocol_witness_0 = 0x00000001013d1b78 libswiftCore.dylib`protocol witness table for <A> Swift.Optional<A> : Swift.CustomDebugStringConvertible in Swift }
String(describing:)
か debugDescription
すればいいんだから、直接埋め込める必要はない気がします。あえて言えば初心者が混乱するくらい??String(desciribing:)
使ったら?」って出せばいいからそこはダイジョブそう
enum
に偏りすぎな気が。 https://github.com/apple/swift-evolution/blob/master/proposals/0194-derived-collection-of-enum-cases.mdBool
は ValueEnumerable
でいいし、 ValueEnumerable
な associated value を持つ case
があってもその enum
は ValueEnumerable
でいい気がする。enum Foo { case bar case baz(Bool) }
は ValueEnumerable
になりたかったりしないかな・・・。The compiler will synthesize an implementation of ValueEnumerable for an enum type if and only if: - the enum contains only cases without associated values; - the enum is not @objc; - the enum has an explicit ValueEnumerable conformance (and does not fulfil the protocol's requirements).
ValueEnumerable
のときは生成で良い気が。 Codable
が Codable
なプロパティを持っている場合と同じように。Foo
の ValueCollection
が得られれば良いのでは?for x in Foo.allValues { }
みたいに書けるようになってもif x == .bar { ... } if case .baz(false) = x { ... }
こういう感じか。struct Card : ValueEnumerable { let suit: Suit // Suit : ValueEnumerable let number: Number // Number : ValueEnumerable } Card.allValues
(edited)Card.ValueCollection
To limit our scope, we are primarily interested in simple enums—those without any associated values—although we would also like to allow more complicated enums and structs to manually participate in this mechanism.
Int
に精度を明示すべきかどうかみたいな話とも関係してるんじゃないかなぁ。 Int
は ValueEnumerable
であってほしくないけど(概念としての整数は無限の要素を持つので) UInt8
は ValueEnumerable
であってほしい。同様に考えると Int32
や UInt32
も ValueEnumerable
であってほしいけど、 Int
を associated value に持つ enum
に ValueEnumerable
であってほしいわけじゃなくて、 Int
と Int32
の使い分けはやっぱり必要な気がする。Never
の bottom 化早く・・・
allValues
ができる Int64
とできない Int
を区別しておきたいですねぇ。Int64
だと count
が Int
で表せないという話は別として)Int32
か Int64
かの選択が揺らぐようなのをなくしたいです。Int32
等に変換して使いたいイメージですね。Int
にはビット演算とかオーバーフローとかもしたくないです。IntXX
でやって、アプリ用に Int
を使った型に変換するのか、それともエンティティレベルで Int
にして、 DB に保存するときにエラーにしてしまうのか。Int
に Java の BigInteger
とか Ruby の整数のような無限精度になってほしいわけではないですが、コードの書き手が単なる整数を意図しているのかそうではないのかを型として区別しておきたいという感じですね。UInt8
だとオーバーフローを利用した計算とかもよくやると思うんですけど、 Int32
ではそれは OK だけど Int
ではやりたくないです。そこは明示的に Int32
に変換してから処理したいです。Int
が実行環境によって精度が変わるかどうかは別として、 Int32
や Int64
より strict な型がほしいという感じですね。Int
が 32 bit に固定されていたとしても、 Int
に対してオーバーフローを利用した演算はしたくないです。Int
が無限長で有限長を使いたいならInt32
然りInt64
を使う、というのが個人的には一番しっくり来るInt
が現実的に 32bit や 64bit なのには不満はないです。無限精度にはなってほしくない。ValueEnumerable
の例で言えば func combination<T: ValueEnumerable, U: ValueEnumerable>(_ a: T.Type, _ b: U.Type) -> [(T, U)]
みたいな関数があったときにUInt8
や Int32
や Int64
は ValueEnumerable
だけど Int
は違ったらcombination(Int, Bool)
みたいなのを防げます。combination(UInt8, Bool)
はやりたいですし、 combination(Int32, Bool)
も同様に認められるべきだと思います。Int
に BigInt
(無限精度)になってほしいわけではなくて、今のままであってほしいと思います。Int
は単に整数であってほしいだけだと思うので、基本的には制限された Int
を使ってInt32
特有の操作をするときだけ明示的に Int32
に変換して使えたらいいんじゃないかと思います。Int
は最もよく利用する型なのでパフォーマンスも求められると思います。 BinaryInteger
として existential で扱うのは許容できないかと。たとえば、 count
は Int
を返しますが、これは整数を表していると思います。しかし、これが BinaryInteger
になるのは許容できないのではないかと。Int
や UInt
に ~
が使えるのとかは違和感を感じますね。 1> let n: UInt = 0 n: UInt = 0 2> ~n $R0: UInt = 18446744073709551615
3> ~(UInt64(n)) $R1: UInt64 = 18446744073709551615
とすべきかと。Int
のビット数を固定しなかったのが良くなかったという意見なのに対して、僕はそれでよかったと思ってるところでしょうか。そして、その裏には、 Int
は整数だからという気持ちがあります。Int
のビット数が固定されないことで、↑のようなビット演算が良くない行為となり、明示的な変換が求められます。ただ、もう少し踏み込んで Int
には ~
や &+
等はなくてよかったと思います。Int
はほぼ最大値を気にしなくてよい整数なんですよね。 BigInteger
が無限精度だと言っても実際には無限ではなくて、↓のような計算をすると精度が足りません。 $ irb irb(main):001:0> 2 ** (2 ** (2 ** (2 ** (2 ** 2)))) (irb):1: warning: in a**b, b may be too big => Infinity
(edited)BigInteger
で何であれ気にしないといけない、かもしれません。 (edited)Int
だろうが BigInteger
だろうがあまり関係なくどちらも整数と思えるという感じです。2 ** (2 ** (2 ** (2 ** 2)))
と入力すると楽しいことになります。irb(main):012:0> a.class => Bignum irb(main):013:0> a = 2 ** a (irb):13: warning: in a**b, b may be too big => Infinity irb(main):014:0> a.class => Float
2 ** (2 ** (2 ** (2 ** (2 ** 2))))
(edited)BigInteger
の限界を突破するということです。BigInteger
が必要そうですねぇ。AnyIterator
が Sequence
なのってなんでですか? https://developer.apple.com/documentation/swift/anyiterator
for x in (AnyIterator { hoge() }) {}
これができたら楽Sequence
としての責務を果たせてない気が。 let i = AnyIterator([2, 3, 5].makeIterator()) let i2 = i.makeIterator() print(i.next()) // 2 print(i2.next()) // 3 let i3 = i.makeIterator() print(i3.next()) // 5
AnySequence { AnyIterator { hoge() } }
になるのかなIteratorProtocol : Sequence
もほしくならない?Sequence
と IteratorProtocol
の責務が同じにならない?struct Countdown: Sequence, IteratorProtocol { var count: Int mutating func next() -> Int? { if count == 0 { return nil } else { defer { count -= 1 } return count } } }
IteratorProtocol
との役割分担がよくわからない・・・。extension Array { /// Sequence of all sub sequences of specified `length`. public func subSequences(of length: Int) -> SubSequenceSequence<Element> { return SubSequenceSequence(array: self, length: length) }
みたいなのを書いてたんですがSubSequenceIteratorをSequenceにしてそれを返すのも良いのか。Iterator
を返すと複数回呼んだ時に使用中のが返ってきたりする可能性も読み取れるような。 でもSequecne
自体も複数回走査が保証されてないなら……Sequence
が makeIterator
で消費されることがありなら、 extension IteratorProtocol { func makeIterator() -> Self { return self } }
的な実装が可能で、すべての IteratorProtocol
の実装は Sequence
として振る舞えることになる。