swift-4.0.2-RELEASE
来てた。String
は StringProtocol
だけど Number
は Numeric
なんですね… https://developer.apple.com/documentation/swift/numericStringProtocol
以外の XxxProtocol
って何があります?IteratorProtocol
普通にわすれてたw NSObjectProtocol
なんてあるのかぁ(白目public protocol NSObjectProtocol {
ってなってるのに、実際の動きは public protocol NSObjectProtocol: class {
なんじゃあないのっていうのが各所で浮き出てくる (edited)Iterator
っていう 名前衝突を避けたくてそうなった感があるけどね・・・@objc
つけたらclass
矯正されるのと同じ感じですかね@objc
明示ルール出来たのにNSObjectProtocol
はそうじゃないっていうのもねinherits
、何かの型がprotocolに準拠している場合は conforms
、多分これで問題ないかと…?Int
は型だから protocol
に Conforms To
ですねStatus
を abstract class
で定義できたらなぁとすごい思うstruct StackArray<value Size: Int> { ... }
var a = StackArray<2>() a.0 // ok a.1 // ok a.2 // compile error
(edited)enum Status { case NotReady case Ready } class Something<value T: Status> { /*中身は同じでOK*/ }
(edited)value T: Status
になってるのか。 (edited)Status
が protocol
じゃダメなんだっけ? sealed にできない?- Now you can define a “dependent type”, for example ModuloInteger<P>, where P is the integer value that defines the type. - Like this, you’ll have: —> MI<2>: {0, 1}, where 1 + 1 = 0. —> MI<3>: {0, 1, 2}, where 1 + 1 = 2, and 2 • 2 = 1
Status
が protocol
でもダメってことはないですが、Something<NotReady>.createInstance()
で書かないといけないのがイケてないですねVector<2>
とか Matrix<4, 4>
とかやりたい。reserveCapacity
とか考えなくて済むstruct MultiArray<T, let Dimensions: Int> { // specify the number of dimensions to the array subscript (indices: Int...) -> T { get { require(indices.count == Dimensions) // ... } }
(edited)struct Real { ... } extension Real : ConstructibleFrom<Float> { init(_ value: Float) { ... } } extension Real : ConstructibleFrom<Double> { init(_ value: Double) { ... } }
サンプルも Rust の From trait と似てるenum
でstate
パターン、無理やりRawValue
に振る舞いを実装して見た https://gist.github.com/norio-nomura/65db97c4786851bc368a8d68834fb31b (edited)RawRepresentable
で実装where T: Ready
で書くと問題ないけど、where T == Ready
で書くと Something.createInstance()
の直後でも変換の補完で .shout()
が出るのなんで?(もちろんコンパイルエラーにはなるけど…)$ swift generate.swift
で実行しているだけなんや。%{ let intTypes = [8,16,32,64] }% % for intType in intTypes { % for sign in ["", "U"] { /// Extension that adds a few additional functionalities to ${sign}Int${intType} extension ${sign}Int${intType} { /// Returns a ${sign}Int${intType} with all ones % if sign == "" { public static var allOnes: Int${intType} { return Int${intType}(bitPattern: UInt${intType}.max) } % } else { public static var allOnes: UInt${intType} { return UInt${intType}.max } % } } % } % }
-alpha
とか -beta
つけるのオススメ。end
とか Python じゃないし。-swift-version 3
を渡してるかどうかは #if swift(>=3.2.2)
で判定。 (edited)[omochi@omochi-iMac gysb (master *+=)]$ cat Examples/include.swift.gysb %! include_code("libs/*.swift") % aaa=${aaa()} bbb=${bbb()} [omochi@omochi-iMac gysb (master *+=)]$ swift run gysb Examples/include.swift.gysb aaa=999 bbb=777
%!
と include_code を追加したのでなんとかなるmaster *+=
ってなんやて思ったけどプロンプトだった%! swift_package("Package.swift")
とか定義しておくと SPM の executable として実行するような機能を作ったら対応できそう。%{...}
の中にimportは書けないのか[omochi@omochi-iMac gysb (master=)]$ swift run gysb --compile Examples/include.swift.gysb func write(_ s: String) { print(s, terminator: "") } func aaa() -> Int { return 999 } func bbb() -> Int { return 777 } write("aaa=") write(String(describing: aaa())) write("\n") write("bbb=") write(String(describing: bbb())) write("\n")
.gysb
インプットから.swift
のString
を作れるAPIがあると、swift test
の度に.swift
を生成する事ができる様になります。 (edited)#comment(lib, "GL.h")
ってかいてリンク指定できるみたいな。 (edited)*.c
をパッケージ内に持ってて、SwiftPMにClangモジュールとしてビルドしてもらってます。Run Script Phase
を使えるからCLIでいいけど、SwiftPMはビルドプロセスに入れられないのがネックだね。vapor build
の手前に処理を差し込む方法ないのって問い合わせたらねえって言われた (edited)vapor cloud deploy
するとリモートでチェックアウトして vapor build
が動くんだけどその手前でコードジェネレータ動かしてもらわないと成果物コミットしてないから当然コンパイル通らないPackage.swift
の内容を切り替え、GYSB=1 swift test
でコード生成し、swift test
で生成したコードを利用する方法を思いついた。swift test --filter Generate
とテストするモジュールを制限しても全てをビルドしようとするから、未生成なコードに依存する部分がビルド出来なくてダメだった。// swift-tools-version:4.0 import PackageDescription import Foundation let package: Package if ProcessInfo.processInfo.environment["GYSB"] != nil { package = Package( name: "Generate", dependencies: [ .package(url: "https://github.com/omochi/gysb.git", .branch("master")), ], targets: [ .testTarget(name: "Generate", dependencies: ["GysbKit"], path: "Tests/GenerateTests") ] ) } else { package = Package( name: "Example", products: [ .library(name: "Example", targets: ["Example"]), .library(name: "Generated", targets: ["Generated"]), ], targets: [ .target(name: "Example", dependencies: ["Generated"]), .target(name: "Generated", dependencies: []), .testTarget(name: "ExampleTests", dependencies: ["Example"]), ] ) }
$ tree . ├── Package.resolved ├── Package.swift ├── README.md ├── Sources │ ├── Example │ │ └── BuildPhase.swift │ └── Generated │ └── vector.swift └── Tests ├── ExampleTests │ └── ExampleTests.swift ├── GenerateTests │ └── GenerateVectorTests.swift └── LinuxMain.swift
こんな感じ (edited)Package.swift
でYams
をビルドして、それを.gysb
の中でインポートしようとしてるのだけど、うまくいかないな。Test Case '-[GysbWithYamsTests.GysbWithYamsTests testExample]' started. process execution failure path=[/usr/bin/swift] arg[0]=[/var/folders/kt/2mwy9b_56_7993x190pl_1fh0000gn/T/vector_49IokLMk.swift] arg[1]=[-L] arg[2]=[/Users/norio/github/GysbWithYams/.build/x86_64-apple-macosx10.10/debug] statusCode=[1] stderr= /var/folders/kt/2mwy9b_56_7993x190pl_1fh0000gn/T/vector_49IokLMk.swift:4:9: error: no such module 'Yams' import Yams ^ Test Case '-[GysbWithYamsTests.GysbWithYamsTests testExample]' passed (0.438 seconds).
$ /usr/bin/swift /var/folders/kt/2mwy9b_56_7993x190pl_1fh0000gn/T/vector_49IokLMk.swift
return try execCapture(path: swiftPath, arguments: [path, "-L", "/Users/norio/github/GysbWithYams/.build/x86_64-apple-macosx10.10/debug"])
(edited) -F <value> Add directory to framework search path
-l
も必要だったかはよくわからない-I…
,-L…
,-F…
つけても、YamsのPackage.swift
でライブラリtypeを.static
や.dynamic
にして-lYams
つけてもダメだ。 path=[/usr/bin/swift] arg[0]=[/var/folders/kt/2mwy9b_56_7993x190pl_1fh0000gn/T/vector_NwwoI7hu.swift] arg[1]=[-I] arg[2]=[/Users/norio/github/GysbWithYams/.build/x86_64-apple-macosx10.10/debug] arg[3]=[-F] arg[4]=[/Users/norio/github/GysbWithYams/.build/x86_64-apple-macosx10.10/debug] arg[5]=[-L] arg[6]=[/Users/norio/github/GysbWithYams/.build/x86_64-apple-macosx10.10/debug] arg[7]=[-lYams] statusCode=[1] stderr= /var/folders/kt/2mwy9b_56_7993x190pl_1fh0000gn/T/vector_NwwoI7hu.swift:4:9: error: no such module 'Yams' import Yams
(edited).dynamic
にして、以下のオプションをswift
に渡したらいけた。 return try execCapture(path: swiftPath, arguments: [ "-I", "/Users/norio/github/GysbWithYams/.build/x86_64-apple-macosx10.10/debug", "-L", "/Users/norio/github/GysbWithYams/.build/x86_64-apple-macosx10.10/debug", "-lYams", path, ])
% import Foundation % import Yams % guard let yaml = try Yams.compose(yaml: String(contentsOf: URL(fileURLWithPath: "TestResources/vector/vector.yml"))) else { fatalError() } % let vars = yaml.array().flatMap { $0.string } % for n in 2...4 { struct Vector${n} { % for i in 0..<n { var ${vars[i]}: Float % } } % }
swift run gysb
が通る状態?// swift-tools-version:4.0 import PackageDescription let package = Package( name: "GysbWithYams", dependencies: [ .package(url: "https://github.com/omochi/gysb.git", .branch("master")), .package(url: "https://github.com/jpsim/Yams.git", .branch("master")), ], targets: [ .testTarget( name: "GysbWithYamsTests", dependencies: ["GysbKit", "Yams"]), ] )
class GysbWithYamsTests: XCTestCase { func testExample() { do { let driver = Driver.init(path: "TestResources/vector/vector.swift.gyb") let actual = try driver.render(to: .render) print(actual) } catch { print(error) } } static var allTests = [ ("testExample", testExample), ] }
(edited)libYams.a
かlibYams.dylib
が無いとダメですね。type: .static
でも本当はいけると思うのですが、swiftc
がクラッシュしてしまいダメでしたが。.o
達を直接リンクします。 (edited)swift test -v
とかしてみるとコンパイラの起動オプションを見られます。type: .dynamic
にするとswift build --static-swift-stdlib
とかしてもそれらのライブラリはダイナミックリンクされるみたいだから、今後は使い勝手が悪くなると避けられるんじゃないかな? (edited).dynamic
なライブラリを同じパッケージ内のexecutableターゲットから使う場合は問題ないのですが、依存しているパッケージから使った場合、それらはフルパスでリンクされてしまい、ポータブルなexecutableではなくなってしまいます。 $ otool -L ./.build/x86_64-apple-macosx10.10/debug/gysbClient ./.build/x86_64-apple-macosx10.10/debug/gysbClient: /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 1445.12.0) /Users/norio/github/GysbWithYams/.build/x86_64-apple-macosx10.10/debug/libGysbKit.dylib (compatibility version 0.0.0, current version 0.0.0) /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0) /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.0.0)
(edited)prefix operator > prefix func >(value: String) { print(value) } let intTypes = [8, 16, 32, 64] for intType in intTypes { for sign in ["", "U"] { >""" /// Extension that adds a few additional functionalities to \(sign)Int\(intType) extension \(sign)Int\(intType) { /// Returns a \(sign)Int\(intType) with all ones """ if sign == "" { >""" public static var allOnes:Int\(intType) { return Int\(intType)(bitPattern: UInt\(intType).max) } """ } else { >""" public static var allOnes:UInt\(intType) { return UInt\(intType).max } """ } >""" } """ } }
(edited)%{ intTypes = [8,16,32,64] }% % for intType in intTypes: % for sign in ['','U']: /// Extension that adds a few additional functionalities to ${sign}Int${intType} extension ${sign}Int${intType} { /// Returns a ${sign}Int${intType} with all ones %if sign == '': public static var allOnes:Int${intType} { return Int${intType}(bitPattern: UInt${intType}.max) } %else: public static var allOnes:UInt${intType} { return UInt${intType}.max } %end } %end %end
ManifestoGenerator
とか出来てる!w https://github.com/omochi/gysb/blob/master/Sources/GysbSwiftConfig/ManifestoGenerator.swift%! swift_config("gysb_swift_config.json") %{ import Foundation import Yams let yamlPath = URL.init(fileURLWithPath: "data.yml") let yamlStr = try! String(contentsOf: yamlPath, encoding: .utf8) let yaml = try Yams.compose(yaml: yamlStr)! let fields: [String] = yaml.array().map { $0.string! } }% struct Data { % for field in fields { var ${field}: String % } }
{ "packageDependencies": [ { "url": "https://github.com/jpsim/Yams.git", "requirement": { "identifier": "0.5.0", "type": "exact" } }, ], "targetDependencies": [ { "name": "Yams" } ] }
%! swift_config()
の指定は1ファイルだけがする。%! swift_config("gysb_swift_config.json")
gysb.json
はどこにあるんだ?ってなっちゃうんですよね%! import("https://github.com/jpsim/Yams.git")
とかするとswift_config()
に渡すjson相当のものが自動で生成される様にするとか。%! import("https://github.com/jpsim/Yams.git") とかするとswift_config()に渡すjson相当のものが自動で生成される様にするとか。
これの問題点は、パッケージ名からターゲット名がわからないことimport
使えるんだっけ?libSwiftPM
が気軽に使えれば「リポジトリからPackage.swiftを解釈して〜」とか簡単に出来そうなのに… https://github.com/apple/swift-package-manager/blob/master/Package.swift#L19%! swift_config("gysb_swift_config.json")
brew install gysb
できる様になると良いね。%! swift_config
以外に %! include_code
っていうマクロ命令もあってswift_config
書く場合と同じでgysb Sources/Foo/*.gysb Sources/Bar/*.gysb
gysb src/
で再帰的にgysb さがすの??gysb -r src/
とか明示的にした方が良さそうな気も。gysb.josn
も全部適用で良さそう。 (edited)gysb Sources/Foo/*.gysb Sources/Bar/*.gysb
みたいなことがしたいんじゃないの?swift_config
を導入せずに gysb.json を置く方式にするのであれば、一つのディレクトリの中で設定を切り替えることはできないという意味です。Sources/Foo/gysb.json Sources/Bar/gysb.json
Souces/gysb.json
と Sources/Foo/gysb.json
をマージ、 Souces/gysb.json
と Sources/Bar/gysb.json
して 2 回実行 Souces/gysb.json Sources/Foo/gysb.json Sources/Bar/gysb.json
Foo/gysb.json
等に記述することを想定)Foo
, Bar
以下のすべての gysb ファイルに対して 1 回で実行 Souces/gysb.json
%! swift_conifig
はやめてディレクトリ遡り探索の gysb.json にしようと思います%!
という複雑性を持ち込まなくてよさそう。% func foo() { FooFooFoo % } % for _ in 0..<3 { % foo() % }
FooFooFoo FooFooFoo FooFooFoo
func taxRate() -> Float { return 1.08 }
%{ func taxRate() -> Float { return 1.08 } }
metalib.swift.gysb
とかになる。Sources/foo/a.swift.gysb // こいつが それを読みに行く Sources/foo/metalib/metalib.swift.gysb
$ gysb --source-dir Sources
を実行すると・・・Sources/foo/metalib/metalib.swift.gysb
が 処理対象になって、 自分を自分の上部にincludeしようとして、無限ループして壊れる。func taxRate()
みたいな、ちょっとしたやつ。%!
的な構文は避けられなさそう。%!
から逃げられないですね%! include("path/to/file")
の行をそのファイルの中身で展開するだけ。{% include footer.html %}
{% include {{ page.my_variable }} %}
% for i in 0..<10 { %! include("file\(i).gysbi") % }
%!
のマクロ言語はテンプレート処理系の前段にあるとしていますinclude
を関数として実装できないかな?write
するgysbi
ファイルに対して gysb
を実行して得られた文字列を挿入すれば。%!
も排除できる。brew
のバイナリ配布、sourcery
がSwiftPMでビルドしたものを使ってる。 https://github.com/Homebrew/homebrew-core/blob/master/Formula/sourcery.rbbottles do ... end
にバイナリの置き場所書けば対応で、省略すればインストール先でビルド必要な認識でした。 (edited)[swift-evolution] update on forum Ted Kremenek via swift-evolution The decision to move to a forum was announced a while ago, and it hasn’t appeared yet. I think we will be making the move soon and I wanted to provide some reasons why it was delayed and what comes next. ... My hope is that process will start in December.
yaml ならいけるかもしれませんが、 gysb の実行に YAML パーサが必要になって依存が生まれてしまいそう・・・
一応書いておくと、YamsはCodable
をサポートしたYAMLパーサです。Yams自身には外部ライブラリ依存はなくて、利用実績としてはSwiftLintが.swiftlint.yml
のパースに使っています。$(brew --repository homebrew/core) git remote add omochi https://github.com/omochi/homebrew-core.git
したら、次のコマンドでformula作成: brew create https://github.com/omochi/gysb/archive/0.8.6.tar.gz
して、出来たgysb.rb
のdepends_on
, def install
, test do
を https://github.com/Homebrew/homebrew-core/blob/master/Formula/sourcery.rb 辺りを参考に設定して、 brew install --verbose --debug gysb
でインストールテストして、 cd $(brew --repo homebrew/core) git checkout -b gysb git add Formula/gysb.rb git commit git push https://github.com/omochi/homebrew-core/ gysb
してPR、って感じかな?Makefile
とか不要。class Gysb < Formula desc "Generate your swifty boilerplate" homepage "" url "https://github.com/omochi/gysb/archive/0.8.6.tar.gz" sha256 "139fd7225442c74e943b32716158a3ea5bd438241372a3cf913fd5313793248e" depends_on :xcode => ["9.0", :build] def install system "swift", "build", "--disable-sandbox", "-c", "release", "-Xswiftc", "-static-stdlib" bin.install ".build/x86_64-apple-macosx10.10/release/gysb" end test do # `test do` will create, run in and delete a temporary directory. # # This test will fail and we won't accept that! For Homebrew/homebrew-core # this will need to be a test that verifies the functionality of the # software. Run the test with `brew test gysb`. Options passed # to `brew install` such as `--HEAD` also need to be provided to `brew test`. # # The installed folder is not in the path, so use the entire path to any # executables being tested: `system "#{bin}/program", "do", "something"`. system "true" end end
test do
にsystem "true"
とか書いたけど、そこは真面目に書き換えないといけない。sourcery --version
で返すかどうか、かな。+struct ParameterizedStruct<T> { + mutating func takesFunctionWithGenericReturnType(_ f: (Int) -> T) {} +}
これがArrayに相当してるのかgit tag --contains cf9a09e18dba7a7fe0506381589fbf0f4bb99a98
で何も出ない。swift-DEVELOPMENT-SNAPSHOT-2017-11-21-a
出てる。func processPo<X: ConstPo>(po: X, process: (X.Element) -> Void) {
これでokconst
の場合と違って、型ごと CostoPo
を満たさないといけないの微妙そう。struct
じゃダメ? Swift の class
は二級市民だと思ってる。View
に対応した ViewModel を struct
で作って渡すとか?View
自体を操作する関数だとダメだけど。const
にしたいくらいだから View
から情報をとりたいだけに見える)enum Hoge { case fuga(Int) case piyo(Int) var count: Int { switch self { case .fuga(let count), .piyo(let count): // <- ここ return count } } }
let count
だからいける?protocol ProtocolA {} enum Hoge { case fuga(ProtocolA) case piyo(ProtocolA) var count: ProtocolA { switch self { case .fuga(let count), .piyo(let count): return count } } }
Playground execution failed: error: MyPlayground.playground:5:24: error: matching a protocol value in multiple patterns is not yet supported; use separate cases instead case .fuga(let count), .piyo(let count): ^
protocol ProtocolA {} enum Hoge<T: ProtocolA> { case fuga(T) case piyo(T) var count: T { switch self { case .fuga(let count), .piyo(let count): return count } } }
let a: Int? = 42 if case let a? = a { print(a) }
int *a = ...; *a = 42;
って書くのと似てるよね。 (edited)*a
が int
型というのと、 a?
が Int
型というのが。a?
は Int 型ではないですよねa?
は Optional<Int> だからこそ a
の部分だけが Int
a?
は Int?
で a
が Int
か。*a
が int
で a
は int *
。protocol ProtocolA {} enum Hoge<T: ProtocolA> { case fuga(T) case piyo(T) func value<T>() -> T { switch self { case .fuga(let value), .piyo(let value): return value } } }
error: MyPlayground.playground:6:20: error: cannot convert return expression of type 'T' to return type 'T' return value ^~~~~ as! T
typealias Tuple = (Int, String) enum Hoge { case fuga(Int) case piyo(Tuple) var value: Int { switch self { case .fuga(let value), .piyo((let value, _)): return value } } }
case let [first, second, third]:
みたいな。error: MyPlayground.playground:6:20: error: cannot convert return expression of type 'T' to return type 'T' return value ^~~~~ as! T
これは真っ当なエラーでは…Token
と tok
と Tok
が出てきて、Tok
の定義が全然見つからないと思ったら Token
型のフィールド名が Tok
だった・・・tok
は enumsnake_case_
ですね、他のC++プロダクトをそんなに読んでないのでわからないですがCMake -G Xcode
Tok
でジャンプできたぞw--release-debuginfo --xcode
でビルドしたらclang: error: no such file or directory: '/Users/omochi/work/swift-source/build/Xcode-RelWithDebInfoAssert/cmark-macosx-x86_64/src/Debug/libcmark.a'
と出ていて (edited)/Users/omochi/work/swift-source/build/Xcode-RelWithDebInfoAssert/cmark-macosx-x86_64/src/RelWithDebInfo/libcmark.a
--release-debuginfo
なのに cmark は --debug
で参照しちゃっててうまくいってないみたいなんですけど--xcode
は作業用、 ninja でビルド するのが良いのか? release-debuginfo があまりメンテナンスされていないので、 release にするのが良いのか? とか、どうなんでしょう--xcode
のせいなのか、そうでないのか調べるために ninja でもやってみます。 /Users/omochi/work/swift-source/build/Xcode-ReleaseAssert/swift-macosx-x86_64/Release/bin/swiftc -apinotes -yaml-to-binary -o /Users/omochi/work/swift-source/build/Xcode-ReleaseAssert/swift-macosx-x86_64/Release/lib/swift/macosx/x86_64/ScriptingBridge.apinotesc -target x86_64-apple-macosx10.9 /Users/omochi/work/swift-source/swift/apinotes/ScriptingBridge.apinotes
/Users/omochi/work/swift-source/build/Xcode-ReleaseAssert/swift-macosx-x86_64/Release/bin/swiftc -apinotes -yaml-to-binary -o /Users/omochi/work/swift-source/build/Xcode-ReleaseAssert/swift-macosx-x86_64/Release/lib/swift/macosx/x86_64/ScriptingBridge.apinotesc -target x86_64-apple-macosx10.9 /Users/omochi/work/swift-source/swift/apinotes/ScriptingBridge.apinotes
出力先 /Users/omochi/work/swift-source/build/Xcode-ReleaseAssert/swift-macosx-x86_64/Release/lib/swift/macosx/x86_64
が存在してなかったが、 /Users/omochi/work/swift-source/build/Xcode-ReleaseAssert/swift-macosx-x86_64/Release/lib/swift
は存在していたので、 mkdir
してやったら、いけました。class ViewBindingHelper<Model> { ... } protocol ViewBindingHelperUser { associatedtype Model var helper: ViewBindingHelper<Model> { get } } extension ViewBindingHelperUser { 追加される機能 }
class ProductListTableView : NSTableView, ViewBindingHelperUser { let helper: ViewBindingHelper<ProductList> = .init() }
(edited)User
の方のプロトコルコンフォーマンスは解除して、 .helper.method
でヘルパ名をネームスペース代わりにするしか無さそう。protocol MyViewProtocol { var button: Button { get } } protocol HasMyViewProtocol: MyViewProtocol { associatedtype MyView: MyViewProtocol var myView: MyView { get } } extension HasMyViewProtocol { var button: Button { return myView.button } }
extension MyViewProtocol
に置けば全部使えるようになる-swift-version 3
を使うとSwift 3.3になるぽい。 $ TOOLCHAINS=org.swift.4120171207a swift -swift-version 3 Welcome to Apple Swift version 4.1-dev (LLVM 67b9a8e8c2, Clang e617c83242, Swift 65b4172032). Type :help for assistance. 1> #if swift(>=4.1) 2. let versions = "swift-4.1" 3. #elseif swift(>=4.0.3) 4. let versions = "swift-4.0.3" 5. #elseif swift(>=4.0.2) 6. let versions = "swift-4.0.2" 7. #elseif swift(>=4.0) 8. let versions = "swift-4.0" 9. #elseif swift(>=3.3) 10. let versions = "swift-3.3" 11. #elseif swift(>=3.2.3) 12. let versions = "swift-3.2.3" 13. #elseif swift(>=3.2.2) 14. let versions = "swift-3.2.2" 15. #else // if swift(>=3.2) 16. let versions = "swift-3.2" 17. #endif 18. versions: String = "swift-3.3" 18>
(edited)subject.value()
がthrowsなのってなんでなんだろAVAudioFile
もなぜか AVAudioFramePosition
は Int64
なのに AVAudioFrameCount
は逆に UInt32
しかないという不可解な現象 https://qiita.com/lovee/items/8bdf7b58d96d683d31b9AUAudioFrameCount
で自分が上げたのは AVAudioFrameCount
なんですよな…This alias is type `uint32_t` for impedance-matching with the pervasive use of `UInt32` in the Audio Toolbox framework and the C Audio Unit framework APIs, as well as the `AVAudioFrameCount` data type.
(edited)var length: AVAudioFramePosition The number of sample frames in the file. typealias AVAudioFrameCount A number of audio sample frames.
この説明がすでに色々理不尽な気が…(CのAPIに合わせてるのなら逆にじゃあなぜCではcountだけが32bitなのか…ComponentResult AudioUnitRender( AudioUnit ci, AudioUnitRenderActionFlags* ioActionFlags, const AudioTimeStamp* inTimeStamp, UInt32 inOutputBusNumber, UInt32 inNumberFrames, AudioBufferList* ioData )
inNumberFrames The number of frames to be rendered. (edited)SInt32 startBufferOffset
これだけ読むとやはりCでは両方32bitにしてるけどAVFoundationがなぜかpositionだけ64bitにしてるんですよね… (edited)UInt32 bufferOffset; bufferOffset Where in the current buffer the event should occur
(edited)GL_PROJECTION // Int32 glMatrixMode(GLenum(GL_PROJECTION)) // Obj-C (C) ではそのまま渡せた
(edited)static var GL_PROJECTION: GLenum
ってオーバレイ用意してほしいですね。#define
だったマクロがそのまま Int32 としてポーティングされてしまっている#define
の数値リテラル?はInt32
になるよね (edited)#include <stdio.h> #define BIG_NUMBER (0xffffffffffffffff) void printHex(unsigned long long number) { printf("%llx\n", number); } int main(void) { printHex(BIG_NUMBER); return 0; }
#define NAME "aaa"
みたいなのもありえるので#define
は型を判定してるのかな?AVFoundation.framework/Frameworks/AVFAudio.framework/Headers/AVAudioTypes.h
/*! @typedef AVAudioFrameCount @abstract A number of audio sample frames. @discussion Rationale: making this a potentially larger-than-32-bit type like NSUInteger would open the door to a large set of runtime failures due to underlying implementations' use of UInt32. TODO: Remove rationales. */ typedef uint32_t AVAudioFrameCount;
TODO: Remove rationales.
は具体的に何を指しているのか… int
が double
に暗黙の型変換されてて、 double c = a / b;
( a
と b
が Android の API のコールで int
が返される)の精度が落ちてしまっている事例が社内で発覚した。やっぱり数値間ですら暗黙の型変換を許さない Swift の方向性は正しかったんだ〜 (edited)/
書く時はトラウマが呼び起こされてミスしない体になったc
の型を書かずに let
にしていた結果、 Int のまま以降の行まで型推論が伝搬していって、/
書く時は周囲に型をだいぶ明示的に書きたくなるlet t = 1 / 2 ... なんか処理 ... TimeInterval(t)
/
は常に実数除算への昇格で、 整数のあまり切り捨て除算は別の演算子になってることもあるね。$ python Python 3.6.1 (default, Apr 19 2017, 14:30:24) [GCC 4.2.1 Compatible Apple LLVM 8.1.0 (clang-802.0.41)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> 3 / 2 1.5 >>> 3 // 2 1
//
があった気がしてたけどpythonか。JSONEncoder
のconvertToSnakeCase
はmyURLProperty
をmy_url_property
に変換するのだけれど、JSONDecoder
のconvertFromSnakeCase
はmy_url_property
をmyUrlProperty
へ変換するので、デコードに失敗する。 https://bugs.swift.org/browse/SR-6629convertFromSnakeCase
の実装がまずい。既存CodingKeys
のstringValue
のlowercased
とJSONのキーから_
を削除した文字列を比較して、一致するCodingKeys
メンバを決定しないといけない。 (edited)String
に汎用のsnake_cased
プロパティとかあった方が良さそう。CodingKeys の stringValue から、 encoder側の convertToSnakeCase と同じ変換をかけてから そのキーで JSON のバリューを読めば、ストレートな処理になりませんか?
今の実装のconvertFromSnakeCase
が色々な表記ゆれをサポートしてるせいで、その方法で上位互換にするのは無理かも。 (edited)YAMLDecoder
で試しに実装してみた。 https://github.com/jpsim/Yams/pull/92JSONDecoder
の実装は無駄に凝りすぎだと思う。typedef NS_ENUM(NSInteger, State) { StateHoge = 0, StateHuga = 1, };
Swift: let state = State(rawValue: 100)! switch state { case .hoge: print("hoge") // ★↑これが実行される case .huga: print("huga") }
State(rawValue: 100)
が nil
にならないところが Swift 的に変で、そこのチェックが漏れてるのかもしれませんね。state.rawValue
は 100
ですか? 0
ですか?switch
で何が起こるかは仕様として決まってないんじゃないかと思います。#include <Foundation/Foundation.h> typedef NS_ENUM(NSInteger, State) { StateHoge = 0, StateHuga = 1, };
main.swift public func foo(state: State) -> Int { switch state { case .hoge: return 1 case .huga: return 2 } } let s = State(rawValue: 100)! print(foo(state: s))
実行 $ swift -import-objc-header enums.h main.swift 1 $ swift -O -import-objc-header enums.h main.swift 2
(edited)-O
有無で結果が違うのはちょっと受け入れられない。Numeric
って ExpressibleByIntegerLiteral
を継承してるのに Int
のイニシャライザに Numeric
を受けるやつないのか…?// Integer literals are limited to 2048 bits.
というコメントが。 https://github.com/apple/swift/blob/0cf1b52452f56b3bbdf2f2305cc10fef42bdff8b/stdlib/public/core/Policy.swift#L99 (edited)Numeric
が ExpressibleByIntegerLiteral
なのはよくわかんないですよね。行列とかで使えなくなっちゃいますし。Numeric
よりも、群・環・体 https://qiita.com/taketo1024/items/733e0ecf12da359db729 みたいなプロトコルほしいですよね。Addable
, Multipliable
とかの方がプログラミング的には使い勝手がいいのかも?BinaryInteger
とFloatingPoint
で分けて実装してるのが一本化できるString
って subscript { set }
ができないからイミュータブルなのかと思ってたけど違った。 1> var s = "ABC" s: String = "ABC" 2> s.removeLast() $R0: Character = { _representation = smallUTF16 { smallUTF16 = 67 } } 3> print(s) AB
subscript { set }
ができないのは、 Character
が何バイトか定まらないから O(1) で実現できないからか。subscript { set }
を実現できない。append
とか removeLast
とかって MutableCollection
についてるのかと思ってたけど違った。で、 subscript { set }
がないから String
は MutableCollection
じゃないだろう→ append
や removeLast
もないだろうと思って勘違いしてた。 https://developer.apple.com/documentation/swift/mutablecollection (edited)String
でも平均 O(1) で実現できて問題ないのか。 (edited)faillthrough
のユースケース?それとも^のコードですか?func tokenize(source: String) -> [Token] { let state = State(input: source) for character in state.input { switch state.mode { case .plain: switch character { case "'": state.mode = .symbol case "\"": state.mode = .string case "\n": state.mode = .newline state.storage = "" case "(", ")", ":": state.tokens.append(Token(type: .token, value: String(character))) case " ": break default: state.mode = .token state.storage = String(character) }
protocol ValueProducer { associatedtype Value var value: Value { get } }
↑これ自作してさprotocol ValueProducer : ObservableConvertible { associatedtype Value var value: Value { get } }
#if _runtime(_ObjC)
でのString
のhashValue
はそもそも文字列全体を使わないはずです。
import Foundation let first32Char = repeatElement("f", count: 32) let middle32Char = repeatElement("m", count: 32) let last32Char = repeatElement("l", count: 32) let a = (first32Char + ["ab"] + middle32Char + ["ab"] + last32Char).joined() let b = (first32Char + ["bc"] + middle32Char + ["bc"] + last32Char).joined() a == b // false // Foundation a.hash // -4528083392938427260 b.hash // -4528083392938427260 // Swift.Hashable a.hashValue // -8957072229412966235 b.hashValue // -8957072229412966235
hash
は同じ。hash
をファイル変更検知に使ってバグってたことがあった時に調べた。 https://github.com/realm/SwiftLint/issues/1184#issuecomment-274744331enum HogeType: Int { case aaa = 1 case bbb case ccc }
↑ この書き方嫌いなんですけど、意外と賛同してくれる人少ないんだろうかと思ってるんですがどうですか enum HogeType: Int { case aaa = 1 case bbb = 2 case ccc = 3 }
IntのrawValueつけるなら全case明示してほしい。Raw value for enum case is not unique
というエラーが出たclass A { weak lazy var hoge: B? = nil } class B {}
これなんか変なコンパイルエラーなったPlayground execution failed: error: cannot convert return expression of type 'B?' to return type 'B?' error: cannot assign value of type 'B?' to type 'B??' error: cannot assign value of type 'B?' to type 'B??'
lazy
なくすとエラーなくなるんだけど、 lazy
ってその変数の型には影響しないよねweak
+ lazy
? が参照持てないし使えないのかなと思ったりretain count
が増えないのが問題なのかなと思いました ってうまく説明できそうな気がしたが感覚でしかわかってないな。。。cannot assign value of type 'B?' to type 'B??'
で、lazyが無いとそのエラーが消えるということは、lazyのあるなしでそのプロパティの型が実は変わっているようなきがするclass A { weak lazy var hoge: B? = B() } class B {}
でもこれはこれですぐ解放されるので あまり通って欲しくもない気がするclass A { weak lazy var hoge: B = B() } class B {}
nil
になるならまだいいんですけど これだとなおわからない気がするnil
になっちゃうんですね class A { lazy var hoge: B! = B() } class B {} let a = A() a.hoge a.hoge = nil a.hoge
あー、じゃあ、僕の会話していた時の頭の中が古かった 前まではもう一度初期化されていたはずだから weak
+ lazy
??? ってなってましたlet a = A() a.hoge // B a.hoge = nil // nil a.hoge // nil
Swift3 let a = A() a.hoge // B a.hoge = nil // nil a.hoge // B
こういうこと3.1
かどうかは置いておいてこういう時代があったんですよね Resolved
B??
と解釈されてるかどうかが変わっているきがするんだけどどうclass A { weak lazy var hoge: B? = { return B??.none }() } class B {}
Playground execution failed: error: cannot convert return expression of type 'B?' to return type 'B?' error: MyPlayground.playground:4:30: error: cannot convert value of type 'B??' to specified type 'B?' weak lazy var hoge: B? = { ^ error: cannot assign value of type 'B?' to type 'B??' error: cannot assign value of type 'B?' to type 'B??'
let articlesVC = ArticlesViewController.init { return ArticlesViewModel.init(dataProvider: ArticlesAPIDataProvider.init()) }
本番のコードなんで文脈なくてすまんやけどuninitialized()
にすればいけんちゃうみたいなuninitialized()
は中身fatalErrorの func uninitialized<T>() -> T
class VC {} class VM { private weak var _vc: VC? = nil var vc: VC { get { return _vc ?? undefined() } set { _vc = vc } } }
class LazyWeak<T> { private weak var _value: T? = nil private func undefined() -> T { fatalError() } var value: T { get { return _value ?? undefined() } set { _value = value } } } class VM { var vc = LazyWeak<VC>() }
こういうイメッジclass A { unowned lazy var hoge: B = B() } class B {}
Playground execution failed: error: cannot convert return expression of type 'B' to return type 'B' error: MyPlayground.playground:4:32: error: cannot convert value of type 'B' to specified type 'B' unowned lazy var hoge: B = B() ^~~ error: cannot assign value of type 'B' to type 'B?' error: cannot assign value of type 'B' to type 'B?'
hoge: B!
だとなんか違う怒られするclass A { var block: (() -> ()) = {} func hoge(block: @escaping (() -> ())) { self.block = block block() } } class VC { func viewDidLoad() { let a = A.init() a.hoge { [unowned self] in print(self) } } } VC.init().viewDidLoad()
__lldb_expr_98.VC
.rx
が 生えてるやつでできることを、それ単体だけ Rx 全部を導入しないで採用できないか、ってのがコアアイデアですかね?class DelegateHolder { weak var delegate: SomethingDelegate? } let holder = DelegateHolder() // これは弱参照で持ってほしい。 holder.delegate = SomethingDelegateImpl() // これは強参照で持ってほしい。なぜなら、これを弱参照にすると map の戻り値の参照を誰も保持してないのですぐに回収されてしまうから。 holder.delegate = SomethingDelegateImpl() .map { a in a * 2 } // この差異を吸収するために、weak と strong の両方を持てるインターフェースを持つ必要があった。これを実現しているのが AnyDelegate。
GenericError
みたいな型を定義するError
を定義する。言語仕様の方のやつと衝突しちゃうのでそっちを使う時は Swift.Error
と完全名で記述するNSError
を使うprotocol DescribedError: Error, CustomStringConvertible { }
typealias DescribedError = Error & CustomStringConvertible
とかでもいいのかな。enum Error: DescribedError
って書きたいからextension String : Error {} func a() throws { throw "error message" } do { try a() } catch let e { print(e) // "error message\n" }
XCTAssert(max(a, b) == c) | | | | | 7 4 7 | 12 false XCTAssert(a + b > c) | | | | | 4 | 7 | 12 11 false XCTAssert(john.isTeenager) | | | false Person(name: "John", age: 42) XCTAssert(mike.isTeenager && john.age < mike.age) | | | | | | | | | false | | 42 | | 13 | | | | Person(name: "Mike", age: 13) | | | false | | Person(name: "John", age: 42) | false Person(name: "Mike", age: 13)
swift-power-assert xctest -Xxcodebuild test -workspace <workspacename> -scheme <schemeName> -sdk iphonesimulator -destination "name=iPhone X,OS=11.2"
Chris_Lattner3
とかいう、めっちゃアカウント生成トラブった感じの名前になってるけどwRelease_Notes_for_Xcode_9.3_beta.pdf
より ## Known Issues in Xcode 9.3 beta ### Swift Compiler - Conditional conformances are unsupported when performing a dynamic cast (with is or as).
これってSwift 4.1リリースでも直らないんだよね? (edited)protocol P { } extension Int: P { } // Fully supported: Set unconditionally conforms to P extension Set: P { } // Not supported in dynamic casts: Array conforms to P // only when its element conforms to P extension Array: P where Element: P { } func castToP(_ value: Any) { if value is P { print("\(type(of: value)) conforms to P"); } else { print("\(type(of: value)) does not conform to P") } } castToP(Set([1, 2, 3])) // unconditional conformances // are supported: // prints "Set<Int> conforms to P castToP([1, 2, 3]) // unsupported conditional conformance: // incorrectly prints "Array<Int> does not // conform to P" castToP([3.141593, 2.71828]) // unsupported conditional conformance: // correctly prints "Array<Double> does not // conform to P"
(edited)flatMap
のdeprecationはSwift 4.1とSwift 3.3両方だから、4.0.xと3.2.x互換を維持する場合のcompactMap
定義は #if (!swift(>=4.1) && swift(>=4.0)) || !swift(>=3.3) extension Array { public func compactMap(_ transform: (Element) throws -> String?) rethrows -> [String] { return try flatMap(transform) } } …
みたいに書く必要があるのか。 (edited)#if (!swift(>=4.1) && swift(>=4.0)) || !swift(>=3.3)
だった。public protocol Po { func doHoge() } extension Po { public static func getDefaultInstance() -> Po { return DefaultPo() } } internal class DefaultPo: Po { func doHoge() {} } // let po = Po.getDefaultInstance() <- Compile error let po = DefaultPo.getDefaultInstance()
なのに今さら気づいた… Protocol は適合する対象であって型としては存在はしないんだなぁというのを実感したfunc hoge(po: Po) // dame func hoge<X: Po>(po: X) // OK
なのも実感として納得がいった (edited)assert
やprecondition
にクロージャ渡せたらループチェックとかかきやすくて良いんじゃないかと思うんですがどうですかね? もとの定義が@autoclosure
なのでそれはずしたのをオーバーロードするだけで行けると思うんですが。assert
やprecondition
は最適化によってcondition
を評価しないだけで呼出し自体が消えるんじゃないみたいですね。 ずっと勘違いしてました。condition
is not evaluated in /// -Ounchecked
builds. In -Ounchecked builds, condition is not evaluated, but the optimizer may assume that it always evaluates to true. Failure to satisfy that assumption is a serious programming error.
precondition(items.all { $0 >= 0 })
これでいいじゃんlet a = [0, 2, 4, 6] assert({ // all even for e in a { guard e % 2 == 0 else { return false } } return true }())
()
を消したいってこと?typealias CountableRange
がなかったんですが、 4.1 でそれを突っ込むと結構大きめの破壊的変更になる気が。これは 5 で入る PR ですか?typealias
でも破壊的か。オーバーロードとか死ぬし。 (edited)typealias O<X> = Optional<X> where X: Sequence O<String>.some("a") O<Int>.some(1) // Error
壊れなくなった可能性があるtypealias O<X> = Optional<X> where X: Sequence O<String>.some("a") //O<Int>.some(1) // Error extension O { func foo() { print("foo") } } Optional<Int>.some(1).foo() //????
Swift compiler integration with external tools Potential mentors Rintaro Ishizaki
## Swift compiler integration with external tools ## Integration of libSyntax with the rest of the compiler pipeline. ### Potential mentors Rintaro Ishizaki
(edited)What are the eligibility requirements for participation? ・You must be at least 18 years of age
do
使う場合は変数多くてメソッド分けたくない場合な気がしますねlet hogeObservable
と let fugaObservable
をこねこね作って、Observable.merge(hogeObservable, fugaObservable)
みたいに書きたい時に、 hogeObservable
と fugaObservable
というローカル変数はなるべくスコープを短くしたいhogeFugaSubscription: do { ... }
do
派です。ローカル関数やクロージャ式にすると実行順がコードの記述順と入れ替わる可能性があり、それを意識しないといけないのが難点だと思います。{ ... }()
はわかってればいいけど可読性的に微妙かなと。do
だと内部から break
等できるけど、ローカル関数やクロージャ式だとできないというのもあります。{ ... }()
の方が読みやすい感覚があるんですよね。do{}
はパッと見てtryか、と思ってしまうので。do { ... // 開始処理 defer { ... // 終了処理 } guard ... { ... break } ... }
do
を抜けるタイミングで終了処理を挟み込みたかったんですが、早期脱出もしたかったので、両方の終了処理を共通化しようとしたらこうなったけど、可読性は低いよなぁと。共通化を諦めて個別に書いた方がいい気もしてます。 while ... { do { ... // 開始処理 defer { ... // 終了処理 } guard ... { ... break } ... } ... }
do
より関数やメソッドに分割が望ましいと思います。
public func AAAAAAA(x: Int) { func step1() { /* ... */ } func step2() { /* ... */ } step1() step2() } public func BBBBBBB(x: Int) { ({ // step 1 /* ... */ })() ({ // step 2 /* ... */ })() } public func CCCCCCC(x: Int) { STEP1: do { /* ... */ } STEP2: do { /* ... */ } }
/* ... */
に十分長い処理を書いて試したところ、-O
でも 内部 func と クロージャはインライン化されなかったです。ちょっと意外。LOOP: while ... { ACT1: do { ... // 開始処理 defer { ... // 終了処理 } guard ... { ... break ACT1 } ... } ... }
こうかなdo
を使うといいながらメソッドに切り出した方がいいというのは変だ・・・。func step1() {
の定義は自然に読み飛ばすので、私の目には step1() step2() だけに見える。CCCCCCC
が読みやすいですね。do
を使いたいという気持ちでした。
let a = ... let b: B do { let t = ... // ちょっと複雑な式 b = foo(t, a) } let c = ...
t
を foo()
の中に書けるけど、可読性のために変数に入れて名前を付けたくて、かといってそれを長々と生かしたくないみたいなケースです。t
で済む一時変数にどこで何に使われてるかわかる説明的な名前を付ける必要が出てきませんかt
という名前を付けることを意図したわけじゃないですが、僕はそのコンテクストでできるだけシンプルな名前を使うのが好きなので、後続処理と名前がかぶって困るということは結構ある気がします。do
なくてもいいんですが、 10-20 行くらいになってくると一度スコープ切っておきたいですね。func これこれこういうイベントで発火するObservableだよ() -> Observable<E> func viewDidLoad() { これこれこういうイベントで発火するObservableだよ() .subscribe { 期待した結果やで } .disposed(by: disposeBag) }
func setupこれこれこういうイベントで発火する奴() { viewModel.hoge.subscribe().disposed(by: bag) }
こうなってるのがいっぱいある。func これこれこういうイベントで発火するObservableだよ() -> Observable<E>
<= これ自体は何回呼んでも、いつ呼んでもいいわけですよね?func outer() { var state1 = ... var state2 = ... func inner1() { } func inner2() {} inner1() inner2() }
↑これ系のスタイルはclass HogeSetUpHelper { var state1 var state2 func inner1() func inner2() func setUp(...) } func outer() { HogeSetUpHelper().setUp(self) }
HogeSetUpHelper().setUp(self)
viewDidLoad
と viewDidUnload
の話だ。class X { lazy var setup: Void = { // only 1 time call here }() }
_ = setup
?class X { lazy var setup: () -> Void = { print("a") return { } }() } let x = X() x.setup()
ほらよ (edited)func nop() { } typealias Setup = () -> Void class X { lazy var setup: Setup = { // 1回だけ return nop }() }
少し見た目をマシにしてみたlet setup = once { }
こういう高階関数作れそうじゃない?fooLoop { (`break`: () -> Never) in ... }
みたいな break
を作りたかったけどできなくて悲しくなった。lazy
内 で self
参照出来るっていうのは正式にOKになったんだっけか。func nop() {} func once(_ f: () -> Void) -> () -> Void { f() return nop } class X { lazy var setup = once { print("1time?") } } let x = X.init() x.setup() x.setup()
public func once<T, R>(_ f: @escaping (T) -> R) -> (T) -> R { var done: Bool = false return { (t: T) -> R in guard !done else { fatalError("do not twice") } done = true return f(t) } }
(edited)public func once<T, R>(_ f: @escaping (T) -> R) -> (T) -> R { var done: Bool = false return { (t: T) -> R in guard !done else { fatalError("do not twice") } done = true return f(t) } } public class Cat { public init(name: String) { self.name = name self.onBorn() } public var name: String public func onBorn() { _onBorn(self) } private let _onBorn: (Cat) -> Void = once { `self` in print("\(self.name)がうまれた") } } Cat(name: "tama")
onBorn
を let にしたかったけど self がキャプチャできなかったので func onBorn
と let _onBorn
に分かれてしまう。public class Cat { public init(name: String) { self.name = name self.onBorn() } public var name: String public lazy var onBorn: () -> Void = once { [unowned self] in print("\(self.name)がうまれた") } }
once
動かないのでは。public func once<T, R>(_ f: @escaping (T) -> R) -> (T) -> R { var done: Bool = false return { (t: T) -> R in guard !done else { fatalError("do not twice") } done = true return f(t) } } class Cat { let born = once { () in print("mew") } } let c = Cat() c.born(()) c.born(())
public class Cat { public init(name: String) { self.name = name self.onBorn() } public var name: String public lazy var onBorn: () -> Void = once { [unowned self] in print("\(self.name)がうまれた") } }
[weak self] _ in guard let `self` = self else { return }
これで (edited)deinit
ちゃんと呼ばれるのね。 func once(_ f: () -> Void) -> () -> Void { f() return {} } public class Cat { public init(name: String) { self.name = name self.onBorn self.onBorn } public var name: String public lazy var onBorn = once { print("\(self.name)がうまれた") } deinit { print("deinit") } } do { Cat(name: "test") }
once
がVoid
ではなく() -> Void
を返すのも地味に良い。Void
だとlazy
の受け側に型指定がないとwarningが出るので。lazy
でself
参照出来るようになったのはSwift 4.0から?public struct S { init() {} public lazy var p = self.f() func f() -> String { return "f()" } } var s = S() s.p
が error: use of unresolved identifier 'self' public lazy var p = self.f() ^~~~
になります。 (edited)swift-4.0-DEVELOPMENT-SNAPSHOT-2017-06-06-a
以降ですね。if case
パターンって、キャスト?もされるのね。知らなかった。 import Foundation enum MyErrorEnum: Error { case message(String) } struct MyErrorStruct: Error {} class MyErrorClass: Error {} extension String: Error {} func check(error: Error) { if case MyErrorEnum.message = error { print("expected error: \(error)") } else { print("unexpected error: \(error)") } } check(error: MyErrorEnum.message("error")) check(error: NSError(domain: "custom error", code: -1, userInfo: nil)) check(error: MyErrorStruct()) check(error: MyErrorClass()) check(error: "StringError")
expected error: message("error") unexpected error: Error Domain=custom error Code=-1 "(null)" unexpected error: MyErrorStruct() unexpected error: __lldb_expr_90.MyErrorClass unexpected error: StringError
(edited)XCTAssertThrowsError(try YAMLDecoder().decode(Sample.self, from: invalidYaml)) { error in if case DecodingError.typeMismatch(_, _) = error {} else { XCTFail("unexpected error: \(error)") } }
の様に記述できる。 (edited)switch x { case 0: break case 1: print(y) print(z) default: print(y) print(z) }
こういう複数のcase
を1行に書いたら構文エラーをレポートする。コンパイルはswiftcだからビルドはできる。独自Parserがあるんだな。Consecutive statements on a line must be separated by ';'
になっちゃうと思いますが。case 1
の時に print(y);print(z)
の動作ですか?case 1
見落としやすいので構文エラーにして欲しい感 is ある func foo() {} func bar() {}
これも曖昧ではないけどエラーになるので、同じポリシーで行くべきだと思います。class A{}; protocol B {};
とかはセミコロン必要ですよね。if value==1 {}
はOKだけどif velue!=1 {}
これがダメなのは理解できるけどわかりにくいから演算子は全部スペース必要でいいんじゃないかと思ったりしてます。0..<(n*2)
(edited)...
や..<
と変わるのが微妙そうですね0 ..< 3
と..<3
で違うスペースの入れ方が強制されるのは微妙だなと..<3
は許されるのに 1..<3
が許されないのは揃ってないということか..< 3
が許されてないのはいいんかという話にもなりかねませんがprotocol A { associatedtype B associatedtype C where C == B.Hoge } struct D: A { typealias B = String typealias C = String }
where C == B.Hoge
のHoge
という型がBに無いのにコンパイルが通ってしまった。where
句の制約は無視されるようになってしまいましたprotocol HasHoge { associatedtype Hoge } protocol A { associatedtype B: HasHoge associatedtype C where C == B.Hoge } struct D: A { typealias B = String typealias C = String }
健全な形はこうか。B.Hoge
って書いてある時点でエラーになりそうなのに確かに通るねSomeType: SomeProtocol
みたいなジェネリクスはもちろん必要だけど、逆に SomeType: !SomeProtocol
みたいなジェネリクスも地味に欲しいよな…<T: FooEnum> where T != case .foo>
みたいなこともしたい・・・。case
の一部を禁じたいこと多い。enum
じゃなくて sealed class
で) (edited)public class Holder<T> {} extension Holder { public func ho() { print("ho1") } } extension Holder where T == String { @available(*, unavailable) public func ho() { print("ho2") } } let a = Holder<Int>() a.ho() // これでいけるかと思ったら ho1 が出力された・・・ let b = Holder<String>() b.ho()
作戦失敗 (edited)enum NetworkError: Error { case timedOut case cannotFindHost case notConnectedToInternet } enum MyAPIError: NetworkError { case responseInvalid case sessionExpired case notEnoughMinerals case insufficientVespineGas }
(edited)case
を追加できちゃわない?: NetworkError
だけど、 NetworkError
として扱えるわけではない?? (edited)enum Foo: Int
は Int
に入れられるわけじゃないからいいのかな?: Foo
に新たな概念を追加することになるのか・・・。enum MyAPIError { spread case NetworkError case responseInvalid case sessionExpired case notEnoughMinerals case insufficientVespineGas }
↑こんな記法だったら良さそう。 (edited)T: !Optional
ですねwT: !Optional
fun <T: Any> foo()
(edited)// 親?クラス struct Animal { var name: String func speak() -> String { return "I am \(name)" } } // トリックここから protocol AnimalExtend { var animal: Animal { get set } var name: String { get set } func speak() -> String } extension AnimalExtend { var name: String { get { return animal.name } set { animal.name = newValue } } func speak() -> String { return animal.speak() } } // トリックここまで // ユーザー例 // プロトコル指定は継承指示 struct Cat : AnimalExtend { // コンパイルエラーがでるのでこれを定義 var animal: Animal // 必然的にこれも書くことになる init(name: String) { animal = Animal(name: name) } } print(Cat(name: "tama").speak()) // ok
Any?
がトップタイプですからねぇ。 Any
で縛れば nullable を弾けますが、 Swift の Optional
は union じゃないから同じことはできないんですよねぇ。Optional<Optional<T>>
ができるのは魅力的ですがOptional
のネストはほしいですね。つい最近もやっぱいるよなと思ったけど何だったかな・・・。struct
の継承もほしい。struct Path: String { // パス操作のための便利メソッド }
Path
を型として分離できるし、 String
として使いたいときはそのまま代入できる。transparent struct Path: String { }
みたいな。 (edited)Path is String
であるためには。let s: String = path
ができたい。func asString() -> String
が 自動で is や as で呼び出されれば大丈夫String is Path
も取りたいなら駄目ですけどねString is Path
だと意味がない。Path
のところに String
渡せてしまうから。.asString()
で。Path
はあくまで String
なんだけど、 Path
として扱っているときは String
を突っ込まれたくない。String
に Path
は入れたいけど Path
に String
は入れたくない。typealias Path = String
だと Path
に String
を突っ込めてしまうけどString
を引数にとる関数に Path
を渡すときにいちいち変換したくない。String
と Path
で話してるからわかりづらいのかも。struct Age: Int {}
Age
と Int
とかWeight: Int
と Height: Int
から BMI 計算するときにprotocol IntConvertible { func asInt() -> Int } extension Age : IntConvertible {}
こうしておいて、X: IntConvertibleで受ければFloat
と Double
はメモリレイアウトが違うし別の型だけどAge
は Int
の用途を絞りたいだけだから、Age is Int
は OK だと思うんよね。Float
とかにするわけでしょ?struct Weight { let value: Float }
とか作って区別するっていうならわかるけど。typealias TimeInterval = Double
じゃない?独自に作ったってこと?Float
にアップキャストされない方がいいような気もしてきた。1999年、NASAの火星探査衛星マーズ・クライメート・オービターは、制御プログラムの力の単位にポンド重とニュートンが混在していたために、計画よりはるかに低い軌道に投入されてしまい、火星大気との摩擦により墜落してして失われてしまいました。
単位計算のルールを型システムにエンコードできれば、コンパイル時にすべての単位エラーを検出できるはずです。
enum
と同じように、 struct Path: String
したら、 path.rawValue
で String
が得られるとかでいいのかも?わざわざ構文増やさなくても、↓書けばいいだけかな・・・。 struct Path { let rawValue: String }
public init
の実装必須のはず。 (edited): String
の意味はあるか?dispatch_once
で検索すると出てくる let myGlobal = { … global contains initialization in a call to a closure … }() _ = myGlobal // using myGlobal will invoke the initialization code only the first time it is used.
JSONEncoder
とJSONDecoder
互換のクラスを追加してみた。 https://github.com/norio-nomura/ObjectEncoder/pull/18JSONSerialization
へ渡す/から受け取るobjectをエンコード/デコードしてる。classの場合
のコードがうごくのはおかしいよねっとw https://qiita.com/noppefoxwolf/items/a9d2a103d54b2b1ea415class
でも self
を書き換え可能な mutating func
がほしいなぁと感じてます。static func
で違う Self
返すしかないですねFoo
に対して func update(foo: Foo, ...) -> Foo { ... }
と class Foo { func update(...) -> Foo { ... } }
があって、 (edited)var foo = ... foo = update(foo: foo, ...) foo = foo.update(...)
と書くのをclass User: Initializable { var id: Int = 1000 /* 暗黙の */ init() {} } extension Initializable { init() { self = Factory.make(type: Self.self) } } User()
で、暗黙の User.init()
に直接ディスパッチされていると思います。 (edited)func update(foo: inout Foo, ...) { ... }
のように inout
にして update(foo: &foo, ...)
はできるけど、 mutating func
がないので対応するメソッド版 update
を作れないです。mutating func
は self
を inout
に持つ関数という文脈で)Account
の id
の初期値をなくすと、それもそのままコンパイルできちゃってStackOverflowになりますinit(id: Int)
になるので Initializable.init()
と Factory.make(type:)
で無限再帰ですね。@tarunon さん、 @rintaro さんと @omochimetaru さんと議論して
パワーワードだwfunc bar() { foo() } func foo() { bar() }
(edited)@_transparent
つけると、先に展開されてからの検知になるので、警告してくれましたが。func generate() -> UInt32 { let a = arc4random_uniform(10) if a > 10 { return a } else { return generate() } }
func generate() -> UInt32 { let a = arc4random() % 10 if a > 10 { return a } else { return generate() } }
$ swift Welcome to Apple Swift version 4.1 (swiftlang-902.0.43 clang-902.0.37.1). Type :help for assistance. 1> Optional(1).map(dump) error: repl.swift:1:17: error: ambiguous reference to member 'dump(_:to:name:indent:maxDepth:maxItems:)' Optional(1).map(dump) ^~~~
(edited) 1> :type lookup dump @discardableResult @_inlineable @_semantics("optimize.sil.specialize.generic.never") func dump<T>(_ value: T, name: Swift.String? = default, indent: Swift.Int = default, maxDepth: Swift.Int = default, maxItems: Swift.Int = default) -> T @discardableResult @_inlineable @_semantics("optimize.sil.specialize.generic.never") func dump<T, TargetStream>(_ value: T, to target: inout TargetStream, name: Swift.String? = default, indent: Swift.Int = default, maxDepth: Swift.Int = default, maxItems: Swift.Int = default) -> T where TargetStream : TextOutputStream
#line
とか使っててマクロがないSwiftでは詰むfunc dump<T>(name: String?=nil, indent: Int=0, maxDepth: Int=0, maxItems: Int=0) -> (T) -> Void { return { value in dump(value, name: name, indent: indent, maxDepth: maxDepth, maxItems: maxItems) } } (Int?.none).map(dump())
f(a, b, c, d)
に対して 好きな引数を埋めた関数を得る操作があると便利か?extension Array { func mapSpecialized<U>(_ type: U.Type=U.self) -> ((Element) -> U) -> [U] { return { self.map($0) } } }
こういうの作るとmapを取り回せるようになるvar a = [2, 3, 5] var b = a a.withUnsafeMutableBufferPointer { $0.baseAddress!.pointee = -1 } print(a) // [-1, 3, 5] print(b) // [2, 3, 5]
var a = [2, 3, 5] var b = a a.withUnsafeBufferPointer { UnsafeMutablePointer(mutating: $0.baseAddress!).pointee = -1 } print(a) // [-1, 3, 5] print(b) // [-1, 3, 5]
withUnsafeMutable~~
は実行した瞬間コピーされてるんですかね? 中身で書き換えるかどうかまで判断してたら相当賢そうですけどwithUnsafeBufferPointer
使えばいいわけだし問題はなさそう。UnsafeMutablePointer
の pointee
に参照型のインスタンス set
するとリファレンスカウント増える??増えないと思ってた。 extension Array { mutating func update(_ body: (inout Element) throws -> ()) rethrows { let count = self.count try withUnsafeMutableBufferPointer { var pointer = $0.baseAddress! for _ in 0..<count { try body(&pointer.pointee) pointer += 1 } } } } class Cat { let name: String init(_ name: String) { self.name = name } deinit { print("deinit: \(name)") } } var a = [Cat("a"), Cat("b"), Cat("c")] a.update { $0 = Cat("\($0.name)2") }
deinit: a deinit: b deinit: c
UnsafeRawPointer
としてコピーとかすると壊れるのか。update
は問題なさそうだけど、これより速い実装ってあるかな?count
が無駄かと思ってポインタを比較してループ回してたけどDispatchQueue.concurrentPerform
を使ったconcurrentUpdate
とか。extension Array { mutating func update(_ body: (inout Element) throws -> ()) rethrows { let count = self.count try withUnsafeMutableBufferPointer { var pointer = $0.baseAddress! let end = pointer + count while pointer != end { try body(&pointer.pointee) pointer += 1 } } } }
getBase() ..< getBase() + count
を getBase()
一回で綺麗に書く構文って現状ありましたっけ? for pointer in $0.baseAddress! ..< $0.baseAddress! + count { try body(&pointer.pointee) }
をもっと短く書きたい。string[string.index(string.startIndex, offsetBy: 3) ..< string.index(string.startIndex, offestBy: 6)]
これも短く書きたい (edited)string[offset: 3..<6]
の議論はどんな感じなんだっけな。$0.baseAddress! ..< $0.baseAddress! + count
できるの知らなかったーinfix operator ~> : StridePrecedence prefix operator ~> infix operator ~>- : StridePrecedence prefix operator ~>- infix operator ...~> infix operator ...~>-
public func ~>-(range: CountableRange<Int>, stride: Int) -> NDArrayIndexElement { return range ~> (-stride) }
a~>-b
は a ~> (-b)
なのねoperator
の上書きが出来ることを初めて知った。 ~>
は stdlib で既に定義されているので、:soon:
入れると勝手に 出してくれるようになって欲しい(嘘 (edited)brew tap el-hoshino/zundoko brew install zundoko
そして使い方は zundoko
の後に適当に何か英文章書きます、何が出力されるかはEnter押してからのお楽しみw zundoko try! Swift is Good
!
a...swiftc --emit-sil
と書いてしまうjava -version
さんパターンだ--version
になるよみたいな話を観た気がしてウキウキして java 9 いれて --version
してそんなオプションネーヨと言われた気持ちdo try
文だとネストが深くなるから、guard try let error {as XxxError}
文欲しくなった今日の今頃guard try? else
と同じような挙動で、guard
と同じ階層で正常系を描く処理ですね、ただ guard try?
は error
を消すけどこちらは消さないguard let player = try AVAudioPlayer(name: name) catch let error as NSError { print(error) // エラーハンドリング return } catch let error { return } player.play()
みたいな (edited)do { try ... } catch { print(error) // エラーハンドリング return }
do
の中で書くとネストが深くなるのがちょっと微妙に嫌ですねguard let Type = Type?
も guard let Type = try Type
も同じようなものだと思うんですよね、どちらも「確実な Type
が欲しい」というわけで-plistArg '{"foo" = bar; "array" = ("foo", {"bar" = "baz"; } ); }'
と -xmlArg "<dict><key>foo</key><string>bar </string><key>baz</key><string>qux</string></dict>"
をフォーマットを事前に指定することもなく、両方使えるようにするとか普通に考えておかしいなあと。protocol HasCodingKeys: Codable {} extension HasCodingKeys { func encode(to encoder: Encoder) throws { fatalError() } init(from decoder: Decoder) throws { fatalError() } } struct A: HasCodingKeys { private typealias Keys = CodingKeys // Use of undeclared type 'CodingKeys' }
Codable
の init(from decoder: Decoder)
とfunc encode(to encoder: Encoder)
をprotocol extensionに実装すると、A
の中でCodingKeys
がundeclaredになるんですが、どういう仕組みになってるんですかね。 (edited)struct A: HasCodingKeys { typealias Keys = CodingKey }
struct A: Codable { struct B {} let b: B typealias Keys = CodingKeys }
これを通したかったみたいでした。 (edited)@available(*, unavailable)
って出来ない?setter
だけじゃなくgetter
の場合もなんですよね。 以前subscript
のsetter
だけ定義したくて試してだめだったのでvar _x: Int = 0 var x: Int { @available(*, unavailable) get { return _x } @available(*, unavailable) set { _x = newValue } } print(x) // 0 x = 100 print(_x) // 100
(edited)@available
だけの話では無いですよね。private(get)
も無いから。subscript
やプロパティである必要がない、ってことなのではないかと思います。 (edited)private var privateValue = 0 func setValue(_ value: Int) { privateValue = value }
deprecated
は実装されそう。 (edited)foo.bar.baz = 1
で、foo
の getter の方が絞られていると bar
がそもそも取り出せないので、変な感じになってくるとかはありそうですね。
(edited)setHogehoge(~)
があってgetHogehoge()
がないのはそこまで違和感を覚えないimport XCTest @testable import pow let lhs = 10 let rhs = 10 let count = 1000000 let expect = Int(pow(Double(lhs), Double(rhs))) final class powTests: XCTestCase { func test0() { var x: Int = 0 measure { for _ in 0..<count { x = power0(lhs, rhs) } } XCTAssertEqual(x, expect) } …
expect
の算出に使ってるInt(pow(Double(lhs), Double(rhs)))
の速度も測ろうと考え func test_() { var x: Int = 0 measure { for _ in 0..<count { x = Int(pow(Double(lhs), Double(rhs))) } } XCTAssertEqual(x, expect) }
を追加したら、10000倍くらい速かった。x = expect
に書き換えてただけだった…pow
が参照等価であることをどうやって知ってるんですか?let expect = Int(pow(Double(lhs), Double(rhs)))
ってのがあって、テストtest_()
内でそのexpect
を参照してるのと、Int(pow(Double(lhs), Double(rhs)
を別モジュールの関数にした場合と速度差がありすぎることから、x = expect
にしているという僕の推測です。 (edited)test_()
内のループカウンタをどれだけ増やしても実行時間が変わらないので、ループ自体が無くなってるのかも?@inline(never) public func blackHole<T>(_ x: T) {}
に食わせて、最適化を防いでますね。 measure { for _ in 0..<count { blackHole(Int(pow(Double(lhs), Double(rhs)))) } }
x = expect
になってるんだったら blackHole(expect)
になるだけだから防げないか。 (edited)echo 'import Foundation; let lhs = 10, rhs = 9, count = 10000000, expect = Int(pow(Double(lhs), Double(rhs))); func test() { var x: Int = 0; for _ in 0..<count { x = Int(pow(Double(lhs), Double(rhs))) }; print(x == expect) }; test()'|swiftc -emit-assembly - -O|xcrun swift-demangle
(edited)pow
の呼び出し自体がなくなってるぽい。-Onone
にするとcallq _pow
が2箇所現れる。x = expect
にしてるわけでは無く、コンパイル時に定数になってるぽい。 movq $10, _main.lhs : Swift.Int(%rip) movq $9, _main.rhs : Swift.Int(%rip) movq $10000000, _main.count : Swift.Int(%rip) movq $1000000000, _main.expect : Swift.Int(%rip) callq _main.test() -> ()
(edited)pow
の呼び出しが残ってる。@llvm.pow.f64
に置き変えですか? (edited)-emit-ir
でpow
は無くなって定数1000000000
になってますね。 define i32 @main(i32, i8** nocapture readnone) local_unnamed_addr #0 { entry: store i64 10, i64* getelementptr inbounds (%TSi, %TSi* @main.lhs : Swift.Int, i64 0, i32 0), align 8 store i64 9, i64* getelementptr inbounds (%TSi, %TSi* @main.rhs : Swift.Int, i64 0, i32 0), align 8 store i64 10000000, i64* getelementptr inbounds (%TSi, %TSi* @main.count : Swift.Int, i64 0, i32 0), align 8 store i64 1000000000, i64* getelementptr inbounds (%TSi, %TSi* @main.expect : Swift.Int, i64 0, i32 0), align 8 tail call swiftcc void @main.test() -> ()() ret i32 0 }
emit-ir
はLLVM最適化後でした。 https://twitter.com/rintaro/status/963754184494350336-disable-llvm-optzns
をフロントエンドに渡してあげると見えるかもしれない。$ echo 'import Foundation; let lhs = 10, rhs = 9, count = 10000000, expect = Int(pow(Double(lhs), Double(rhs))); func test() { var x: Int = 0; for _ in 0..<count { x = Int(pow(Double(lhs), Double(rhs))) }; print(x == expect) }; test()'|swiftc -frontend -emit-ir -primary-file - -target x86_64-apple-darwin17.4.0 -enable-objc-interop -sdk /Applications/Xcode-beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk -O -color-diagnostics -disable-llvm-optzns -module-name main -o - |xcrun swift-demangle
$ echo 'import Foundation; let lhs = 10, rhs = 9, count = 10000000, expect = Int(pow(Double(lhs), Double(rhs))); func test() { var x: Int = 0; for _ in 0..<count { x = Int(pow(Double(lhs), Double(rhs))) }; print(x == expect) }; test()' | swiftc -O -emit-ir -Xfrontend -disable-llvm-optzns -
define i32 @main(i32, i8**) #0 { entry: %2 = bitcast i8** %1 to i8* store i64 10, i64* getelementptr inbounds (%TSi, %TSi* @main.lhs : Swift.Int, i32 0, i32 0), align 8 store i64 9, i64* getelementptr inbounds (%TSi, %TSi* @main.rhs : Swift.Int, i32 0, i32 0), align 8 store i64 10000000, i64* getelementptr inbounds (%TSi, %TSi* @main.count : Swift.Int, i32 0, i32 0), align 8 %3 = call double @pow(double 1.000000e+01, double 9.000000e+00)
pow
残ってる。define i32 @main(i32, i8**) #0 { entry: %2 = bitcast i8** %1 to i8* store i64 10, i64* getelementptr inbounds (%TSi, %TSi* @_T04main3lhsSivp, i32 0, i32 0), align 8 store i64 9, i64* getelementptr inbounds (%TSi, %TSi* @_T04main3rhsSivp, i32 0, i32 0), align 8 store i64 10000000, i64* getelementptr inbounds (%TSi, %TSi* @_T04main5countSivp, i32 0, i32 0), align 8 %3 = call double @pow(double 1.000000e+01, double 9.000000e+00) %4 = bitcast double %3 to i64 ... declare double @pow(double, double) #1
この時点ではまだ 普通のpowですね。pow
は単純なforループ版より3~9倍遅かった。x = expect
にしているという僕の推測です。 pow
が参照等価であることをコンパイラが知らないと x = expect
とすることができないんじゃないかと思ったんですが、そもそもコンパイル時に展開されているということは pow
が特別扱いされてそうですね。
/// canConstantFoldCallTo - Return true if its even possible to fold a call to /// the specified function. bool canConstantFoldCallTo(ImmutableCallSite CS, const Function *F);
canConstantFoldCallTo
の実装。 https://github.com/apple/swift-llvm/blob/stable/lib/Analysis/ConstantFolding.cpp#L1441switch
のパターンマッチに ?
使えるの知らなかった if case let
だけかと思ってた。 let a: Int? = 42 switch a { case let x?: print(x + 1) // 43 default: print("nil") }
.some(let x)
って書いてた。.some(let x)
にしてた。x?.
の時は ?.
だけど x?:
の時は x?
:
なのが紛らわしいな。:
は演算子には使えない文字なんだっけ。switch (open, close) { case (let open?, let close?): return "\(open)〜\(close)" case (let open?, nil): return "\(open)〜" case (nil, let close?): return "〜\(close)" case (nil, nil): return "" }
最近こんなん書いたけど、?
ついてるからややこしいなーと (edited).some
の方が可読性高い??
ついてると一瞬脳が Optional
と認識してしまいそうかも?if case let a? = aOrNil
はうまい表現だと思うんだよなぁ。宣言しているのはあくまで a
で ?
が剥がされてる感が。if let a? = aOrNil
にしてほしい。else if
でかかなきゃならない?if case
の1行表記が欲しいenum Animal { case cat(Cat) case dog ... }
↑で animal: Animal から Cat? を取り出したい (edited)run { if case .cat(let x) = animal { return x } else { return nil } }
(edited)Cat?
を取り出しても、大抵のケースでは結局その後で分岐することになるのでは?button.isEnabled = ...
みたいなときに Bool
がほしいのはある気がする。Observable<Animal>
から Observable<Cat>` に変換する時とかにほしいんですよArray<Animal>
から Array<Cat>
に compactMap するとかでもいいですね。switch
か if case
して return
するしかなさそうだなぁ。 (edited)'public' modifier cannot be used with extensions that declare protocol conformances
と言われるんですが、なぜそうなってるんでしょう?(でも外からはちゃんと認識されてるっぽい)extension Polynomial: EuclideanRing where R: Field {
protocol Collection: Sequence
みたいに書くのとはまた違う感じでしょうか?func bar(foo: int) { func inner(arg: int = foo) {} print(inner()) } bar(foo: 3)
Swift version 4.1 (swift-4.1-RELEASE) Target: x86_64-unknown-linux-gnu
/usercode/main.swift:1:15: error: use of undeclared type 'int' func bar(foo: int) { ^~~ /usercode/main.swift:2:21: error: use of undeclared type 'int' func inner(arg: int = foo) {} ^~~
func bar(foo: Int) { func inner(arg: Int = foo) {} print(inner()) } bar(foo: 3)
Swift version 4.1 (swift-4.1-RELEASE) Target: x86_64-unknown-linux-gnu
swift: /home/buildnode/jenkins/workspace/oss-swift-4.1-package-linux-ubuntu-16_04/swift/lib/SILGen/SILGenGlobalVariable.cpp:64: bool isGlobalLazilyInitialized(swift::VarDecl *): Assertion `!var->getDeclContext()->isLocalContext() && "not a global variable!"' failed. /usr/bin/swift[0x3f24d54] /usr/bin/swift[0x3f25096] /lib/x86_64-linux-gnu/libpthread.so.0(+0x11390)[0x7f15d2b98390] /lib/x86_64-linux-gnu/libc.so.6(gsignal+0x38)[0x7f15d12d7428] /lib/x86_64-linux-gnu/libc.so.6(abort+0x16a)[0x7f15d12d902a] /lib/x86_64-linux-gnu/libc.so.6(+0x2dbd7)[0x7f15d12cfbd7] /lib/x86_64-linux-gnu/libc.so.6(+0x2dc82)[0x7f15d12cfc82] /usr/bin/swift[0xc929db] /usr/bin/swift[0xc6a1e3] /usr/bin/swift[0xc6af00] /usr/bin/swift[0xc7448c] /usr/bin/swift[0xc69ee4] /usr/bin/swift[0xcc47f6] /usr/bin/swift[0xc91f8d] /usr/bin/swift[0xc2e86b] /usr/bin/swift[0xc2c51b] /usr/bin/swift[0xc2b847] /usr/bin/swift[0xcc1225] /usr/bin/swift[0xcc106e] /usr/bin/swift[0xc8fec5] /usr/bin/swift[0xc33515] /usr/bin/swift[0xc2ba85] /usr/bin/swift[0xc30f7b] /usr/bin/swift[0xc31c46] /usr/bin/swift[0xc3221d] /usr/bin/swift[0x4c27c4] /usr/bin/swift[0x4beecc] /usr/bin/swift[0x4778c4] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f15d12c2830] /usr/bin/swift[0x475179] Stack dump: 0. Program arguments: /usr/bin/swift -frontend -interpret /usercode/main.swift -disable-objc-interop -module-name main 1. While emitting SIL for 'bar(foo:)' at /usercode/main.swift:1:1 2. While silgen emitFunction SIL function "@_T04main3barySi3foo_tF". for 'bar(foo:)' at /usercode/main.swift:1:1 3. While silgen emitDefaultArgGenerator SIL function "@_T04main3barySi3foo_tF5innerL_ySi3arg_tFfA_". for expression at [/usercode/main.swift:2:27 - line:2:27] RangeText="f" Aborted (core dumped)
Assertion !var->getDeclContext()->isLocalContext() && "not a global variable!"' failed.
(edited)struct Stone {} extension Stone { func aaa<T>(_ t: T) {} }
protocol A {} protocol B {} protocol C {} extension A: B where Self: C {} extension B: C where Self: A {} extension C: A where Self: B {}
2018-03-31-a 4.1 4.0.3 3.1.1 3.0.2
func bar(foo: Int) { func inner(arg: Int = foo) {} print(inner()) } bar(foo: 3)
Swift version 4.1 (swift-4.1-RELEASE) Target: x86_64-unknown-linux-gnu
swift: /home/buildnode/jenkins/workspace/oss-swift-4.1-package-linux-ubuntu-16_04/swift/lib/SILGen/SILGenGlobalVariable.cpp:64: bool isGlobalLazilyInitialized(swift::VarDecl *): Assertion `!var->getDeclContext()->isLocalContext() && "not a global variable!"' failed. /usr/bin/swift[0x3f24d54] /usr/bin/swift[0x3f25096] /lib/x86_64-linux-gnu/libpthread.so.0(+0x11390)[0x7f6befe6f390] /lib/x86_64-linux-gnu/libc.so.6(gsignal+0x38)[0x7f6bee5ae428] /lib/x86_64-linux-gnu/libc.so.6(abort+0x16a)[0x7f6bee5b002a] /lib/x86_64-linux-gnu/libc.so.6(+0x2dbd7)[0x7f6bee5a6bd7] /lib/x86_64-linux-gnu/libc.so.6(+0x2dc82)[0x7f6bee5a6c82] /usr/bin/swift[0xc929db] /usr/bin/swift[0xc6a1e3] /usr/bin/swift[0xc6af00] /usr/bin/swift[0xc7448c] /usr/bin/swift[0xc69ee4] /usr/bin/swift[0xcc47f6] /usr/bin/swift[0xc91f8d] /usr/bin/swift[0xc2e86b] /usr/bin/swift[0xc2c51b] /usr/bin/swift[0xc2b847] /usr/bin/swift[0xcc1225] /usr/bin/swift[0xcc106e] /usr/bin/swift[0xc8fec5] /usr/bin/swift[0xc33515] /usr/bin/swift[0xc2ba85] /usr/bin/swift[0xc30f7b] /usr/bin/swift[0xc31c46] /usr/bin/swift[0xc3221d] /usr/bin/swift[0x4c27c4] /usr/bin/swift[0x4beecc] /usr/bin/swift[0x4778c4] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f6bee599830] /usr/bin/swift[0x475179] Stack dump: 0. Program arguments: /usr/bin/swift -frontend -interpret /usercode/main.swift -disable-objc-interop -module-name main 1. While emitting SIL for 'bar(foo:)' at /usercode/main.swift:1:1 2. While silgen emitFunction SIL function "@_T04main3barySi3foo_tF". for 'bar(foo:)' at /usercode/main.swift:1:1 3. While silgen emitDefaultArgGenerator SIL function "@_T04main3barySi3foo_tF5innerL_ySi3arg_tFfA_". for expression at [/usercode/main.swift:2:27 - line:2:27] RangeText="f" Aborted (core dumped)
func bar(foo: Int) { func inner(arg: Int = foo) {} print(inner()) } bar(foo: 3)
Swift version 4.2-dev (LLVM 0d52728a8a, Clang 1d3cad1e6b, Swift 6c42bcccbd) Target: x86_64-unknown-linux-gnu
swift: /home/buildnode/jenkins/workspace/oss-swift-package-linux-ubuntu-16_04/swift/lib/SILGen/SILGenGlobalVariable.cpp:64: bool isGlobalLazilyInitialized(swift::VarDecl *): Assertion `!var->getDeclContext()->isLocalContext() && "not a global variable!"' failed. /usr/bin/swift[0x411c854] /usr/bin/swift[0x411cb96] /lib/x86_64-linux-gnu/libpthread.so.0(+0x11390)[0x7f64a8588390] /lib/x86_64-linux-gnu/libc.so.6(gsignal+0x38)[0x7f64a6cc7428] /lib/x86_64-linux-gnu/libc.so.6(abort+0x16a)[0x7f64a6cc902a] /lib/x86_64-linux-gnu/libc.so.6(+0x2dbd7)[0x7f64a6cbfbd7] /lib/x86_64-linux-gnu/libc.so.6(+0x2dc82)[0x7f64a6cbfc82] /usr/bin/swift[0xcb8bb3] /usr/bin/swift[0xc8d123] /usr/bin/swift[0xc8dde3] /usr/bin/swift[0xc9e360] /usr/bin/swift[0xc8cef4] /usr/bin/swift[0xcecb34] /usr/bin/swift[0xcb8091] /usr/bin/swift[0xc4fb59] /usr/bin/swift[0xc4d64f] /usr/bin/swift[0xc4c878] /usr/bin/swift[0xce96b5] /usr/bin/swift[0xce94fe] /usr/bin/swift[0xcb5f5b] /usr/bin/swift[0xc54c84] /usr/bin/swift[0xc4cb25] /usr/bin/swift[0xc525bb] /usr/bin/swift[0xc53266] /usr/bin/swift[0xc5385d] /usr/bin/swift[0x4d820d] /usr/bin/swift[0x4d4b9c] /usr/bin/swift[0x48a26d] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f64a6cb2830] /usr/bin/swift[0x487ac9] Stack dump: 0. Program arguments: /usr/bin/swift -frontend -interpret /usercode/main.swift -disable-objc-interop -module-name main 1. While emitting SIL for 'bar(foo:)' at /usercode/main.swift:1:1 2. While silgen emitFunction SIL function "@$S4main3bar3fooySi_tF". for 'bar(foo:)' at /usercode/main.swift:1:1 3. While silgen emitDefaultArgGenerator SIL function "@$S4main3bar3fooySi_tF5innerL_3argySi_tFfA_". for expression at [/usercode/main.swift:2:27 - line:2:27] RangeText="f" Aborted (core dumped)
func foo<T>(_ array: [T?]) -> [T] { ... }
はできるのに↓ができないのは、関数よりもメソッドを優先する Swift としては明らかな言語仕様的不足。 extension<T> Array where Wrapped == T? { func foo() -> [T] { ... } }
OptionalProtocol
、昔は where T == Int?
とかでも必要だったけどこれは解消してマシになったんですけど、まだ == T?
が書けないんですよねぇ。compactMap
の Proposal に書かれてる compact
も実装できない・・・。 https://github.com/apple/swift-evolution/blob/master/proposals/0187-introduce-filtermap.mdextension<T> Array where Element == T? { func foo() -> [T] { ... } }
(edited)extension Array where Element: OptionalConvertible { ... } extension Optional : OptionalConvertble { ... }
(edited)public protocol OptionalConvertible { associatedtype _Wrapped func asOptional() -> Optional<_Wrapped> } extension Optional : OptionalConvertible { public func asOptional() -> Optional<Wrapped> { return self } }
public protocol EquivalenceRelation { .. } public struct QuotientSet<X, Rel: EquivalenceRelation>: SetType where X == Rel.Base { .. } public struct ModSubgroupRelation<H: Subgroup>: EquivalenceRelation { .. } public typealias QuotientGroup<G, H: Subgroup> = QuotientSet<G, ModSubgroupRelation<H>> where G == H.Super extension QuotientGroup: Group where X: Group, Rel: ModSubgroupRelation<H> // あっ
protocol A {} struct X<T: A> {} struct B<S>: A{} typealias Y<S> = X<B<S>> extension<S> Y where T == B<S> { .. } // コレ
(edited)protocol A {} struct X<T: A> {} struct B<S>: A{} typealias Y<S> = X<B<S>> protocol BProtocol: A { associatedtype _S var bValue: B<_S> { get } } extension B : BProtocol { var bValue: B<S> { return self } } extension X where T : BProtocol { // これがやりたい }
extension<S> Y where T == B<S>
は extension<S> X where T == B<S>
と同じ意味になると思います。Optional
の話と合わせると BProtocol
を BConvertible
とした方がよかったかもしれません。BProtocl
は B
に変換できるので実質的に B
のように扱えます。public protocol _ModSubgroupRelation: EquivalenceRelation where Base == Sub.Super { associatedtype Sub: Subgroup } public struct ModSubgroupRelation<H: Subgroup>: _ModSubgroupRelation { public typealias Base = H.Super public typealias Sub = H ... } public typealias QuotientGroup<G, H: Subgroup> = QuotientSet<G, ModSubgroupRelation<H>> where G == H.Super extension QuotientGroup: Group where Rel: _ModSubgroupRelation, X == Rel.Base { ... }
できたっぽいです!_ModSubgroupRelation
プロトコルから ModSubgroupRelation
を取り出すメソッドかプロパティをつけないといけないと思います。 (edited)protocol P{} struct A<T> {} extension A: P where T == Int {} extension A: P where T == String {} // error: redundant conformance of 'A<T>' to protocol 'P'
異なる条件でも同じ protocol への conformance はできないんですね… (edited)protocol IntOrString {} extension Int: IntOrString {} extension String: IntOrString {} extension A: P where T: IntOrString {}
みたいに回り道が必要になりますねぇprotocol A {} protocol B: A {} protocol C: A {} protocol D: B, C {} struct X<T>: A{} extension X: D where T == Int { // Type 'X<T>' does not conform to protocol 'B' }
Swift version 4.1 (swift-4.1-RELEASE)
/usercode/main.swift:7:1: error: type 'X<T>' does not conform to protocol 'B' extension X: D where T == Int { // Type 'X<T>' does not conform to protocol 'B' ^ /usercode/main.swift:4:10: note: type 'X<T>' does not conform to inherited protocol 'B' protocol D: B, C {} ^
protocol A {} protocol B: A {} protocol C: A {} protocol D: B, C {} struct X<T>: A{} extension X: B where T == Int {} extension X: C where T == Int {} extension X: D where T == Int {}
Swift version 4.1 (swift-4.1-RELEASE)
protocol A {} protocol B: A {} protocol C: A {} protocol D: B, C {} struct X<T>: A{} extension X: B, C, D where T == Int {}
Swift version 4.1 (swift-4.1-RELEASE)
extension BilinearMap: VectorSpace, BilinearMapType where Domain: ProductSetType & VectorSpace, Domain.Left: VectorSpace, Domain.Right: VectorSpace, Codomain: VectorSpace, Domain.CoeffRing == Codomain.CoeffRing, Domain.CoeffRing == Domain.Left.CoeffRing, Domain.CoeffRing == Domain.Right.CoeffRing {
extension <V1: VectorSpace, V2: VectorSpace, W: VectorSpace> BilinearMap: BilinearMapType where Domain == ProductVectorSpace<V1, V2>, Domain.CoeffRing == Codomain.CoeffRing { }
これで済むと思います。extension<T> Array where Element == Optional<T> { func compact() -> Array<T> { ... } }
の代わりに func compact<T>(_ array: Array<Optional<T>>) -> Array<T> { ... }
になりますが、関数だと記述順が辛いところをfunc |> (a, b) { return b(a) }
public typealias BilinearForm<V: VectorSpace> = BilinearMap<V, V, AsVectorSpace<V.CoeffRing>> extension BilinearForm: BilinearFormType where Domain: ProductSetType & VectorSpace, Domain.Left: VectorSpace, Domain.Left == Domain.Right, Domain.CoeffRing == Domain.Left.CoeffRing, Codomain == AsVectorSpace<Domain.CoeffRing> { }
typealias
に対して extension
を書かない方がいいかもしれませんね。class C<T> {} typealias IntC = C<Int> extension IntC {}
Swift version 4.1 (swift-4.1-RELEASE)
/usercode/main.swift:3:1: error: constrained extension must be declared on the unspecialized generic type 'C' with constraints specified by a 'where' clause extension IntC {} ^ ~~~~
#if swift(>=4.1.0) let version = "4.1.0" #elsif swift(>=4.0.3) // it should be `elseif` let version = "4.0.3" #endif
Swift version 4.1 (swift-4.1-RELEASE)
/usercode/main.swift:3:9: error: expected expression #elsif swift(>=4.0.3) // it should be `elseif` ^ /usercode/main.swift:4:17: error: invalid redeclaration of 'version' let version = "4.0.3" ^ /usercode/main.swift:2:17: note: 'version' previously declared here let version = "4.1.0" ^
#if swift(>=4.1.0) let version = "4.1.0" #elsif swift(>=4.0.3) // it should be `elseif` let version = "4.0.3" #endif
Swift version 4.1 (swift-4.1-RELEASE)
error: failed to launch REPL process: process launch failed: 'A' packet returned an error: 8
#if swift(>=4.1.0) let version = "4.1.0" #elsif swift(>=4.0.3) // it should be `elseif` let version = "4.0.3" #endif
Swift version 4.1 (swift-4.1-RELEASE)
-swift-version 3
が付いた時に#elsif
ってのがそのまま通ってしまうぽい?#if
から #endif
の間が swift(>=4.1.0)
じゃないので、パースの対象外になるので、_ = version
書いとけば判定はできそうですね。 一般的には使えなそうですが。-swift-version 3
でも 4.2
対応のコンパイラなら swift(>=4.1.0)
は false
だけども内容はパースする。canImport()
とかの新しい条件が含まれてた時にエラーになったりしないですかね。つまり -swift-version 3 でも 4.2 対応のコンパイラなら swift(>=4.1.0) は false だけども内容はパースする。
コードが想定する対応バージョンのコンパイラでちゃんとテストしろ、で済んでしまう問題ではあるのですよね…extension Optional { public func unwrap(_ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) -> Wrapped { guard let value = self else { let m = message() fatalError("Optional unwrap failed" + (!m.isEmpty ? ": " + m : ""), file: file, line: line) } return value }
guard let tableView = tableViewController.tableView else { fatalError("UITableViewControllerじゃなくなった?") }
let tableView = tableViewController.tableView.unwrap("UITableViewControllerじゃなくなった?")
↑こうかいたほうがよくない?!
とか、死ぬケースっていうのは、把握しておく必要はないはずなんだよね!
相当のクラッシュとかは、メソッド冒頭に集めてあるイメージではあるfunc preconditionNotNone<T>(_ t: T?) -> T
let x = a.x * b.x - a.y * b.y - a.z * b.z - a.w * b.w
が Expression was too complex... と言われて辛い なぜかこうすると通るようにはなる… let x = a.x * b.x - (a.y * b.y + a.z * b.z + a.w * b.w)
true && true && true
とかやるだけで出てた気がするのでだいぶ良くはなったんだと思いますがx
, y
, z
, w
の型が定まってるなら組み合わせなさそうですけどねーExpressibleByXxxLiteral
で組み合わせ爆発するけど(ここが Swift 特有の問題だと思ってます)、この場合はどうしてだろう・・・。 (edited)Double
? public static func -(a: 𝐑, b: 𝐑) -> 𝐑 { return 𝐑(a.value - b.value, a.error + b.error) }
(a.x * b.x )- (a.y * b.y) - (a.z * b.z) - (a.w * b.w)
の -
を探し続けてたってこと? (edited)swift -frontend -typecheck -debug-constraints ファイル名.swift
で見れます )public extension AdditiveGroup { public static func -(a: Self, b: Self) -> Self { return (a + (-b)) } }
https://github.com/taketo1024/SwiftyMath/blob/master/Sources/SwiftyMath/Abstract/AdditiveGroup.swift#L12let x = a.x * b.x + -a.y * b.y - a.z * b.z - a.w * b.w
swift -frontend -typecheck -debug-constraints
って簡単なコードでもすごい大量の出力がありますね。protocol FooProtocol { static func +(lhs: Self, rhs: Self) -> Self static func -(lhs: Self, rhs: Self) -> Self static prefix func-(value: Self) -> Self } extension FooProtocol { static func -(lhs: Self, rhs: Self) -> Self { return lhs + -rhs } } struct Foo : FooProtocol { static func +(lhs: Foo, rhs: Foo) -> Foo { return lhs } static prefix func-(value: Foo) -> Foo { return value } } let a = Foo() let b = a + a - a + a - a + a - a + a
protocol FooProtocol { static func +(lhs: Self, rhs: Self) -> Self static func -(lhs: Self, rhs: Self) -> Self static prefix func-(value: Self) -> Self } extension FooProtocol { static func -(lhs: Self, rhs: Self) -> Self { return lhs + -rhs } } struct Foo : FooProtocol { static func +(lhs: Foo, rhs: Foo) -> Foo { return lhs } static prefix func-(value: Foo) -> Foo { return value } } let a = Foo() let b = a + a - a + a - a + a - a + a
protocol FooProtocol { static func +(lhs: Self, rhs: Self) -> Self static func -(lhs: Self, rhs: Self) -> Self static prefix func-(value: Self) -> Self } extension FooProtocol { static func -(lhs: Self, rhs: Self) -> Self { return lhs + -rhs } } struct Foo : FooProtocol { static func +(lhs: Foo, rhs: Foo) -> Foo { return lhs } static prefix func-(value: Foo) -> Foo { return value } } extension Foo { static func -(lhs: Foo, rhs: Foo) -> Foo { return lhs + -rhs } } let a = Foo() let b = a + a - a + a - a + a - a + a
-
はデフォルト実装だからじゃないですか?prefix
の可能性もあるのか。prefix
と解釈したらパースに失敗しそうな?+
か -
かどっちかは明示的な実装が必要でないですか?let x = a.x * b.x - a.y * b.y - a.z * b.z// - a.w * b.w
protocol FooProtocol { static func +(lhs: Self, rhs: Self) -> Self static func -(lhs: Self, rhs: Self) -> Self } extension FooProtocol { static func -(lhs: Self, rhs: Self) -> Self { return lhs + rhs } } struct Foo : FooProtocol { static func +(lhs: Foo, rhs: Foo) -> Foo { return lhs } } let a = Foo() let b = a + a - a + a - a + a - a + a
@available
を使える様にしてもらった。 https://bugs.swift.org/browse/SR-7201.app
形式にうまくパッケージされない気が@testable import MainApp
したらMainApp側の型がコード補完上見れるようになったところまではやったEXCLUDED_SOURCE_FILE_NAMES=AppDelegate.swift
と書きつつ、 TestAppDelegate.swift
というのだけ追加すればいいのではないかしら。 (edited)let viewController = ... let window = UIWindow() window.backgroundColor = .white window.rootViewController = viewController window.makeKeyAndVisible() RunLoop.main.run(until: Date(timeIntervalSinceNow: 0)) viewController.view.layer.render()
^ みたいなことをした方が簡単。Process
で起動した子プロセスの出力をキャプチャする際にはDispatchGroup
で待つと良いという知見を得た。 https://github.com/norio-nomura/SwiftCompilerDiscordappBot/blob/master/Sources/SwiftCompilerDiscordappBot/execute().swift#L27-L31dequeueReusableCell(withReuseIdentifier:for:)
でインスタンス化を行うため、そもそもコンストラクタのカスタマイズはできないものなのでしょうか?let cell = collectionView.dequeueReusableCell(with: FilterCell.self, for: indexPath) cell.configure(image: image, name: name)
内包する案もよさそうですね、ありがとうございます*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'the cell returned from -collectionView:cellForItemAtIndexPath: does not have a reuseIdentifier - cells must be retrieved by calling -dequeueReusableCellWithReuseIdentifier:forIndexPath:'
message2
でだけas [String : Any]
が必要だと言われるのだろう? @swift-4.1.3
let content = "" let fields = [["name": "stdout.txt", "value": ""]] let message1 = fields.isEmpty ? ["content": content] : ["content": content, "embed": ["fields": fields]] let message2 = ["content": content, "embed": ["fields": fields]]
main.swift:4:16: error: heterogeneous collection literal could only be inferred to '[String : Any]'; add explicit type annotation if this is intentional let message2 = ["content": content, "embed": ["fields": fields]] ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ as [String : Any]
message1
も同じ型になるのに。dynamicMemberLookup
把握。subscript(dynamicMember:)
の実装を必要とするアトリビュートなんだね。 @swift-4.2.4
@dynamicMemberLookup indirect enum UID: CustomStringConvertible { case root(String) case leaf(parent: UID, String) subscript(dynamicMember member: String) -> UID { return .leaf(parent: self, member) } var description: String { switch self { case .root(let string): return string case .leaf(let parant, let string): return "\(parant).\(string)" } } } let root = UID.root("root") print(root.a.b.c)
extension Matrix: Codable where R: Codable { //Implementation of 'Decodable' cannot be automatically synthesized in an extension
struct
を作れば解決する気がします。Array
も Element
が Codable
なときだけ Codable
になりました
extension Array : Codable where Element : Codable { ... }
let elements = try container.decode([A : R].self, forKey: .elements)
(edited)CGAffineTransform
の逆行列は transform.inverted()
なのに、 ARKit 等で使う simd の matrix_float4x4
の逆行列は matrix.inverse
になってる・・・ (edited)CGAffineTransform
はかけ算も concatenating
だし、基本的に行列として扱わないネーミングなのかな? (edited)Vector2
を Codable
にして JSON に変換すると {"x":2,"y":3}
のように出力させる実装をする 2. Library A の中で Vector2
を持つ struct Foo : Codable
を作る 3. Library A を使う App B を作る 4. App B のあるファイルで Library A を import
せず に Vector2
を Codable
にして JSON に変換すると [2, 3]
のように出力させる実装をする 5. App B の別のファイルで Library A を import
して Vector2
を JSON に変換すると [2, 3]
、 Foo
を JSON に変換するとその中の Vector2
は {"x":2,"y":3}
というのができた。 (edited)Vector2
に二通りの Codable
の実装をして、それぞれ呼び分けることができた。なんとなくできない気がしてたけど、問題なかった。 (edited)import
で Codable
の実装を切り替えたりできそうですね。Codable
に限りませんが)import LibraryA
をせずに Vector2
を持つ struct
を Codable
にしようとしたらエラーになったから、これはと思って試したんだけどimport LibraryA
せずに Vector2
を持つ struct
が Codable
にできるようになってしまった。逆に Codable
を付けようとすると redundant でエラーになる・・・。 (edited)[omochi@omochi-iMacPro k (master=)]$ cat Sources/App/main.swift import Nature import Japan import US var animals: [AnimalProtocol] = [] animals.append(createJapanCat()) animals.append(createUSCat()) animals.forEach { animal in print(animal.speak()) } [omochi@omochi-iMacPro k (master=)]$ swift run にゃあ meow
&+
ならオーバーフローしても落ちないですfunc addingReportingOverflow(_ other: Int) -> (partialValue: Int, overflow: Bool)
addWithOverflow
の名前が変わったんですね infix operator %+ struct E : Error {} func %+(a: UInt32, b: UInt32) throws -> UInt32 { let c = a.addingReportingOverflow(b) if c.overflow { throw E() } return c.partialValue } try UInt32(0x80_00_00_00) %+ UInt32(0x80_00_00_00)
Swift version 4.1 (swift-4.1-RELEASE)
/usercode/main.swift:11:27: warning: result of operator '%+' is unused try UInt32(0x80_00_00_00) %+ UInt32(0x80_00_00_00) ~~~~~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~ Fatal error: Error raised at top level: main.E(): file /home/buildnode/jenkins/workspace/oss-swift-4.1-package-linux-ubuntu-16_04/swift/stdlib/public/core/ErrorType.swift, line 191 Current stack trace: 0 libswiftCore.so 0x00007f8e1fc285c0 _swift_stdlib_reportFatalErrorInFile + 221 1 libswiftCore.so 0x00007f8e1f9973dc <unavailable> + 1369052 2 libswiftCore.so 0x00007f8e1fbd1222 <unavailable> + 3703330 3 libswiftCore.so 0x00007f8e1fbd2689 <unavailable> + 3708553 4 libswiftCore.so 0x00007f8e1f996ad6 <unavailable> + 1366742 5 libswiftCore.so 0x00007f8e1fbd0feb <unavailable> + 3702763 6 libswiftCore.so 0x00007f8e1f996ad6 <unavailable> + 1366742 7 libswiftCore.so 0x00007f8e1fb03f79 <unavailable> + 2862969 8 libswiftCore.so 0x00007f8e1f9d4960 swift_errorInMain + 318 10 swift 0x0000000000fed1ce <unavailable> + 12505550 11 swift 0x0000000000ff1692 <unavailable> + 12523154 12 swift 0x00000000004d9076 <unavailable> + 888950 13 swift 0x00000000004c35d3 <unavailable> + 800211 14 swift 0x00000000004beecc <unavailable> + 782028 15 swift 0x00000000004778c4 <unavailable> + 489668 16 libc.so.6 0x00007f8e22141740 __libc_start_main + 240 17 swift 0x0000000000475179 <unavailable> + 479609 /usr/bin/swift[0x3f24d54] /usr/bin/swift[0x3f25096] /lib/x86_64-linux-gnu/libpthread.so.0(+0x11390)[0x7f8e23a17390] ...
array[i]
などと同じく API 設計上の意図的なものだと思うので。 (edited)let o1 = tanh(x ⊗ w1 + b1)
内積演算子(テンソル積演算子?)、どうやって入力するんだろう.. (edited)import TensorFlow let x = Tensor<Float>(shape: [1, 2], repeating: 0.1) let y = Tensor<Float>(shape: [3, 4], repeating: 0.1) let matmul = x ⊗ y print(matmul)
test.swift:5:16: error: internal error generating TensorFlow graph: Dimensions must be equal, but are 2 and 3 for 'op.test.swift.5.16' (op: 'MatMul') with input shapes: [1,2], [3,4]. let matmul = x ⊗ y
(edited)import TensorFlow let x = Tensor<Float>(shape: [1, 2], repeating: 0.1) let y = Tensor<Float>(shape: [3, 4], repeating: 0.1) let matmul = x ⊗ y print(matmul)
main.swift:4:21: error: internal error generating TensorFlow graph: GraphGen cannot lower a 'receive' from the host yet let y = Tensor<Float>(shape: [3, 4], repeating: 0.1) ^
~/Library/Developer/Xcode/UserData/
に入れればすぐ出ます。 (edited)function (lhs ... ) { ... }
JSONEncoder.KeyEncodingStrategy.convertToSnakeCase
とJSONDecoder.KeyDecodingStrategy.convertFromSnakeCase
が非対称となる問題のスレッドがSwift Forumではじまりました。 https://forums.swift.org/t/handling-edge-cases-in-jsonencoder-jsondecoder-key-conversion-strategies-sr-6629/12384
import Foundation struct S: Codable { var myURLProperty: String } let encoder = JSONEncoder() encoder.keyEncodingStrategy = .convertToSnakeCase let data = try encoder.encode(S(myURLProperty: "property")) let decoder = JSONDecoder() decoder.keyDecodingStrategy = .convertFromSnakeCase let decoded = try decoder.decode(S.self, from: data) // "No value associated with key CodingKeys(stringValue: \"myURLProperty\", intValue: nil) (\"myURLProperty\"), converted to my_url_property."
上記コードはLinuxでは動きません。 (edited)swift
の標準入力へソースコードを渡して実行させる時、-
以降をCommandLine.arguments
として取り出せるのね。 $ echo 'dump(CommandLine.arguments)' | swift -Onone - -verbose ▿ 2 elements - "-" - "-verbose"
▿ 2 elements - "-" - "-verbose"
UserDefaults.argumentDomain
サポートは4.2から。 @swift-4.1.3 @swift-4.2.4 - -param1 yes import Foundation print(CommandLine.arguments) print("param1: \(UserDefaults.standard.bool(forKey: "param1"))")
["-", "-param1", "yes"] param1: true
["-", "-param1", "yes"] param1: false
protocol A{} struct S<X> {} extension S: A where X == Int {} extension S: A where X == String {}
protocol A{} struct S<X> {} extension S: A where X == Int {} extension S: A where X == String {}
swift-4.1.1-RELEASE
/usercode/main.swift:4:14: error: redundant conformance of 'S<X>' to protocol 'A' extension S: A where X == Int {} ^ /usercode/main.swift:5:1: note: 'S<X>' declares conformance to protocol 'A' here extension S: A where X == String {} ^
protocol IntOrString {} extension Int : IntOrString {} extension String : IntOrString {} extension S: A where X: IntOrString {}
enum AorB { case a(A) case b(B) } protocol AorBProtocol { var _value: AorB { get } } extension A: AorBProtocol { var _value: AorB { return .a(self) } extension B: AorBProtocol { var _value: AorB { return .b(self) } extension Array: Foo where Element: AorBProtocol { func fooFunc() { forEach { switch $0._value { case .a(let a): // write a case here case .b(let b): // write b case here } } } }
(edited)protocol A1 {} protocol A2: A1 {} protocol A3: A2 {} struct C<R>: A1 extension C: A2, A3 where R == X extension C: A2 where R == Y
(edited)Complex<R>
にして、複素数体 C = Complex<Real>
と ガウス整数環 Complex<Int>
を共通化しようとしまして、 (edited)protocol XorY {} struct X: XorY {} struct Y: XorY {} protocol A1 {} protocol A2: A1 {} protocol A3: A2 {} struct C<R>: A1 { } extension C: A2 where R: XorY { } extension C: A3 where R == Y { }
protocol XorY {} struct X: XorY {} struct Y: XorY {} protocol A1 {} protocol A2: A1 {} protocol A3: A2 {} struct C<R>: A1 { } extension C: A2 where R: XorY { } extension C: A3 where R == Y { }
swift-4.1.1-RELEASE
protocol XorY {} struct X: XorY {} struct Y: XorY {} protocol A1 { func a1() -> String } protocol A2: A1 { func a2() -> String } protocol A3: A2 { func a3() -> String } struct C<R>: A1 { func a1() -> String { return "a1\(R.self)" } } extension C: A2 where R: XorY { func a2() -> String { return "a2\(R.self)" } } extension C: A3 where R == Y { func a3() -> String { return "a3\(R.self)" } } print(C<X>().a1()) print(C<X>().a2()) // print(C<X>().a3()) // compile error print(C<Y>().a1()) print(C<Y>().a2()) print(C<Y>().a3())
シンプルな例ならイケそうな雰囲気はありますが…もしかしたら別のところでダメなのかも (edited)protocol XorY {} struct X: XorY {} struct Y: XorY {} protocol A1 { func a1() -> String } protocol A2: A1 { func a2() -> String } protocol A3: A2 { func a3() -> String } struct C<R>: A1 { func a1() -> String { return "a1\(R.self)" } } extension C: A2 where R: XorY { func a2() -> String { return "a2\(R.self)" } } extension C: A3 where R == Y { func a3() -> String { return "a3\(R.self)" } } print(C<X>().a1()) print(C<X>().a2()) // print(C<X>().a3()) // compile error print(C<Y>().a1()) print(C<Y>().a2()) print(C<Y>().a3())
swift-4.1.1-RELEASE
a1X a2X a1Y a2Y a3Y
public typealias 𝐑 = RealNumber
enum AorB { case a(A) case b(B) } protocol AorBProtocol { var _value: AorB { get } }
すいません、こちらはちょっと理解が不十分でした、public protocol ComplexType: Ring { associatedtype Base: Ring init(_ x: Base) init(_ x: Base, _ y: Base) static var imaginaryUnit: Self { get } var realPart: Base { get } var imaginaryPart: Base { get } var inverse: Self? { get } var conjugate: Self { get } }
ってして、 protocol extension つける方向で行こうかと思いますextension Array: Equatable where Element==Int {}
(edited)extension Array: Equatable where Element==Int {}
swift-4.1.1-RELEASE
/usercode/main.swift:1:18: warning: conformance of 'Array<Element>' to protocol 'Equatable' was already stated in the type's module 'Swift' extension Array: Equatable where Element==Int {} ^ Swift.Array<Element>:1:11: note: 'Array<Element>' declares conformance to protocol 'Equatable' here extension Array : Equatable where Element : Equatable { ^
extension Array: Equatable where Element==Never { static func == (lhs: Array, rhs: Array) -> Bool { return true } }
(edited)extension Array: Equatable where Element==Never { static func == (lhs: Array, rhs: Array) -> Bool { return true } }
extension Array: Equatable where Element==Never { static func == (lhs: Array, rhs: Array) -> Bool { return true } }
swift-4.1.1-RELEASE
/usercode/main.swift:1:18: warning: conformance of 'Array<Element>' to protocol 'Equatable' was already stated in the type's module 'Swift' extension Array: Equatable where Element==Never { static func == (lhs: Array, rhs: Array) -> Bool { return true } } ^ /usercode/main.swift:1:63: note: operator function '==' will not be used to satisfy the conformance to 'Equatable' extension Array: Equatable where Element==Never { static func == (lhs: Array, rhs: Array) -> Bool { return true } } ^ Swift.Array<Element>:1:11: note: 'Array<Element>' declares conformance to protocol 'Equatable' here extension Array : Equatable where Element : Equatable { ^
#if swift(>=4.2) print("swift-4.2") #elseif swift(>=4.1.50) print("swift-4.1.50") #elseif swift(>=4.1.2) print("swift-4.1.2") #endif
swift-4.1.50
Swift version 4.2-dev (LLVM a38ff55b31, Clang 5272858825, Swift defc3e9073) Target: x86_64-unknown-linux-gnu
(edited)nil
パターンのテスト書かなくて済むメリットがあるのかなという意味です¬AutoLayout
は多分そもそもGitHubでリポジトリ作れないしCartfileとかで指定できなさそうな気が let f = Float.nan let a = [f] let b = [f] print(f == f) // false print(a == a) // true print(a == b) // false
let f = Float.nan let a = [f] let b = [f] print(f == f) // false print(a == a) // true print(a == b) // false
swift-4.1.1-RELEASE
false true false
print(Float.nan == Float.nan)
(edited)let f = Float.nan let a = Optional(f) let b = Optional(f) print(f == f) // false print(a == a) // false print(a == b) // false
let f = Float.nan let a = Optional(f) let b = Optional(f) print(f == f) // false print(a == a) // false print(a == b) // false
swift-4.1.1-RELEASE
false false false
Dictionary
や Set
もおかしくなるんじゃない?Optional
は中身が一つしかないからそれの ==
を使うだろうけど、 Dictionary
や Set
だと Array
と同じショートカットが行われてそう。Array
のバグなのか、 Float
の(というか IEEE の)問題なのか。a == a
であるとして設計されてそうだしEquatable
なのに equality じゃなくて equivalence なのか・・・。英語むずい・・・。Float
の ==
を変えるのも難しいよね・・・。Array
等のショートカットをやめる 3. Float
等の ==
を変える だけど。結局 1 にしかならなさそう。var d: [Float: String] = [:] d[.nan] = "a" d[.nan] = "b" d[.nan] = "c" print(d.count) print(d[.nan]) print(d == d)
var d: [Float: String] = [:] d[.nan] = "a" d[.nan] = "b" d[.nan] = "c" print(d.count) print(d[.nan]) print(d == d)
swift-4.1.1-RELEASE
3 nil true
/usercode/main.swift:6:7: warning: expression implicitly coerced from 'String?' to Any print(d[.nan]) ^~~~~~~ /usercode/main.swift:6:8: note: provide a default value to avoid this warning print(d[.nan]) ~^~~~~~ ?? <#default value#> /usercode/main.swift:6:8: note: force-unwrap the value to avoid this warning print(d[.nan]) ~^~~~~~ ! /usercode/main.swift:6:8: note: explicitly cast to Any with 'as Any' to silence this warning print(d[.nan]) ~^~~~~~ as Any
&==
を IEEE 754 に従った素の計算にして、 ==
だと反射率を満たすようにすればいい気が。&==
入れるなら ==
がIEEEに従う じゃないですか?==
は Equatable
で規定されるものだから、 Equatable
の ==
が反射率を満たす必要があることを明記して&==
は &+
等と同様の余分なオーバーヘッドのない計算をしてくれる演算子でいいのでは?true
でいいんじゃないかなぁ== .nan
を見て、このコードバグってんぞ→バグってなかった!ってなりそうInt
の +
だってそうでしょ?Float
や Double
の ==
より Int
の +
を使う機会の方がずっと多いのでは?+
や *
は使っても ==
はそんなに使わなさそう。Float
や Double
で、 CPU 上で計算してる時点でパフォーマンスにこだわるケースじゃなさそう。Equatable
はあくまで計算結果の値についてなので、成り立つように思います。Equatable
はあくまで値についての性質なので、どのような式で nan
が導かれても推移律は満たされることになるかと。a == a
のケースについて話されてるかはこれから読みます。Array.==
first looks to referential equality of underlying buffer...Array.==
first looks to referential equality of underlying Element.==
. As a consequence, an array of NaN compares equal to another array of NaN if they share the same buffer, but otherwise false. This is an undesirable outcome. 頭から書いてあった
The last time that this topic was brought up, competing demands voiced by different people were not possible to reconcile: 1) Equatable `==` must be a full equivalence relation. 2) Floating-point types must conform to `Equatable` and not to some alternative such as `PartiallyEquatable`. 3) Floating-point `==` must be IEEE-compliant (at least in the concrete context), and therefore *not* a full equivalence relation. 4) IEEE-compliant floating-point equivalence must be spelled `==` and not some alternative such as `&==`. 5) Behavior of `==` must not change between generic and concrete contexts.
protocol A { static func hoge() } struct B: A { static func hoge() { print("B") } } extension Optional: A where Wrapped: A { static func hoge() { print("Optional") } } struct F<T> { static func fuga() { switch T.self { case is A.Type: (T.self as! A.Type).hoge() default: fatalError() } } } F<B>.fuga() // B // warning: Swift runtime does not yet support dynamically querying conditional conformance F<B?>.fuga() // fatalError
(edited)swift-4.2-DEVELOPMENT-SNAPSHOT-2018-04-23-a
HList
を HCons
と HNil
に限定できないのが辛いですね。 enum
でも書けなさそうだし・・・。List
なら↓みたいに書けるんですけどね〜。 enum List<Element> { case `nil` indirect case cons(Element, List<Element>) } let a: List<Int> = .cons(2, .cons(3, .cons(5, .nil)))
(edited)enum
が型パラメータを取れないと無理なんですよね……。canImport
はimport
の様にシンボルを使う事は出来ないのか…。 @swift-main
import Foundation let killSignals: [Int32] = { var signals = [SIGILL, SIGTRAP, SIGABRT, SIGFPE, SIGBUS, SIGSEGV, SIGQUIT] #if canImport(Glibc.SIGSYS) signals.append(Glibc.SIGSYS) #endif return signals }()
(edited)<stdin>:4:5: error: unexpected platform condition argument: expected identifier #if canImport(Glibc.SIGSYS) ^
(edited)public struct Uniform { var base: RandomNumberGenerator init(base: RandomNumberGenerator) { self.base = base } /// Returns a value from uniform [low, high) distribution. public mutating func next(low: Float, high: Float) -> Float { let uint32: UInt32 = base.next() return (high - low) * (Float(bitPattern: uint32 >> 9 | 0x3f80_0000) - 1) + low } } extension RandomNumberGenerator { public var uniform: Uniform { return Uniform(base: self) } }
こういうの作ろうと思ったんですがRNGがstructだと内部状態コピーされるから微妙ですね…… (edited)next(range: Range<Float>)
を RandomNumberGenerator
に生やすとか?extension
で追加してもいい気も (edited)next(range: Range<Float>)
とnext(mu: Float, sigma: Float)
だと分かりづらくないですかね?Random
は struct
だけどそれは起こらないのと、struct
の場合var a = FooRandom() var b = a a.next() == b.next() // true
になるんだから、 Uniform
もそれでいいんじゃないかな?var a = FooRandom() print(a.uniform.next(...) print(a.uniform.next(...)
これで同じのが出るのが嫌か。uniform
を get set
なプロパティにしてBool
の toggle
とかと同じように元の struct
に変更を反映できない?set
で base
を self
に代入すればいいのか。 (edited)swift public struct Uniform { var base: RandomNumberGenerator init(base: RandomNumberGenerator) { self.base = base } /// Returns a value from uniform [low, high) distribution. public mutating func next(low: Float, high: Float) -> Float { print("base before; \(base)") let uint32: UInt32 = base.next() print("base after; \(base)") return (high - low) * (Float(bitPattern: uint32 >> 9 | 0x3f80_0000) - 1) + low } } extension RandomNumberGenerator { public var uniform: Uniform { get { return Uniform(base: self) } set { print("before set: \(self)") self = uniform.base as! Self print("set self: \(self) \(uniform.base)") } } } struct DummyRNG: RandomNumberGenerator { static var `default` = DummyRNG.init() var state: UInt32 = 0 mutating func next<T>() -> T where T : FixedWidthInteger, T : UnsignedInteger { state += 123456789 return T(state) } } print(DummyRNG.default.uniform.next(low: 0, high: 1)) print(DummyRNG.default.uniform.next(low: 0, high: 1)) print(DummyRNG.default.uniform.next(low: 0, high: 1))
base before; DummyRNG(state: 0) base after; DummyRNG(state: 123456789) before set: DummyRNG(state: 0) set self: DummyRNG(state: 0) DummyRNG(state: 0) 0.02874446 base before; DummyRNG(state: 0) base after; DummyRNG(state: 123456789) before set: DummyRNG(state: 0) set self: DummyRNG(state: 0) DummyRNG(state: 0) 0.02874446 base before; DummyRNG(state: 0) base after; DummyRNG(state: 123456789) before set: DummyRNG(state: 0) set self: DummyRNG(state: 0) DummyRNG(state: 0) 0.02874446
Uniform<Random : RandomNumberGenerator>
にした方が Swifty じゃないですか?base
を fileprivate
にする PR 送ろうかと思ったら、逆に 1.0.0
から 1.0.1
で internal
→ public
な変更がされてるんですが、この意図は何でしょう?1.0.0
→ 1.1.0
の変更だと思います。-alpha
や -beta
, -beta.2
等を付けておくのがオススメです。1.0.0
から始めずに 0.1.0
から始めた方が気軽に破壊的変更しやすいです。)base
を外部から使ってなくないですか? https://github.com/t-ae/xorswift/blob/swift4.2/Sources/Uniform.swiftbase.x
とかが出てきます.base
で検索してたFloat.random(in:)
がありましたね。 normalもこっちの形式に揃えるほうがいいんだろうか……strings.compactMap(Int.init)
で、 flatMap
以前なので 3 週古くて(リネーム前の flatMap
→ Array
を返す flatmap
→ reduce
)reduce
使うにしても今だったら reduce(into:_:)
だし。let a = [[2], [3 ,5]] for var (i, numbers) in a.enumerated() { numbers.append(3) print("\(i): \(numbers)") }
let a = [[2], [3 ,5]] for var (i, numbers) in a.enumerated() { numbers.append(3) print("\(i): \(numbers)") }
swift-4.1.1-RELEASE
0: [2, 3] 1: [3, 5, 3]
/usercode/main.swift:3:10: warning: variable 'i' was never mutated; consider changing to 'let' constant for var (i, numbers) in a.enumerated() { ^
numbers
は var
に、 i
は let
にしたい。let a = [[2], [3 ,5]] for (i, var numbers) in a.enumerated() { numbers.append(3) print("\(i): \(numbers)") }
let a = [[2], [3 ,5]] for (i, var numbers) in a.enumerated() { numbers.append(3) print("\(i): \(numbers)") }
swift-4.1.1-RELEASE
0: [2, 3] 1: [3, 5, 3]
var
と let
に bind したい。 @swiftbot
let a = [[2], [3 ,5]] var iterator = a.enumerated().makeIterator() if var (i, numbers) = iterator.next() { numbers.append(0) print("\(i): \(numbers)") }
let a = [[2], [3 ,5]] var iterator = a.enumerated().makeIterator() if var (i, numbers) = iterator.next() { numbers.append(0) print("\(i): \(numbers)") }
swift-4.1.1-RELEASE
0: [2, 0]
/usercode/main.swift:4:9: warning: variable 'i' was never mutated; consider changing to 'let' constant if var (i, numbers) = iterator.next() { ^
if case (let i, var numbers)? = iterator.next() {
case
にしちゃえばいいのか。ありがとうございます!_random()
をrandom(in: UnboundedRange)
にしたら?って提案しようかと思うんですがこういう細かい&そもそもまだ固まってない内容もフォーラムにスレッド立てていいんですかね? RandomUnificationのスレはちょっと古くて……random(in: UnboundedRange)
は新しい API の提案だし、 reduce(into:_:)
や toggle
、 compactMapValues
を考えると、単独の API の提案は全然ありな気がします。FixedWidthInteger
に限らず検討することになるかもしれないにしても、 pitch は気軽に投げていいんじゃないでしょうか。struct Foo { var bar: Bar { mutating get { ... } } }
↓に書き換えた方がいいでしょうか? struct Foo { mutating func bar() -> Bar { ... } }
get
されてから lazy に読み込んでキャッシュしたいケースです。var foo1 = Foo() var foo2 = foo1 var bar = foo2.bar
というときに、foo1
にキャッシュが共有されないというのが許容出来る場合、僕なら mutating func bar()
にします。class
にするか、グローバルにキャッシュを持つしかない。protocol P { associatedtype T func f(_ g: @escaping (T) -> Void) } class C<S>: P { typealias T = S private let _f: ((S) -> Void) -> Void init<Q: P>(q: Q) where Q.T == T { // Error: cannot assign value of type '((S) -> Void) -> Void' to type '((S) -> Void) -> Void' self._f = { g -> Void in q.f(g) } } func f(_ g: @escaping (S) -> Void) { self._f(g) } }
protocol P { associatedtype T func f(_ g: @escaping (T) -> Void) } class C<S>: P { typealias T = S private let _f: (@escaping (S) -> Void) -> Void init<Q: P>(q: Q) where Q.T == T { // Error: cannot assign value of type '((S) -> Void) -> Void' to type '((S) -> Void) -> Void' self._f = { g -> Void in q.f(g) } } func f(_ g: @escaping (S) -> Void) { self._f(g) } }
cannot assign value of type
のエラーわかりにくい問題、最新のXcodeだと治ってて一発でわかりますよ@escaping
入れなきゃいけない位置を秒で特定できたのはちょい謎@escaping
必要だって、、わいのXcodeは表示したんや…そのはずや…self
の再宣言で LLDB 壊れますね class Example { func ok() { let f = { [weak self] in guard let strongSelf = self else { return } // Set a breakpoint at here print(strongSelf) } f() } func error() { let f = { [weak self] in guard let `self` = self else { return } // Set a breakpoint at here print(self) } f() } } Example().ok() Example().error()
(lldb) br set --file example.swift --line 7 Breakpoint 1: where = example`closure #1 () -> () in example.Example.ok() -> () + 111 at example.swift:7, address = 0x00000001000017df (lldb) br set --file example.swift --line 18 Breakpoint 2: where = example`closure #1 () -> () in example.Example.error() -> () + 111 at example.swift:18, address = 0x00000001000019cf (lldb) r Process 6298 launched: '/Users/yuki.kokubun/Development/self-self-lldb/example' (x86_64) Process 6298 stopped * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 frame #0: 0x00000001000017df example`closure #1 in Example.ok(self=0x0000000100802b30) at example.swift:7 4 guard let strongSelf = self else { return } 5 6 // Set a breakpoint at here -> 7 print(strongSelf) 8 } 9 10 f() Target 0: (example) stopped. (lldb) po self ▿ Optional<Example> - some : <Example: 0x100802b30> (lldb) c Process 6298 resuming example.Example Process 6298 stopped * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 2.1 frame #0: 0x00000001000019cf example`closure #1 in Example.error(self=0x0000000100a01030) at example.swift:18 15 guard let `self` = self else { return } 16 17 // Set a breakpoint at here -> 18 print(self) 19 } 20 21 f() Target 0: (example) stopped. (lldb) po self error: warning: <EXPR>:12:9: warning: initialization of variable '$__lldb_error_result' was never used; consider replacing with assignment to '_' or removing it var $__lldb_error_result = __lldb_tmp_error ~~~~^~~~~~~~~~~~~~~~~~~~ _ error: <EXPR>:18:5: error: value of type 'Example' has no member '$__lldb_wrapped_expr_2' $__lldb_injected_self.$__lldb_wrapped_expr_2( ^~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~
fr var
は下のようになるので単純な名前ベースでの解決をしようとすると死ぬのが原因…? (lldb) fr var (@lvalue example.Example?) self = 0x0000000100a01030 (example.Example) self = 0x0000000100a01030 {}
self?.
で書くか、 クロージャの中で必要な変数をそれぞれguardでアンラップする、って感じに最近はしてますね。guard let `self` = self else { return }
^ のところをselfじゃなくて、selfの先を3〜4つアンラップする感じd。guard let
self = self else { return }
<= これは見た目美しいけどトラブルが多いので良くない、 strongSelf
<= これは人によって色々だしどう書いても美しくない、Error
のインスタンスが手元にあるときに、それでクラッシュさせる ( try!
に失敗したのと同じ状態にする)簡単な方法ってありますっけ? fatalError("\(error)")
でもいいのかもしれませんが、 Error
から String
に情報が落ちてしまってますし。try! throw error
try ! { throw error }()
だと Never
でないので guard
で使えないですし。try! throw error
は throw
が関数じゃないからできなくない?internal func fatalError<E: Error>(with error: E) -> Never { try! { throw error }() fatalError("Never reaches here.") }
という微妙なユーティリティ関数を作ろうとしたけどもっといい方法はないかなと。throw new RuntimeException(exception);
とかでいいんだけど。fatalError
じゃなくて preconditionFailure
がいいかな。 precondition なのか微妙だけど。)String(reflecting: error)
で同等みたいです。_unexpectedError
の返り値の型は Never
ではないのですねCMSampleBufferGetImageBuffer(_:)
みたいな関数群があるけど https://developer.apple.com/documentation/coremedia/1489236-cmsamplebuffergetimagebufferDispatchQueue.global(qos: .default).async { // この中で [NSException raise] が呼ばれていて、 // breakpoint set -S raise で止まった状態を想定してください。 // ここで、この doSomething を呼び出す task を誰が追加したのか // 追跡したい感じです。 doSomething() }
(lldb) th backtrace * thread #3, queue = 'com.apple.root.default-qos', stop reason = breakpoint 1.1 frame #0: 0x000000010e89e001 libobjc.A.dylib`objc_exception_throw frame #1: 0x000000010f2090b9 CoreFoundation`-[NSException raise] + 9 * frame #2: 0x000000010df90ea6 StackChain`doInnerSomething() at ViewController.swift:8 frame #3: 0x000000010df90e19 StackChain`doSomething() at ViewController.swift:4 frame #4: 0x000000010df910c9 StackChain`closure #1 in ViewController.onButton() at ViewController.swift:14 frame #5: 0x000000010df910fd StackChain`thunk for @escaping @callee_guaranteed () -> () at ViewController.swift:0 frame #6: 0x000000011359b7ab libdispatch.dylib`_dispatch_call_block_and_release + 12 frame #7: 0x000000011359c7ec libdispatch.dylib`_dispatch_client_callout + 8 frame #8: 0x00000001135a1619 libdispatch.dylib`_dispatch_queue_override_invoke + 1451 frame #9: 0x00000001135a836c libdispatch.dylib`_dispatch_root_queue_drain + 664 frame #10: 0x00000001135a8076 libdispatch.dylib`_dispatch_worker_thread3 + 132 frame #11: 0x0000000113ac7169 libsystem_pthread.dylib`_pthread_wqthread + 1387 frame #12: 0x0000000113ac6be9 libsystem_pthread.dylib`start_wqthread + 13 (lldb)
thread backtrace -e true
でEnqueued from…の内容も見られますね。(lldb) h th b Show thread call stacks. Defaults to the current thread, thread indexes can be specified as arguments. Use the thread-index "all" to see all threads. Use the thread-index "unique" to see threads grouped by unique call stacks. Syntax: Command Options Usage: thread backtrace [-c <count>] [-s <frame-index>] [-e <boolean>] -c <count> ( --count <count> ) How many frames to display (-1 for all) -e <boolean> ( --extended <boolean> ) Show the extended backtrace, if available -s <frame-index> ( --start <frame-index> ) Frame in which to start the backtrace
/usr/lib/system/introspection
を使った機能みたいです。$ ls /usr/lib/system/introspection libdispatch.dylib* libsystem_pthread.dylib*
* @discussion * These hooks are only available in the introspection version of the library, * loaded by running a process with the environment variable * DYLD_LIBRARY_PATH=/usr/lib/system/introspection
lldb
を直接起動する場合とかは自分で設定する必要があるみたいです。target module list
かけてみて libdispatch.dylib が本物っぽいかどうかだけ確認してみますprocess launch -v DYLD_LIBRARY_PATH=/usr/lib/system/introspection
で/usr/lib/system/introspection/libdispatch.dylib
をロードしただけでは、thread backtrace -e true
は意図した通りに動きませんでした。 /Applications/Xcode.app/Contents/Developer/usr/lib/libBacktraceRecording.dylib
ってのをlldb-rpc-server
は使ってるけど、lldb
で plugin load /Applications/Xcode.app/Contents/Developer/usr/lib/libBacktraceRecording.dylib
してもダメだった。 (edited)process launch -v DYLD_LIBRARY_PATH=/usr/lib/system/introspection -v DYLD_INSERT_LIBRARIES=/Applications/Xcode.app/Contents/Developer/usr/lib/libBacktraceRecording.dylib
でイケた。thread backtrace -e true
in lldb
swift -frontend -repl
なんてのがあったのね。 $ swift -frontend -repl *** You are running Swift's integrated REPL, *** *** intended for compiler and stdlib *** *** development and testing purposes only. *** *** The full REPL is built as part of LLDB. *** *** Type ':help' for assistance. *** (swift) :help Available commands: :quit - quit the interpreter (you can also use :exit or Control+D or exit(0)) :autoindent (on|off) - turn on/off automatic indentation of bracketed lines :constraints debug (on|off) - turn on/off the debug output for the constraint-based type checker :dump_ir - dump the LLVM IR generated by the REPL :dump_ast - dump the AST representation of the REPL input :dump_decl <name> - dump the AST representation of the named declarations :dump_source - dump the user input (ignoring lines with errors) :print_decl <name> - print the AST representation of the named declarations :print_module <name> - print the decls in the given module, but not submodules API documentation etc. will be here eventually. (swift)
$ swift
のときに突入するのがそれだと思ってました (edited)lldb
を使わないので、--privileged
無しのdockerでも使える。--privileged
無しdockerなので、Herokuで動いてるSwiftボットでも、修正すれば使える様になりそう。swift -deprecated-integrated-repl
がそれですね。[omochi@omochi-iMac-PC43 bne-loci (master *+=)]$ swift -deprecated-integrated-repl *** You are running Swift's integrated REPL, *** *** intended for compiler and stdlib *** *** development and testing purposes only. *** *** The full REPL is built as part of LLDB. *** *** Type ':help' for assistance. *** (swift) ^D [omochi@omochi-iMac-PC43 bne-loci (master *+=)]$ swift Welcome to Apple Swift version 4.2 (swiftlang-1000.0.36 clang-1000.0.4). Type :help for assistance. 1> ^D [omochi@omochi-iMac-PC43 bne-loci (master *+=)]$ swift -frontend -repl *** You are running Swift's integrated REPL, *** *** intended for compiler and stdlib *** *** development and testing purposes only. *** *** The full REPL is built as part of LLDB. *** *** Type ':help' for assistance. *** (swift) ^D
-frontend -repl
のほうが -deprecated-integrated-repl
か・・・print_decl
とprint_module
くらいだけど、どれも出力が大きくなるからボットで使えてもありがたみが薄いかな?:print_decl Equatable
protocol Equatable { static func == (lhs: Self, rhs: Self) -> Bool } extension Equatable { @inlinable static func != (lhs: Self, rhs: Self) -> Bool }
-frontend -repl
サポート出来た。swift-DEVELOPMENT-SNAPSHOT-2018-08-26-a
があるけど https://github.com/apple/swift/tags にタグが無いな。git
で見ても無さげ。T: Hoge
みたいに書けるけど、handle
書くの、気持ち悪い気がしたけど defer
的な気持ちで見れば良いのか。do/catch
で囲まなくてよいのでネストが深くならないのが良い?finally
を採用せずに defer
にしたんだったら、この handle
みたいなのの方が理に適ってる気がするけどどうだろう? (edited)handle
とスコープについては、 Go の defer
はスコープ関係なく関数単位だったはずだから、 handle
はどうなんだろう?とさっきから思ってる。String
からNSString
への暗黙変換が起きる条件って何だろう?NSString.character(at:)
は、Linuxでは4.2から起きる。 @swift-4.0.3 @swift-4.1.3 @swift-4.2.4 -frontend -repl import Foundation "test".character(at: 0)
(edited)<REPL Input>:1:1: error: value of type 'String' has no member 'character' "test".character(at: 0) ^~~~~~ ~~~~~~~~~ Swift.String:42:16: note: did you mean 'characters'? public var characters: String.CharacterView { get set } ^
(edited)<REPL Input>:1:1: error: value of type 'String' has no member 'character' "test".character(at: 0) ^~~~~~ ~~~~~~~~~ Swift.String:10:16: note: did you mean 'characters'? public var characters: String.CharacterView { get set } ^ Swift.String:8:16: note: did you mean '_characters'? public var _characters: String._CharacterView { get set } ^
(edited)$ echo 'import Foundation; "test".character(at: 0)'|swift -frontend -repl -sdk `xcrun --sdk macosx --show-sdk-path` <REPL Input>:1:20: error: value of type 'String' has no member 'character' import Foundation; "test".character(at: 0) ^~~~~~ ~~~~~~~~~ Swift.String:10:16: note: did you mean 'characters'? public var characters: String.CharacterView { get set } ^ Swift.String:8:16: note: did you mean '_characters'? public var _characters: String._CharacterView { get set } ^
Swift.String
であり、2) Swift.String
が _ObjectiveCBridgeable
であり、 3) lookupするメンバー名が Swift.String
に生えておらず、 4) ブリッジ先タイプにはそのメンバーが存在し 5) 存在するモジュールが Clang モジュールの Foundation
以外のとき。 っていう条件なので、 corelibs-foundation は 5 の条件をすり抜けて見えちゃっている感じっぽいですね。 (edited)NSString
にインスタンスメンバーを追加すると、String
からも使えてしまうと。 @swift-4.0.3 @swift-4.1.3 @swift-4.2.4 -frontend -repl import Foundation extension NSString { func hoge() -> String { return "hoge" } } "test".hoge()
// r0 : String = "hoge"
<REPL Input>:1:1: error: value of type 'String' has no member 'hoge' "test".hoge() ^~~~~~ ~~~~
<REPL Input>:1:1: error: value of type 'String' has no member 'hoge' "test".hoge() ^~~~~~ ~~~~
.swiftmodule
ファイルとしてキャッシュされないですか?.swiftmodule
は依存の解決には使われていなかったと思うのですが、記憶違いかも。 (edited).swiftmodule
は出力されるものではありますが、他ファイルのコンパイル時に参照されて使われる物ではないですね。A.swift
,B.swift
, C.swift
あったときにクリーンビルドだと swift -frontend -c -primary-file A.swift B.swift C.swift swift -frontend -c A.swift -primary-file B.swift C.swift swift -frontend -c A.swift B.swift -primary-file C.swift
の 3 フロントエンド実行されて、frontend に -primary-file
じゃないファイルの .swiftmodule
があったらそれに読み替えるみたいな機能はないので。${PROJECT_TEMP_ROOT}/XCBuildData/*-manifest.xcbuild
に生成します。 それらをSwiftPMの.build/debug.yaml
とかと比較すると違いを調べやすいかも? (edited)$ cat A.swift @available(*, introduced: 1) public func funcA() { print("funcA") } $ cat B.swift public func funcB() { print("funcB") funcA() } $ cat C.swift public func funcC() { print("funcC") } $ cat output.json { "A.swift": { "object": "Derived/A.o", "swiftmodule": "Derived/A~partial.swiftmodule", "swift-dependencies": "Derived/A.swiftdeps", }, "B.swift": { "object": "Derived/B.o", "swiftmodule": "Derived/B~partial.swiftmodule", "swift-dependencies": "Derived/B.swiftdeps", }, "C.swift": { "object": "Derived/C.o", "swiftmodule": "Derived/C~partial.swiftmodule", "swift-dependencies": "Derived/C.swiftdeps", }, "": { "swift-dependencies": "Derived/buildrecord.swiftdeps" } } $ mkdir -p Derived
な状態から、 $ xcrun swiftc -v -incremental -output-file-map output.json A.swift B.swift C.swift -module-name MyModule -emit-library -emit-module -o Derived/MyModule.dylib
でとりあえずクリーンビルドして、Derived
ディレクトリの中身見たり、A.swift
の@available
消して同コマンド実行して何が起こってるか確認したりすると面白いです。 (edited)swiftc
コマンドに -enable-batch-mode
追加してあげるとXcode10の挙動と同等に。 (edited)[swift 4.2]
みたいなバッジがついてたりしたら、安心です
あと、プロジェクトの中で、あるモジュールは4.1、あるモジュールは4.2でビルドしてからリンクします、 みたいなやつ、動くのかもしれないけど信用ならないから心配。
むむ、これって何かトラブルの事例ってあるのですか?SWIFT_VERSION = 4.2
になっててもswiftc
へは-swift-version 4
って渡すのかな?project.pbxproj
でSWIFT_VERSION = 4.2
になってても過去のXcodeでビルド出来るなら、SWIFT_VERSION = 4.2
にしてしまっても良い様な気がしてきた。project.pbxproj
でSWIFT_VERSION = 4.2
になってても、Xcode 9.0.1, 9.1, 9.2, 9.3.1, 9.4.1はswiftc
へ-swift-version 4
を渡すのを確認した。SWIFT_VERSION = 4.2
にしてもbreaking changeにならないとしても、podspecのswift_version
はどうなんだろう?(indirect.storage -> some -> value)
Found 2 object leaking children[0].viewModel: SomeViewModel children[0].textField: UITextField
Summary: Found 2 leak objects Leaked objects: 0: Description: Node Type: Any Location: .linkedNodes[0] 1: Description: Node Type: Any Location: (root) Circular reference paths: 0: .linkedNodes[0].linkedNodes[0]
Sequence
( Collection
?)を型パラメータにとるのがおもしろいですね。 https://github.com/pointfreeco/swift-nonempty (edited)Collection
っぽいですね。 https://github.com/pointfreeco/swift-nonempty/blob/master/Sources/NonEmpty/NonEmpty.swift#L1Image<Element>: Sequence
を作ってますが Image
to Image
の map
ができてるので。 Sequence
由来のと曖昧になりそうな気がするんですが、 Image
to Image
の方が優先されてますね。Sequence
に map
とかついてるのほんと微妙ですよねぇ。 makeIterator
だけの純粋な Sequence
と map
とかを分離してほしい・・・。Collection
として扱われるので Collection
の map
が呼ばれるんじゃないですか?↓とかですよね? public func map<T>(_ transform: (Element) throws -> T) rethrows -> NonEmpty<[T]> { return try NonEmpty<[T]>(transform(self.head), self.tail.map(transform)) }
[Element]
を [T]
に変換するんで Self
じゃなくて、 higher-kinded type がないとできないんですよねぇ・・・。
NonEmpty<Element, NonEmpty<Element, C>>
NonEmpty<Element, NonEmpty<Element, C>>
は考えてませんでしたが(それぞれの struct
を実装するイメージしてました)、多分うまくいきそうな気がします。その場合だけ init(Element, Element, C)
を extension
で生やせると便利そうですね〜。typealias ArrayLongerThan2<Element> = PrefixedArray<Element, PrefixedArray<Element, PrefixedArrayEnd<Element>>>
となっていて、これで flatMap とかの実装が衝突して死んだみたいなエラーに出くわして、ウワァ、ダメなのかみたいに引き返したんです (edited)protocol NonEmptySequence: Sequence { var first: Element { get } } struct NonEmptyArray<Element>: NonEmptySequence { private var array: [Element] init(_ array: [Element]) { precondition(!array.isEmpty) self.array = array } var first: Element { return array[0] } func makeIterator() -> Array<Element>.Iterator { return array.makeIterator() } }
(edited)protocol NonEmptySequence: Sequence { var first: Element { get } } struct NonEmptyArray<Element>: NonEmptySequence { private var array: [Element] init(_ array: [Element]) { precondition(!array.isEmpty) self.array = array } var first: Element { return array[0] } func makeIterator() -> Array<Element>.Iterator { return array.makeIterator() } }
(edited)protocol NonEmptySequence: Sequence { var first: Element { get } } struct NonEmptyArray<Element>: NonEmptySequence { private var array: [Element] init(_ array: [Element]) { precondition(!array.isEmpty) self.array = array } var first: Element { return array[0] } func makeIterator() -> Array<Element>.Iterator { return array.makeIterator() } }
first
は Sequence
じゃなくて Collection
なのか。extension
でも生えてないんですね。 map
とかは生えてるのに・・・。protocol I { init() } protocol P { associatedtype A: I } extension P { var bar: A? { return nil } } protocol Q: P {} extension Q { var bar: A { return A() } } struct S<T: I>: Q { typealias A = T let value: T var bar: T { return value } } extension Int: I { init() { self = 0 } } let s = S(value: 42) print(s.bar)
(edited)safeFirst
って何ができなかったんですか? Optional
を非 Optional
で満たすことができなかったとかではなく??protocol P { associatedtype A var a: A? { get } } struct S<T>: P { typealias A = T let value: T var a: T { return value } } let s = S(value: 42) print(s.a)
<stdin>:7:8: error: type 'S<T>' does not conform to protocol 'P' struct S<T>: P { ^ <stdin>:10:9: note: candidate has non-matching type 'T' var a: T { return value } ^ <stdin>:4:9: note: protocol requires property 'a' with type 'S<T>.A?'; do you want to add a stub? var a: A? { get } ^
1. オブジェクトを全部スキャンする 2. 検査したい関数を実行する 3. スキャンしてあるweak参照の先に生きてるオブジェクトが無いことを確認する
(edited)let target = createSomething() let memoryLeaks = detectLeaks(target) XCTAssertTrue( memoryLeaks.leakedObjects.isEmpty, memoryLeaks.prettyDescription )
class Cat { var parent: Cat? } func createSomething() -> Cat { let cat1 = Cat() let cat2 = Cat() let cat3 = Cat() cat2.parent = cat3 cat3.parent = cat2 return cat1 }
Summary: Found 0 leaked objects Leaked objects: (empty)
class Cat { var parent: Cat? var child: Cat? } func createSomething() -> Cat { let cat1 = Cat() let cat2 = Cat() let cat3 = Cat() cat2.parent = cat3 cat3.parent = cat2 cat2.child = cat1 return cat1 }
let json = """ [{ "id": 0, "mode": "high" },{ "id": 1, "mode": "middle" },{ "id": 2, "mode": "moddle" },{ "id": 3, "mode": "low" }] """ enum Mode: String, Decodable { case high case middle case low } struct Object: Decodable { let id: Int let mode: Mode } let objects = try! JSONDecoder().decode([Object].self, from: json.data(using: .utf8)!) print(objects)
↑のような時に、Jsonのデコードを失敗とせずid:0,1,3のObjectの配列を返すような実装がしたい場合Arrayのラッパーみたいなものを書く感じになるのでしょうか?enum Mode: String, Decodable { case high case middle case low } struct Object: Decodable { let id: Int let mode: Mode? } do { let decoder = JSONDecoder() let data = json.data(using: .utf8)! let objects = try decoder.decode([Object].self, from: data).compactMap({ $0.mode != nil }) print(objects) } catch { print(error) }
import Foundation let json = """ [{ "id": 0, "mode": "high" },{ "id": 1, "mode": "middle" },{ "id": 2, "mode": "moddle" },{ "id": 3, "mode": "low" }] """ enum Mode: String, Decodable { case high case middle case low } struct Object: Decodable { let id: Int let mode: Mode? enum CodingKeys: CodingKey { case id, mode } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.id = try container.decode(Int.self, forKey: .id) self.mode = try? container.decode(Mode.self, forKey: .mode) } } let objects = try! JSONDecoder().decode([Object].self, from: json.data(using: .utf8)!).filter { $0.mode != nil } print(objects)
[main.Object(id: 0, mode: Optional(main.Mode.high)), main.Object(id: 1, mode: Optional(main.Mode.middle)), main.Object(id: 3, mode: Optional(main.Mode.low))]
import Foundation let json = """ [{ "id": 0, "mode": "high" }, { "id": 1, "mode": "middle" }, { "id": 2, "mode": "moddle" }, { "id": 3, "mode": "low" } ] """ enum Mode: String, Decodable { case high case middle case low } struct Object: Decodable { let id: Int let mode: Mode init(id: Int, mode: Mode) { self.id = id self.mode = mode } } struct FailableBox<T> : Decodable where T : Decodable { init(from decoder: Decoder) throws { self.value = try? T.init(from: decoder) } var value: T? } let objects: [Object] = try! JSONDecoder() .decode([FailableBox<Object>].self, from: json.data(using: .utf8)!) .compactMap { $0.value } print(objects)
[main.Object(id: 0, mode: main.Mode.high), main.Object(id: 1, mode: main.Mode.middle), main.Object(id: 3, mode: main.Mode.low)]
import Foundation enum Result { case win case lose case none } var results: [Int : Result] = [:] results[0] = .win results[1] = .lose results[2] = .none if results[2] == nil { print("result.2 is nil") }
result.2 is nil
import Foundation enum Result { case win case lose case none } var results: [Int : Result] = [:] results[0] = .win results[1] = .lose results[2] = .some(.none) if results[2] == nil { print("result.2 is nil") }
Dictionary
の subscript
が -> Value?
だからかぁ。get
と set
で、 get
は Optional
だけど set
は Optional
でなくしたいケース、ときどきある気がしてる。enum Result { case win case lose case none } func foo(_ resultOrNil: Result?) { print(resultOrNil as Any) } foo(.win) foo(.lose) foo(.none) foo(Result.none)
Optional(main.Result.win) Optional(main.Result.lose) nil Optional(main.Result.none)
none
は避けるようにした方が無難そうですね。 (edited)removeValue(forKey:)
だけにして、 subscript set
を非 Optional
にしてほしいです・・・。set
で非 Optional
化できるようになっても、互換性の問題で Dictionary
の subscript set
をなくすのってできないかもですねdict[key] = nil
って便利構文なんじゃなくて、 subscript
の仕様制約上 set
を非 Optional
にできなかったため仕方なくついてるものだと思ってました。 (edited)nil
リテラルの代入で削除以外が起こることはないはずだから、nil
リテラルの代入以外のOptionalの代入をコンパイラか別のLinterが警告する というのが妥当か。print
のOptional
警告はあるから、 Dictionary
の subscript set
でもその線が妥当そうですね。Optional(2018)年
問題回避に役立ちますけど。CustomStringConvertible
以外できなくしちゃってもいいと思うんですよね。@nilWarning
属性みたいなものをつけられるといいのか?Optional
暗黙変換問題はどこででも起こりうるので、そういうのがあると良いのかも?@discardableResult
とかと同じで Attribute 付けるとかしないとできなくないですか?enum Result { case win case lose case none } let result: Result? = .none
これは暗黙変換ではなく Optional<Result>.none
を入れてるだけですよね。// result : Result? = nil
import Foundation enum Computer { case win case mac } enum Result { case win case lose case none case some(Computer) } func foo(_ resultOrNil: Result?) { print(resultOrNil as Any) } foo(.win) foo(.lose) foo(.none) foo(.some(.win)) print("") foo(Result.some(.win))
Optional(main.Result.win) Optional(main.Result.lose) nil Optional(main.Result.win) Optional(main.Result.some(main.Computer.win))
enum Hoge { case waiwai case mu(Never) } let hoge = Hoge.waiwai switch hoge { case .waiwai: print("わいわい") }
Result<Foo, Never>
の switch
で case .failure
書かなくても網羅的になるはず。 https://discordapp.com/channels/291054398077927425/291054454793306112/336463567039496192 "([0-9a-fA-F]+)\\.\\.([0-9a-fA-F]+);([a-zA-Z]+)"
そうですねえ。i
と element
の片方を let
、片方を var
にする方法ってありますか? let array = [2, 3, 5] for var (i, element) in array.enumerated() { print("\(i): \(element)") }
let array = [2, 3, 5] for (i, var element) in array.enumerated() { element += 1 print("\(i): \(element)") }
0: 3 1: 4 2: 6
let array = [2, 3, 5] for (i, var element) in array.enumerated() { i += 1 element += 1 print("\(i): \(element)") }
<stdin>:4:6: error: left side of mutating operator isn't mutable: 'i' is a 'let' constant i += 1 ~ ^
var
(let a, var b) = (2, 3)
var (x, y) = (0, 0) y = 190 print(x, y)
この形だとx is never mutatedの警告すら出ないですねvar
にするのがいいのかな。let x: Int var y: Int (x, y) = (0, 0)
一応これは可能です。 let point: (Int, Int)? = nil if case (let x, var y)? = point { print(x, y) }
static subscript
って作れないのか。 @swift-4.2.4
struct S { static subscript(i: Int) -> Int { return i + 1 } }
<stdin>:3:12: error: subscript cannot be marked 'static' static subscript(i: Int) -> Int { return i + 1 } ~~~~~~~^
class Container<Content> { init(a: Content) { // イニシャライザA fatalError() } init<T>(b: T) where T == Content { // イニシャライザB self.init(a: b as! Int) } }
(edited)class Container<Content> { init(a: Content) { fatalError() } init<T>(b: T) where T == Content { self.init(a: b as! Int) } }
<stdin>:7:27: error: same-type requirement makes generic parameters 'T' and 'Content' equivalent init<T>(b: T) where T == Content { ^ #0 0x000000000410ac94 PrintStackTraceSignalHandler(void*) (/usr/bin/swift+0x410ac94) #1 0x0000000004108b22 llvm::sys::RunSignalHandlers() (/usr/bin/swift+0x4108b22) #2 0x000000000410ae42 SignalHandler(int) (/usr/bin/swift+0x410ae42) #3 0x00007fdc32623390 __restore_rt (/lib/x86_64-linux-gnu/libpthread.so.0+0x11390) #4 0x00000000016b1b09 swift::FunctionType::get(swift::Type, swift::Type, swift::AnyFunctionType::ExtInfo const&) (/usr/bin/swift+0x16b1b09) #5 0x00000000017fde74 swift::GenericFunctionType::substGenericArgs(swift::SubstitutionMap const&) (/usr/bin/swift+0x17fde74) #6 0x00000000017fdd02 swift::GenericFunctionType::substGenericArgs(llvm::ArrayRef<swift::Substitution>) (/usr/bin/swift+0x17fdd02) #7 0x000000000147abe0 swift::UncurriedCandidate::UncurriedCandidate(swift::ValueDecl*, unsigned int) (/usr/bin/swift+0x147abe0) #8 0x000000000147f346 swift::CalleeCandidateInfo::CalleeCandidateInfo(swift::Type, llvm::ArrayRef<swift::constraints::OverloadChoice>, bool, swift::constraints::ConstraintSystem&, bool) (/usr/bin/swift+0x147f346) #9 0x0000000001466f19 (anonymous namespace)::FailureDiagnosis::visitApplyExpr(swift::ApplyExpr*) (/usr/bin/swift+0x1466f19) #10 0x000000000144d4d6 swift::ASTVisitor<(anonymous namespace)::FailureDiagnosis, bool, void, void, void, void, void>::visit(swift::Expr*) (/usr/bin/swift+0x144d4d6) #11 0x0000000001446642 swift::constraints::ConstraintSystem::diagnoseFailureForExpr(swift::Expr*) (/usr/bin/swift+0x1446642) #12 0x000000000144cb76 swift::constraints::ConstraintSystem::salvage(llvm::SmallVectorImpl<swift::constraints::Solution>&, swift::Expr*) (/usr/bin/swift+0x144cb76) #13 0x0000000001352138 swift::TypeChecker::solveForExpression(swift::Expr*&, swift::DeclContext*, swift::Type, swift::FreeTypeVariableBinding, swift::ExprTypeCheckListen
where T == Content
はダメだよって正しいエラーを吐いたあとにセグフォで死ぬのを見つけたT
しか受けないことが決まっているイニシャライザAに T
ではない Int
を渡せちゃってる?Stack dump: 0. Program arguments: /Applications/Xcode_10_1.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift -frontend -interpret Development/MyPlayground.playground/Contents.swift -enable-objc-interop -sdk /Applications/Xcode_10_1.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk -color-diagnostics -module-name Contents 1. While type-checking 'init(b:)' at Development/MyPlayground.playground/Contents.swift:6:5 2. While type-checking statement at [Development/MyPlayground.playground/Contents.swift:6:38 - line:8:5] RangeText="{ self.init(a: b as! Int) }" 3. While type-checking expression at [Development/MyPlayground.playground/Contents.swift:7:9 - line:7:31] RangeText="self.init(a: b as! Int)" fish: 'swift Development/MyPlayground.…' terminated by signal SIGSEGV (Address boundary error)
class Container<Content> { init(a: Content) { fatalError() } init<T>(b: T) where T == Content { self.init(a: b as! Int) } }
<stdin>:7:27: error: same-type requirement makes generic parameters 'T' and 'Content' equivalent init<T>(b: T) where T == Content { ^ <stdin>:8:14: error: cannot invoke 'Container<Content>.init' with an argument list of type '(a: Int)' self.init(a: b as! Int) ^ <stdin>:8:14: note: expected an argument list of type '(a: Content)' self.init(a: b as! Int) ^ <stdin>:7:5: error: designated initializer for 'Container<Content>' cannot delegate (with 'self.init'); did you mean this to be a convenience initializer? init<T>(b: T) where T == Content { ^ convenience <stdin>:8:14: note: delegation occurs here self.init(a: b as! Int) ^
for i in 1... { print(i) }
これ無限ループになるんですね、終端値無くてもrangeになるんだfunc eatBuffer() { self.buffer = Array(self.buffer[self.pos...]) self.pos = 0 }
↑ストリーム処理を書いているときにこれをよくやりますzip(0..., arraySlice)
swiftc
の代わりにSourceKitを使うSwiftSyntaxだ。swiftc
-> JSON -> SwiftSyntax -> SwiftLintFramework が SourceKit -> JSON -> SwiftSyntax -> SwiftLintFramework になってる。 (edited)[String: Any]
ベースよりも速くなる可能性があるな。 https://github.com/apple/swift-syntax/blob/master/Sources/SwiftSyntax/ByteTreeDeserialization.swiftPackage.resolved
をコミットしていないリポジトリにいつの間にかPackage.resolved
が生成されたり、知らないうちにPackage.resolved
が更新されたりしてたりしたのが不思議だったのだけど、SourceKit-LSPを入れたVSCodeでワーキングコピーを開いてたからだった。Package.swift
の中身がLinux向けとmacOS向けで依存するライブラリが違ってて、リポジトリにはLinux向けに生成されたPackage.resolved
がコミットされてて、それをmacOSのVSCodeで開くとPackage.resolved
が更新される。swift-5.0-DEVELOPMENT-SNAPSHOT-…
のmacOS版でString
のUTF16関連がぶっ壊れてるぽい。Data.withUnsafeBytes(_:)
がクロージャへコピーされた一時メモリを指すポインタを渡すように変わったからだった。import Foundation let data = "test".data(using: .utf8)! dump(data) data.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> Void in dump(bytes) }
(edited)▿ 4 bytes - count: 4 ▿ pointer: 0x00000000079af0d0 - pointerValue: 127594704 ▿ bytes: 4 elements - 116 - 101 - 115 - 116 ▿ 0x00000000079af0d0 - pointerValue: 127594704
(edited)pointerValue
が違う。 $ xcrun --toolchain org.swift.5020181225a swift swift_oss_helper command enabled. Welcome to Apple Swift version 5.0-dev (LLVM c351ac7354, Clang aadec4ff83, Swift 5cfc2e7ba9). Type :help for assistance. 1> import Foundation 2. let data = "test".data(using: .utf8)! 3. dump(data) 4. data.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) in 5. dump(bytes) 6. } ▿ 4 bytes - count: 4 ▿ pointer: 0x00007ffeefbff818 - pointerValue: 140732920756248 ▿ bytes: 4 elements - 116 - 101 - 115 - 116 ▿ 0x00007ffeefbffb30 - pointerValue: 140732920757040
(edited)Codable
は便利ですが、Foundation
のJSONEncoder
, JSONDecoder
を使っていて微妙に不便に感じる事があります。自分がいろいろな案件をこなしたり、他人の困り事を聞いてきた上で、...LinkedListObject
周りリークしまくりでは。LinkedListObject.Index
をLinkedListObject.Node?
にしたらシンプルになるのでは?と試してたのだけど、public typealias Index = Optional<Node>
を定義してもCollection
にconform出来ていないと文句を言ってくる。Collection.Index
にはOptional
を使えないのかな。extension Optional: Comparable where Wrapped: Comparable
になってなかった。Node
をSequence
にすると、func <
が少し簡単になる。next
をfollowing
に変えてる。 public static func < (lhs: LinkedListObject.Node, rhs: LinkedListObject.Node) -> Bool { if lhs == rhs || lhs.previous == rhs { return false } for following in lhs where following == rhs { return true } return false }
public typealias Index = Node?
案はやはり却下という結論に至った。func copy
でoldIndices
に書き戻してるところは、何に使うつもりで書かれてたのですか?Node
をCollection
に。 extension LinkedListObject.Node: Collection { public enum Index: Comparable { case node(LinkedListObject.Node), none public static func < (lhs: Index, rhs: Index) -> Bool { switch (lhs, rhs) { case (.node(let lhs), .node(let rhs)): return lhs < rhs case (.node(_), .none): return true default: return false } } init(_ node: LinkedListObject.Node?) { self = node.map(Index.node) ?? .none } var node: LinkedListObject.Node? { guard case .node(let node) = self else { return nil } return node } } public var startIndex: Index { return .node(self) } public var endIndex: Index { return .none } public subscript(position: Index) -> LinkedListObject.Node { guard let node = position.node else { preconditionFailure("Index out of range") } return node } public func index(after i: Index) -> Index { guard let node = i.node, let nextIndex = node.next.map(Index.node) else { return .none } return nextIndex } }
LinkedListObject.Node.Index
をLinkedListObject.Index
に。BidirectionalCollection
はLinkedListObject
で対応ですね。 extension LinkedListObject : BidirectionalCollection { public func index(before i: Index) -> Index { checkValidIndex(i) if i == endIndex { return Index(last) } precondition(i != startIndex, "Can't advance before startIndex") return Index(i.node?.previous) } }
Node
がCollection
になれるだけで、Collection
であるメリットは全く無い。Sequence
で十分。copy
周りはRangeReplaceableCollection
のreplaceSubrange()
みたいに、操作に必要なデータも渡してしまう方が良い気がする。XCTAssertNoThrow
の引数にtestBookModelに相当するクロージャー渡すのでもダメなのかな?(試してない)#define
で定義された式展開マクロみたいですね、これはどうしようもない。XCTAssertNoThrow(try { let book = try BookModel(from: sampleDictionary) XCTAssertEqual(book.name, "...") XCTAssertEqual(book.description, "...") }())
import XCTest :print_decl XCTAssertNoThrow
func XCTAssertNoThrow<T>(_ expression: @autoclosure () throws -> T, _ message: @autoclosure () -> String = default, file: StaticString = #file, line: UInt = #line)
XCTAssertNoThrow
のオリジナルはマクロの集合体で、シンボルとしては存在しないから、同じものとして扱っていないのでは。 #define XCTAssertNoThrow(expression, ...) \ _XCTPrimitiveAssertNoThrow(self, expression, @#expression, __VA_ARGS__) #define _XCTPrimitiveAssertNoThrow(test, expression, expressionStr, ...) \ ({ \ @try { \ (void)(expression); \ } \ @catch (NSException *exception) { \ _XCTRegisterFailure(test, _XCTFailureDescription(_XCTAssertion_NoThrow, 0, expressionStr, [exception reason]), __VA_ARGS__); \ } \ @catch (...) { \ _XCTRegisterFailure(test, _XCTFailureDescription(_XCTAssertion_NoThrow, 1, expressionStr), __VA_ARGS__); \ } \ }) …
var errorDescription: String?
を実装してやれば、NSError
変換されるときに勝手にlocalizedDescriptionになった。_swift_Foundation_getErrorDefaultUserInfo
これですかねCustomStringConvertible
で良さげ。 @swift-4.0.3
import XCTest struct MyError: Error, CustomStringConvertible { var description = "my error" } class Test: XCTestCase { func testA() throws { throw MyError() } static var allTests = [("testA", testA)] } XCTMain([testCase(Test.allTests)])
Test Suite 'All tests' started at 2019-01-21 20:10:23.991 Test Suite 'bin.xctest' started at 2019-01-21 20:10:23.993 Test Suite 'Test' started at 2019-01-21 20:10:23.993 Test Case 'Test.testA' started at 2019-01-21 20:10:23.993 <EXPR>:0: error: Test.testA : threw error "my error" Test Case 'Test.testA' failed (0.004 seconds) Test Suite 'Test' failed at 2019-01-21 20:10:23.997 Executed 1 test, with 1 failure (1 unexpected) in 0.004 (0.004) seconds Test Suite 'bin.xctest' failed at 2019-01-21 20:10:23.997 Executed 1 test, with 1 failure (1 unexpected) in 0.004 (0.004) seconds Test Suite 'All tests' failed at 2019-01-21 20:10:23.997 Executed 1 test, with 1 failure (1 unexpected) in 0.004 (0.004) seconds
==
で書いた場合だけか?// : Same-type constraint type 'P' does not conform to required protocol 'P' extension P where Self == P { func b() {} }
protocol P { func a() } struct ExP : P { let p: P func a() { print("existential") } } class Actor<T: P> { let p: T init(_ p: P) { self.p = ExP(p: p) } init(_ p: T) { self.p = p } }
SWIFT_EXEC
を置き換えて起動するのは面白い。 https://swift.org/blog/sourcekitd-stress-tester/swift-DEVELOPMENT-SNAPSHOT-2019-02-26-a.xctoolchain
.package(url: "https://github.com/apple/swift-syntax.git", .branch("master")),
の環境でやっているんですけど、SwiftSyntaxのビルドでSyntaxKindなどがないと怒られてしまいます。Replace <#Specify Release tag#> by the version of SwiftSyntax that you want to use (see the following table for mapping details). Swift Release Tag SwiftSyntax Release Tag swift-4.2-RELEASE 0.40200.0
47326318
ってSwift 4.2の変更だよね。 https://developer.apple.com/documentation/xcode_release_notes/xcode_10_2_beta_4_release_notes/swift_5_release_notes_for_xcode_10_2_beta_4
@swift-4.1.3 @swift-4.2.4 @swift-5.0.3
func forceCast<U>(_ value: Any?, to type: U.Type) -> U { return value as! U } let value: Any? = 42 print(forceCast(value, to: Any.self)) // Prints "Optional(42)" // (Prior to Swift 5, this would print "42".) print(value as! Any) // Prints "Optional(42)"
Optional(42) Optional(42)
stderr:<stdin>:10:13: warning: forced cast from 'Any?' to 'Any' always succeeds; did you mean to use 'as'? print(value as! Any) ^~~ as
42 Optional(42)
stderr:<stdin>:10:13: warning: forced cast from 'Any?' to 'Any' always succeeds; did you mean to use 'as'? print(value as! Any) ^~~ as
Optional(42) Optional(42)
stderr:<stdin>:10:13: warning: forced cast from 'Any?' to 'Any' always succeeds; did you mean to use 'as'? print(value as! Any) ^~~ as
struct Outer { typealias E = NestedValidation.T protocol NestedValidation { typealias T = A.B } }
func foo<Value>(_ x: Any?, as type: Value.Type) -> Value? { return x as? Value } dump(foo(nil, as: Any.self))
-swift-version 5
以外だと、Swift 4.1の挙動に戻るらしい… (edited)-swift-version 4.2
を付けることでSwift 4.2と非互換になるって、意味がわからん。#if compiler
では区別できそう? (edited)makefile
内で、xcodebuild
のバージョンによりswift build
へ渡す-Xswiftc -static-stdlib
の有無を使い分ける必要があるぽい。class A {} struct Box<T: A> {} let box = Box() print(box)
users.map(\.email)
// `self` key paths [1, nil, 3, nil, 5].compactMap(\.self)
↑これオシャレでいいな。 { $0 }
の意味。boolObservable.filter { $0 }
も同様に書ける?func foo<T>(_ t: T) { print(t) } let a: Any = 42 foo(a)
func foo<T: Any>(_ t: T) { print(t) } let a: Any = 42 foo(a)
func foo<T: AnyObject>(_ t: T) { print(t) } class C {} let a: AnyObject = C() foo(a)
func foo<T: Error>(_ t: T) { print(t) } struct E: Error {} let a: Error = E() foo(a)
<stdin>:8:1: error: cannot invoke 'foo' with an argument list of type '(Error)' foo(a) ^ <stdin>:8:1: note: expected an argument list of type '(T)' foo(a) ^
func foo<T: Error>(_ t: T) { print(t) } struct E: Error {} let a: Error = E() foo(a)
if #available
の否定ほしい const result = require('child_process').execSync('docker images kishikawakatsumi/swift --format "{{.Tag}}"').toString();
ほとんどの Container Registry ストレージ バケットに使用されるデフォルトの Cloud Storage クラスは、Multi-Regional です。 Multi-Regional バケットの月額料金は、約 $0.026/GB です。
https://cloud.google.com/container-registry/pricingstruct Stone { var a: Int var b: Int init(a: Int = 10 * 2 + 3 /*草*/ - (5 + 2), b: Int = 20) { self.a = a self.b = b } }
// SIL struct Stone { @_hasStorage var a: Int { get set } @_hasStorage var b: Int { get set } init(a: Int = 10 * 2 + 3 /*草*/ - (5 + 2), b: Int = 20) }
func nthOfEach( _ n: Int, from heterogeneousCollections: [any Collection] ) -> Any { return heterogeneousCollections.map { collection in // collection is `any Collection` let nthIndex = collection.startIndex.advanced(by: n) // error: inferred static type of nthIndex is something like `any Collection.Index`, // so compiler can’t guarantee it indexes `collection` … correct? return collection[nthIndex] } }
https://forums.swift.org/t/se-0244-opaque-result-types-reopened/22942/49func main() { let ac = AnyCollection<Int>([1]) let s = AnyCollection<Character>("str") let x = ac[s.startIndex] // Fatal error: Index type mismatch! } main()
let ac = AnyCollection<Int>([1]) let x = ac[ac.startIndex]
AnyCollection
を使った場合に↑の二つのコードを区別してコンパイル時の挙動を変える話。AnyCollection
というか generalized existential の問題の話で、同じことが type erasure でも言えるということじゃないかな。 (edited)AnyCollection
って AnyCollection<Element, Indices>
とかの方がよかったのでは・・・。 (edited)Iterator
と SubSequence
はいいけど、 Indices
が定まらないのはいいのかな・・・。 (edited)Self
戻り値はいいけど引数はダメみたいな話?AnyCollection<Element, Indices>
にすれば型安全にできる気がするけど、 generalized existential って必ずしもすべての associated type を指定しなければならないわけじゃないから、その辺りの型安全性を解決するのに path-dependent type が必要という話なんじゃないかな? (edited)AnyCollection
の場合は Indices
を型パラメータにしなかったのでそれを指定する手段がないから実行時エラーにするしかない。func g(_ x: P) { let a = x.value x.value = a }
value
プロパティについて、コードのフローを考慮して同じ型であることが保証できる場合のみ代入できるようにするとか?
as!
的な。let cs: [Character] = ["a", "b"] let str: String = "cde" func concat<T>(_ a: AnyCollection<T>, _ b: AnyCollection<T>) -> [T] { return a.map { $0 } + b.map { $0 } } let r = concat(AnyCollection(cs), AnyCollection(str)) print(r)
["a", "b", "c", "d", "e"]
let cs: [Character] = ["a", "b"] let str: String = "cde" func concat<T>(collections: [AnyCollection<T>]) -> [T] { return collections.reduce([]) { $0 + $1.map { $0 } } } let r = concat(collections: [AnyCollection(cs), AnyCollection(str)]) print(r)
["a", "b", "c", "d", "e"]
func hoge<T>() -> some Collection<.Element == T>
とかを許すので (edited)any Colleciton
とか any Collection<.Element == Int>
とか any Collection<.Element == Int, .Index == Int>
(edited)==
するときとかはそういうパターン。any Collection<.Element == Int>
の場合Index: any Comparable
として生成されるのかな、それだと例のクラッシュがありえるけどfunc nthOfEach( _ n: Int, from heterogeneousCollections: [any Collection] ) -> Any { return heterogeneousCollections.map { collection in // collection is `any Collection` let nthIndex = collection.startIndex.advanced(by: n) // error: inferred static type of nthIndex is something like `any Collection.Index`, // so compiler can’t guarantee it indexes `collection` … correct? return collection[nthIndex] } }
collection
… correct? mutating func Array.clip(low, high)
みたいなextensionをはやしてて、数が多くなってきたのでArray.ex.clip(low, high)
に移したいなと思ったんですが値型だとこれできないですよね……extension Array { var ex: Ex<Element> { get { return Ex(self) } set { self = newValue.array } } }
ex
をどっかに代入されたときなんですよね。.ex
方式、そもそもあんまりよくない気もするResult
は標準ライブラリの型だから、 @inlinable
がなくても specialize は行われるっていう認識でいいのかな?それだと "benchmarked to check if it's beneficial and not harmful" を作るのは更に難しそう。 (edited)@inlineable
以前から specialize された件って、 @_inlinable
とかのおかげだったってこと?public struct MyStruct1 { public internal(set) var x: Int @inlinable public init(x: Int) { self.x = x } } public struct MyStruct2 { @usableFromInline public internal(set) var x: Int @inlinable public init(x: Int) { self.x = x } }
<stdin>:11:5: error: '@usableFromInline' attribute can only be applied to internal declarations, but 'x' is public @usableFromInline ^~~~~~~~~~~~~~~~~ <stdin>:6:9: error: setter for 'x' is internal and cannot be referenced from an '@inlinable' function self.x = x ^ <stdin>:2:30: note: setter for 'x' is not '@usableFromInline' or public public internal(set) var x: Int ^ <stdin>:16:9: error: setter for 'x' is internal and cannot be referenced from an '@inlinable' function self.x = x ^ <stdin>:12:30: note: setter for 'x' is not '@usableFromInline' or public public internal(set) var x: Int ^
func testMultiplyPixel() { var rgba = [Double](repeating: 1, count: 4) let scalar: Double = 0.99 measure { // 0.108sec for _ in 0..<1000000 { rgba.withUnsafeMutableBufferPointer { var p = $0.baseAddress! for _ in 0..<$0.count { p.pointee *= scalar p += 1 } } } } } func testMultiplyPixel3() { var rgb = [Double](repeating: 1, count: 3) let scalar: Double = 0.99 measure { // 0.141sec for _ in 0..<1000000 { rgb.withUnsafeMutableBufferPointer { var p = $0.baseAddress! for _ in 0..<$0.count { p.pointee *= scalar p += 1 } } } } }
要素4つのほうが3つより早いという直感に反する結果に……$swiftc --emit-assembly
だけど[araki@Arakis-MBP No Backup]$ diff main3.txt main4.txt 22c22 < movl $3, %ecx --- > movl $4, %ecx
[araki@Arakis-MBP No Backup]$ diff main3.txt main4.txt 35c35 < movl $3, %edi --- > movl $4, %edi 37c37 < movq $3, 16(%rax) --- > movq $4, 16(%rax) 40,41c40 < movabsq $4607182418800017408, %rcx < movq %rcx, 48(%rax) --- > movupd %xmm0, 48(%rax)
[araki@Arakis-MBP No Backup]$ cat main.swift var rgb = [Double](repeating: 1, count: 3) let scalar: Double = 0.99 rgb.withUnsafeMutableBufferPointer { var p = $0.baseAddress! for _ in 0..<$0.count { p.pointee *= scalar p += 1 } } [araki@Arakis-MBP No Backup]$ swiftc -emit-assembly -O main.swift > main3.txt
[araki@Arakis-MBP No Backup]$ diff main3.txt main4.txt 20,23d19 < .section __TEXT,__literal8,8byte_literals < .p2align 3 < LCPI1_2: < .quad 4607092346807469998 43c39 < movl $3, %edi --- > movl $4, %edi 45c41 < movq $3, 16(%rax) --- > movq $4, 16(%rax) 48,49c44 < movabsq $4607182418800017408, %rcx < movq %rcx, 48(%rax) --- > movups %xmm0, 48(%rax) 85c80 < movl $3, %edi --- > movl $4, %edi 89,94c84,90 < movupd 32(%rdi), %xmm0 < mulpd LCPI1_1(%rip), %xmm0 < movupd %xmm0, 32(%rdi) < movsd 48(%rdi), %xmm0 < mulsd LCPI1_2(%rip), %xmm0 < movsd %xmm0, 48(%rdi) --- > movapd LCPI1_1(%rip), %xmm0 > movupd 32(%rdi), %xmm1 > movupd 48(%rdi), %xmm2 > mulpd %xmm0, %xmm1 > movupd %xmm1, 32(%rdi) > mulpd %xmm0, %xmm2 > movupd %xmm2, 48(%rdi)
func test() { var rgb = [Double](repeating: 1, count: 4) let scalar: Double = 0.99 rgb.withUnsafeMutableBufferPointer { var p = $0.baseAddress! for _ in 0..<$0.count { p.pointee *= scalar p += 1 } } }
rgb[0...1]
は128bitリテラル読み書き1回 rgb[2]
は64bit即値書き込み1回 rgb[0...1]
[2...3]
128bitリテラル読み込み1回書き込み2回 rgb[0...1]
128bit対象レジスタへ読み込み1回、128bitリテラルとレジスタの乗算1回、128bit書き込み1回 rgb[2]
64bit対象読レジスタへみ込み1回、64bit64bitリテラルとレジスタの乗算1回、64bit書き込み1回 rgb[0...1]
[2...3]
128bitリテラルをレジスタへ読み込み1回、128bit対象をレジスタへ読み込み2回、128bitレジスタ同士の乗算2回、128bit書き込み2回xmm0
に書き込まれるから順次実行、main4は乗算の結果を書き込む先がxmm1とxmm2別になってるから並列実行してそう。 (edited)scalar
を1度読めば使い回せるけど、 main3の方は 128bit 同士と 64bit同士になる関係で、 scalar
の読み込みが多くなっちゃう?async/await
が導入されたら [weak self]
やりたくなることが多そうだけどどうなるんだろう?↓とか? func asyncFoo() async { weak var welf: ViewController? = self let isFinished = await UIView.animate(withDuration: 0.5, animations: { ... }) guard let self = welf else { return } ... }
guard let
だと同一スコープで複数回同じ名前付けれないから、これまでネストしてた非同期処理で guard let self =
を何度も書けなくて self
のシャドーイングに落ち着いた名前問題が再燃する? (edited)await
後は(同一スコープなのに)いきなり明示的 self.
が必要になったり、色々変な感じになることがありそう・・・。 (edited)async
なクロージャと組み合わせられるとまずそう?class C { let foo: () async -> Void = { [weak self] in guard let self = self else { return } await bar() baz(self) } }
(edited)[weak self]
挟むから大丈夫か (edited)let fibs = Generator { yield in var (a, b) = (0, 1) while true { await yield(a) (a, b) = (b, a + b) } }
func actInf() { while true { sendMessage() } }
↑もしこれを(別スレッドなどで)呼び出したらselfは永遠に解放されないZ_SYNC_FLUSH
= 00 00 FF FF
でスプリットしろと書いてあるがこの4バイトが見当たらない。WebSocketClient
でWebSocketClientUpgradeHandler
がreceivedContents
へchannelRead
で受け取ったデータを溜め込む実装は筋が悪いと思うんだよね。 (edited)WebSocketClientUpgradeHandler
のchannelActive
は下流へchannelActive
を発火せず、channelRead
で.switchingProtocols
を受け取ったら自身をハンドラから削除してから下流へchannelActive
を発火することで、意図しないchannelRead
が発生しない様にしてる。 (edited)channelActive
を受け取らない限りread
もwrite
も起きないと思います。WebSocketClientUpgradeHandler
のchannelRead
はfireChannelRead
を呼ばない前提です。channelActive
, channelRead
を次のハンドラへ流さないことで、次のハンドラからのwrite
を抑制して予期しないchannelRead
を発生させない」ですね。 (edited)func median<T: Comparable>(bp: UnsafeMutableBufferPointer<T>) -> T { // error: cannot use mutating member on immutable value: 'bp' is a 'let' constant bp.sort() return bp[bp.count / 2] }
これってMutableCollection
の定義に従うためだけにmutating
なんですかねstruct
である UnsafeMutableBufferPointer
の nonmutating func
で状態が変更されるってカオスな気も。subscript
はすでにそうだった。nonmutatimg func
でオーバーライドができればいいのかな?protocol P { mutating func foo() } extension P { mutating func foo() { print("P") } } struct S: P { func foo() { print("S") } } let s: S = S() s.foo() // ↓エラー // let p: P = s // p.foo() var p: P = s p.foo()
nonmutating
な sort
実装できそうだね。
NSMutableArray
とかもなってるかも?Sequence
だけど MutableCollection
じゃないのか。 > NSMutableArray
UnsafeMutableAudioBufferListPointer
UnsafeMutableBufferPointer
UnsafeMutableRawBufferPointer
subscript set
が nonmutating
であるべきかは判断が難しい・・・。 https://developer.apple.com/documentation/swift/emptycollection/1541374-subscriptsort
もいけそうw https://developer.apple.com/documentation/swift/collectionofoneCollectionOfOne
については、 sort
は nonmutating
にできるけど、 subscript set
はできないね。CollectionOfOne
は微妙だし、 EmptyCollection
も意見が分かれるかもだけど、ポインタ系はやるべきな気がするね。 subscript set
も nonmutating
なわけだし。MutableCollection
以外で Mutable*
で nonmutating
できそうなものとかあるかなぁ。RangeReplaceableCollection
見てたけど、 append
とかはできないよね。count
を書き換えないといけないから。append
生えてないのか。let count
だけど、一応 self
書き換えはできるだろうけど。append
とかもない? (edited)UnsafeMutableAudioBufferListPointer
って初めて見た。UnsafeMutableBufferPointer
UnsafeMutableRawBufferPointer
protocol P { mutating func foo() } extension Array: P { func foo() { } } var a = [0, 1, 2] var p: P = a p.foo()
こういう形のときCoWがどうなるんだろうとか思ったり。func test1(bp: UnsafeMutableBufferPointer<Double>) { bp[0] = 0 } func test2(slice: Slice<UnsafeMutableBufferPointer<Double>>) { slice[0] = 0 // error: cannot assign through subscript: 'bp' is a 'let' constant }
こっちは対処するのめんどくさそうですが……func f() { ここに実装があるよ } mutating func f() { f() } // プロトコルへのconformだよ
これが出来れば丸く解決する (edited)inout
の話、前に話したことあるよね。 withUnsafeMutableBufferPointer
の inout
は過剰だけど、現状表現できるものが inout
しかないって。nonmutating
で実装されれば問題ない?self
書き換えならぬ inout
で渡されたもの自体を書き換えることを言ってる?↓みたいな感じで。 array.withUnsafeMutableBufferPointer { p in p = q }
let
で渡して欲しいね@escaping
にキャプチャされることを防ぐためには inout
が必要だけど、ポインタ自体の書き換えは封じられてるから、 inout
のそれ自体を書き換えられる機能は要らないという理解。 return bp
しちゃえば取り出せるからあんまり意味ないと思うreturn bp
と意図せずやってしまうキャプチャとでは、後者だけ防げるのは意味がある気がする。inout
を外すことを検討しても良さそうな気も。The issue with changing .swapTo (et al.?) to nonmutating is that semantically it really is a mutation. But pointers as collections have different mutation semantics to other collections: Mutating an Array’s storage is the same as mutating its value, whereas a pointer’s value is its address, not its storage. Making the Unsafe*Pointer MutableCollection methods themselves nonmutating probably wouldn’t be a source-breaking change (it’d just lower the “bar of entry” to include let constant instances too). I imagine this is noncontroversial.
https://forums.swift.org/t/why-does-the-withunsafemutablebufferpointer-closure-take-an-inout-parameter/6794/10 (edited)@escaping
キャプチャ防止の話はされてなさそう?protocol P { // mutating func foo() } extension P { mutating func foo() { print("P") } } struct S: P { func foo() { print("S") } } let s: S = S() s.foo() // "S" var s2: S = S() s2.foo() // "S" var p: P = s p.foo() // "S"
protocol P { // mutating func foo() } extension P { mutating func foo() { print("P") } } struct S: P { func foo() { print("S") } mutating func foo() { print("S2") } } let s: S = S() s.foo() // "S" var s2: S = S() s2.foo() // "S" var p: P = s p.foo() // "S"
(edited)<stdin>:15:19: error: invalid redeclaration of 'foo()' mutating func foo() { ^ <stdin>:12:10: note: 'foo()' previously declared here func foo() { ^
(edited)S
のままでは呼び出せないし。sort
が MutableCollection
にないのは、 Element
が Comparable
じゃないといけないからか。MutableCollection
methods as nonmutatingimport Foundation func time(label: String, f: ()->Void) { let start = Date() f() print("\(label): elapsed time: ", Date().timeIntervalSince(start), "sec") } var x = [Int](0..<65536) x.withUnsafeMutableBufferPointer { bp in time(label: "Slice") { bp[0..<60000].sort() } time(label: "Rebase") { var rebase = UnsafeMutableBufferPointer(rebasing: bp[0..<60000]) rebase.sort() } }
(edited)Stack dump: 0. Program arguments: /usr/bin/swift -frontend -interpret - -disable-objc-interop -I /Libraries/.build/x86_64-unknown-linux/debug -I /Libraries/.build/checkouts/SwiftBacktrace/Sources/CSwiftBacktrace/include -I /Libraries/.build/checkouts/SwiftBacktrace/Sources/Clibunwind/include -I /Libraries/.build/checkouts/swift-nio/Sources/CNIOHTTPParser/include -I /Libraries/.build/checkouts/swift-nio/Sources/CNIOSHA1/include -I /Libraries/.build/checkouts/swift-nio/Sources/CNIOAtomics/include -I /Libraries/.build/checkouts/swift-nio/Sources/CNIODarwin/include -I /Libraries/.build/checkouts/swift-nio/Sources/CNIOLinux/include -module-cache-path /Libraries/.build/x86_64-unknown-linux/debug/ModuleCache -O -D DEBUG -Xcc -fmodule-map-file=/Libraries/.build/checkouts/SwiftBacktrace/Sources/CSwiftBacktrace/include/module.modulemap -Xcc -fmodule-map-file=/Libraries/.build/checkouts/SwiftBacktrace/Sources/Clibunwind/include/module.modulemap -Xcc -fmodule-map-file=/Libraries/.build/x86_64-unknown-linux/debug/CNIOHTTPParser.build/module.modulemap -Xcc -fmodule-map-file=/Libraries/.build/x86_64-unknown-linux/debug/CNIOSHA1.build/module.modulemap -Xcc -fmodule-map-file=/Libraries/.build/x86_64-unknown-linux/debug/CNIOAtomics.build/module.modulemap -Xcc -fmodule-map-file=/Libraries/.build/x86_64-unknown-linux/debug/CNIODarwin.build/module.modulemap -Xcc -fmodule-map-file=/Libraries/.build/x86_64-unknown-linux/debug/CNIOLinux.build/module.modulemap -module-name main -lLibraries /usr/bin/swift[0x4626bd4] /usr/bin/swift[0x46249a0] /usr/bin/swift[0x4626d82] /lib/x86_64-linux-gnu/libpthread.so.0(+0x11390)[0x7fbbc7af7390] [0x7fbbc7f25d22] [0x7fbbc7f25837] [0x7fbbc7f24e3b] [0x7fbbc7f24d08] [0x7fbbc7f24af7] [0x7fbbc7f24862] [0x7fbbc7f242d3] /usr/bin/swift[0xcf1a7e] /usr/bin/swift[0xcf5c92] /usr/bin/swift[0x5162df] /usr/bin/swift[0x4eb215] /usr/bin/swift[0x4e66b6] /usr/bin/swift[0x48da2e] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7fbbc
(edited)string1 += string2
はちゃんと string1 = string1 + string2
よりも効率的に実装されてるのか。 https://github.com/apple/swift/blob/master/stdlib/public/core/String.swift#L575-L577+=
もかな。capacity
を持っておいたいいってことか。as!
によるキャストは真の型を実際に検証する。 (edited)public init(unsafeUninitializedCapacity:,initializingWith initializer:)
これinit+末尾クロージャのみのケースではだったらどうするんだろう……let a = [0, 1, 2] a.withUnsafeBufferPointer { defer { print($0) } _ = $0 }
let a = [0, 1, 2] a.withUnsafeBufferPointer { defer { print($0) } _ = $0 }
swift-4.2.1-RELEASE
/usercode/main.swift:4:15: error: anonymous closure argument not contained in a closure print($0) ^
.zero
じゃなくて0書くだけで少し高速化できる。 (edited)let ptr = UnsafeMutablePointer<Int8>.allocate(capacity: len) ptr[0] = Int8(Character("n").asciiValue!) ptr[1] = Int8(Character("e").asciiValue!) ptr[2] = Int8(Character("k").asciiValue!) ptr[3] = Int8(Character("o").asciiValue!) ptr[4] = Int8(Character("\0").asciiValue!) let immutablePtr = UnsafePointer<Int8>(ptr)! let neko = String(cString: immutablePtr)
(edited)CChar
なんですよ。CChar
がInt8
のtypealiasなのでInt8
に見えます。Character.asciiValue
に関してはアスキーキャラクターコードが 0x00 - 0xFF だからだと思います。UTF8
を受け取るCのAPIがUnsafePointer<UInt8>!
とかになってたりするから、UTF8
でもあるasciiValue
もUInt8
の方が便利そう。-Ounchecked
? (edited)-Ounchecked
を提案してみた。protocol Protocol { associatedtype T1 associatedtype T2 func myFunc<Bar, Baz>(_: Bar) -> Class<Bar.T1, Baz> where Bar: Class<T1, T2> } class Class<T1, T2> : Protocol { func myFunc<Bar, Baz>(_: Bar) -> Class<Bar.T1, Baz> where Bar: Class<T1, T2> { } }
このコードをコンパイルしようとすると Abort Trap:6 になるのですが、これって既知のバグでしょうか protocol Protocol { associatedtype T1 func myFunc<Bar>(_: Bar) -> Class<Bar.T1> where Bar: Class<T1> } class Class<T1> : Protocol { func myFunc<Bar>(_: Bar) -> Class<Bar.T1> where Bar: Class<T1> { } }
protocol Protocol { associatedtype T1 func myFunc<Bar>(_: Bar) -> Class<Bar.T1> where Bar: Class<T1> } class Class<T2> : Protocol { func myFunc<Bar>(_: Bar) -> Class<Bar.T1> where Bar: Class<T2> { } }
protocol Protocol { associatedtype T1 func myFunc<Bar>(_: Bar) -> Class<Bar.T1> where Bar: Class<T1> } class Class<T2> : Protocol { func myFunc<Bar>(_: Bar) -> Class<Bar.T1> where Bar: Class<T2> { } }
swift-4.2.1-RELEASE
/usercode/main.swift:4:43: error: reference to invalid associated type 'T1' of type 'Bar' func myFunc<Bar>(_: Bar) -> Class<Bar.T1> where Bar: Class<T1> ^ /usercode/main.swift:7:7: error: type 'Class<T2>' does not conform to protocol 'Protocol' class Class<T2> : Protocol { ^ /usercode/main.swift:2:20: note: protocol requires nested type 'T1'; do you want to add it? associatedtype T1 ^
While emitting witness table for protocol conformance to ...
が僕のと同じなので既知のBugでした、ありがとうございました swift struct ZeroRNG: RandomNumberGenerator { // Implements `mutating func next() -> UInt64` func next() -> UInt64 { return 0 } } let rng = ZeroRNG() print(rng.next()) var rng2 = rng print(Float.random(in: 0..<1, using: &rng2))
(edited)SystemRandomNumberGenerator
あたりにできなかった名残がありますが。 https://github.com/apple/swift/blob/master/stdlib/public/core/Random.swift#L157some
でassociatedType
の型を制限する @swift-5.1.5
protocol P1 { associatedtype A var a: A { get } } protocol AisInt: P1 where A == Int {} struct S<A>: P1 { var a: A } extension S: AisInt where A == Int {} func f1() -> some P1 { S(a: 1) } func f2() -> some AisInt { S(a: 1) } print(f1().a is Int) print(f2().a is Int)
true true
stderr:<stdin>:15:14: warning: 'is' test is always true print(f2().a is Int) ^
some
を使ってみようとしたけど、some
がネストすると型推測がうまくいかず断念した。Publishers.Deferred
はDeferred
へ変更 Publishers.Empty
はEmpty
へ変更 Publishers.Fail
はFail
へ変更 Publishers.Once
はResult.Publisher
へ変更 Publishers.Optional
はOptional.Publisher
へ変更 Publisher
型毎の特化実装メソッドが減る。 Published
のpropertyWrapper仕様が更新(acceptされた最新ではない) keyPath map関連がFoundation
からCombine
へ移動。AnyCancellable
をちゃんと保持しないと即座に解放される様になり、非同期なPublisherとかも解放されてしまい動かなくなった(たぶん正しい挙動になった)bar
はString?として扱えるのすごいな @propertyWrapper public struct UserDefault<Value> { private let key: String private let defaultValue: Value private let defaults: UserDefaults public init(key: String, defaultValue: Value, defaults: UserDefaults = .standard) { self.key = key self.defaultValue = defaultValue self.defaults = defaults } public var wrappedValue: Value { get { (defaults.object(forKey: key) as? Value) ?? defaultValue } set { defaults.set(newValue, forKey: key) } } } final class A { @UserDefault(key: "foo", defaultValue: nil, defaults: .standard) var foo: String? @UserDefault(key: "bar", defaultValue: nil, defaults: .standard) var bar: String }
(edited)CurrentValueSubject
は CoWとかしないんだね。let subject1 = CurrentValueSubject<Int, NSError>(1) let subject2 = subject1 subject1.value = 5 subject2.value == 5 // true
(edited)Codable
, Equatable
, Hashable
とか、その実装がコンパイラにより生成されたものを利用している、を保証する様な仕組みが欲しい気がする。func ==(P, P)
が実装してあっても、 P?
== P?
はできないのですぐ詰まるAnySubscriber
の実装が変わった。Subscriber
が要求する3つのインスタンスメソッドを保持する事で型を消してたけど、Boxクラスを使う形式に変わってる。AnySubscriber
周りで@inlinable
が使われる様になったため、Xcode-beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/Combine.framework/Modules/Combine.swiftmodule/x86_64.swiftinterface
を見ると実装がほぼ丸見え。Dictionary.subscript
のdefault
は、mutating
メンバを使うとDictionary
へ登録できる。 @swift-5.0.3
class ClassBox { var name = "" } var classDictionary = [String: ClassBox]() classDictionary["test", default: ClassBox()].name = "name" print("classDictionary:", classDictionary) struct ValueBox { var name = "" } var valueDictionary = [String: ValueBox]() valueDictionary["test", default: ValueBox()].name = "name" print("valueDictionary:", valueDictionary)
(edited)classDictionary: [:] valueDictionary: ["test": main.ValueBox(name: "name")]
(edited)as?
の右側のプロトコル部分を実行時に変えられる様にならない限りはそうなるのかな? (edited)func cast<T>(_ x: X, type: T.Type) -> X? { return x as? T }
↑こういうのはかけますよclass A { func foo() { } } class B <T> : A { override func foo(x: Any) { if let t = cast(x, T.self) { ... } } } func f(a: A) { a.foo() }
(edited)class C {} func cast<P>(_ any: Any, _ type: P.Type) -> (C & P)? { any as? (C & P) }
<stdin>:3:50: error: non-protocol, non-class type 'P' cannot be used within a protocol-constrained type func cast<P>(_ any: Any, _ type: P.Type) -> (C & P)? { ^ <stdin>:3:50: error: non-protocol, non-class type 'P' cannot be used within a protocol-constrained type func cast<P>(_ any: Any, _ type: P.Type) -> (C & P)? { ^ <stdin>:4:18: error: non-protocol, non-class type 'P' cannot be used within a protocol-constrained type any as? (C & P) ^
as?
の右側のプロトコル部分を実行時に変えられない」は合ってる? (edited)protocol P {} class A {} class B : A, P {} func f() -> A & P { return B() }
as?
によるキャストは普通の型の場合と protocol existentialの場合で全然別物が2種類あるのかな?P
の宣言はジェネリックパラメータとしてあるよ。 (edited)func f(_ x: Any) -> (A & P)? { return x as? A & P }
protocol P {} func f<T>(_ x: Any, _ t: T.Type) -> (P & T)? { return x as? P & T }
(edited)<stdin>:2:42: error: non-protocol, non-class type 'T' cannot be used within a protocol-constrained type func f<T>(_ x: Any, _ t: T.Type) -> (P & T)? { ^ <stdin>:2:42: error: non-protocol, non-class type 'T' cannot be used within a protocol-constrained type func f<T>(_ x: Any, _ t: T.Type) -> (P & T)? { ^ <stdin>:3:22: error: non-protocol, non-class type 'T' cannot be used within a protocol-constrained type return x as? P & T ^
(edited)@dynamicMemberLookup
とかあるよ。 (edited)_swift_dynamicCast
が呼ばれるな。 @swift-5.1.5
protocol P {} class C: P {} func cast(_ any: Any) -> (C & P)? { any as? (C & P) } _ = cast(C())
(edited)swift_conformsToSwiftProtocolImpl
の中で__swift5_proto
セクションの中のレコードを探すところですけど、 for (const auto &record : section) { auto &descriptor = *record.get(); // We only care about conformances for this protocol. if (descriptor.getProtocol() != protocol) continue;
void swift::initializeProtocolConformanceLookup() { REGISTER_FUNC( addImageCallback<TextSegment, ProtocolConformancesSection, addImageProtocolConformanceBlockCallback>); }
#define REGISTER_FUNC(...) _dyld_register_func_for_add_image(__VA_ARGS__)
When you call _dyld_register_func_for_add_image, the dynamic linker runtime calls the specified callback (func) once for each of the images that is currently loaded into the program. When a new image is added to the program, your callback is called again with the mach_header for the new image, and the virtual memory slide amount of the new image.
protocol P {} class C: P {} func cast(_ any: Any) -> (C & P)? { any as? (C & P) } _ = cast(C())
これ、C & P
のメタデータを用意してキャストするコードが生成されるから、witness tableも持ってそう。C
が既にP
だというのは考慮されていない感じ。_swift_dynamicCast
に丸投げで、結果witness table不要となる可能性があるのかも。Array<Optional<T>>
が一度作られるところの複雑度が高い気がするけど mapの方は ?? []
のところでArrayのカッコがまた出てくるのが気に食わん。map
の方だ。!
があるのが嫌だけど直感的には一番わかりやすいですね
protocol P : AnyObject {} struct S<T: AnyObject> {} // 'S' requires that 'P' be a class type S<P>()
(edited)protocol P : AnyObject {} class C : P {} struct S<T: AnyObject> {} var a: P = C() var b: AnyObject = a as AnyObject
P?
のweak var
も作れるんだよなあ。:AnyObject
の場合はstruct ClassExistentialContainer { HeapObject *value; WitnessTable *witnessTables[NUM_WITNESS_TABLES]; };
struct Weak<T: AnyObject> { }
↑これに入れたかったprotocol
を@objc protocol
にすれば@objc
使いたくないンゴねT: P
をstrong参照 AnyP<X: P>
はT: P
を内部でstrong参照 Weak<Y>
はY = AnyP<T>
を内部でweak参照WeakAnyP
の実装が必要で、 これだとうまくいくんだなswift-5.1.2-RELEASE
は出ないのかな。extension Optional { public mutating func consume<R>(_ f: (Wrapped) throws -> R) rethrows -> R? { guard let x = self else { return nil } self = nil return try f(x) }
self.cameraCapture.consume { $0.dispose() } // ↓と同じ if let c = self.cameraCapture { c.dispose() self.cameraCapture = nil }
(edited)guard let capture = (self.cameraCapture.consume { $0 }) else { return } use(capture) // ↓と同じ guard let capture = self.cameraCapture else { return } self.cameraCapture = nil use(capture)
protocol Enum { static func associatedValue(_ value: String) -> Self static var singleValue: Self { get } } enum Foo: Enum { case associatedValue(String) case singleValue }
protocol Enum { static func associatedValue(_ value: String) -> Self static var singleValue: Self { get } } enum Foo: Enum { static func associatedValue(_ value: String) -> Foo { _associatedValue(value) } static var singleValue: Foo { _singleValue } case _associatedValue(String) case _singleValue }
class X { init(){} deinit { print("deinit") } } do { let x = X() print(x) } let x = X() print(x)
(edited)class X { init(){} deinit { print("deinit") } } do { let x = X() print(x) } let x = X() print(x)
swift-5.1-RELEASE
main.X deinit main.X
class X { init(){} deinit { print("deinit") } } do { let x = X() print(x) } let x = X() print(x)
swift-DEVELOPMENT-SNAPSHOT-2019-11-08-a
main.X deinit main.X
// c3.swift public protocol P { func foo() -> Int }
; c3.ll ... @"$s2c31PMp" = constant <{ i32, i32, i32, i32, i32, i32, %swift.protocol_requirement }> <{ i32 65603, ...
(edited)// c4.cpp #include <stdio.h> #include <stdlib.h> #include <dlfcn.h> int main() { void *handle = dlopen(nullptr, RTLD_LAZY); if (!handle) { printf("dlopen failed: %s\n", dlerror()); return 0; } void *symbol = dlsym(handle, "$s2c31PMp"); if (!symbol) { printf("symbol not found: %s\n", dlerror()); return 0; } int32_t flags = ((int32_t *)symbol)[0]; printf("flags=%d\n", flags); if (dlclose(handle)) { printf("dlclose failed: %s\n", dlerror()); return 0; } return 0; }
$ clang++ -std=c++14 c4.cpp -c -S -emit-llvm $ ./c4.out flags=65603
protocol EquatableOpener { init<T>(_ value: T) init<T: Equatable>(_ value: T) } func openEquatable<EO: EquatableOpener>(_ value: Any, openerType: EO.Type) -> EO { // 黒魔術 }
AnyEquatable
を openEquatableに渡せるstruct MyAnyHashable: Hashable { var originalHashValue: Int var originalTypeIdentifier: ObjectIdentifier init<H: Hashable>(_ origin: H) { self.originalHashValue = origin.hashValue self.originalTypeIdentifier = ObjectIdentifier(H.self) } } print(MyAnyHashable(1) == MyAnyHashable(1.0))
Dictionary<AnyHashable, Any>
だし。 (edited)NSNumber
になるprint("hello")
print("hello")
swift-5.1.3-RELEASE
hello
struct Cont<A, B> { var run: ((A) -> B) -> B var flatMap: (A) -> Cont<A, B> { get { fatalError() } _modify { let that = self var me: (A) -> Cont<A, B> = { (a: A) -> Cont<A, B> in that } yield &me let tmp = { (k: (A) -> B) -> B in that.run({ (a: A) -> B in me(a).run(k) }) } run = tmp } } } var a = Cont<Int, Int>( run: { (k: (Int) -> Int) -> Int in k(1) } ) a.flatMap = { (x: Int) -> Cont<Int, Int> in Cont<Int, Int>( run: { (k: (Int) -> Int) -> Int in k(x + 1000) } ) } a.flatMap = { (x: Int) -> Cont<Int, Int> in Cont<Int, Int>( run: { (k: (Int) -> Int) -> Int in k(x + 2000) } ) } a.run( { (a: Int) in print(a) return a } )
struct Cont<A, B> { var run: ((A) -> B) -> B var flatMap: (A) -> Cont<A, B> { get { fatalError() } _modify { let that = self var me: (A) -> Cont<A, B> = { (a: A) -> Cont<A, B> in that } yield &me let tmp = { (k: (A) -> B) -> B in that.run({ (a: A) -> B in me(a).run(k) }) } run = tmp } } } var a = Cont<Int, Int>( run: { (k: (Int) -> Int) -> Int in k(1) } ) a.flatMap = { (x: Int) -> Cont<Int, Int> in Cont<Int, Int>( run: { (k: (Int) -> Int) -> Int in k(x + 1000) } ) } a.flatMap = { (x: Int) -> Cont<Int, Int> in Cont<Int, Int>( run: { (k: (Int) -> Int) -> Int in k(x + 2000) } ) } a.run( { (a: Int) in print(a) return a } )
swift-5.1.3-RELEASE
3001
/usercode/main.swift:31:3: warning: result of call to function returning 'Int' is unused a.run( { (a: Int) in ^ ~~~~~~~~~~~~~~~
$ swiftc yield.swift -emit-sil Run module pass #0, stage Guaranteed Passes, pass 0: SILGenCleanup (silgen-cleanup) Start function passes at stage: Guaranteed Passes Run #1, stage Guaranteed Passes, pass 1: DiagnoseInvalidEscapingCaptures (diagnose-invalid-escaping-captures), Function: $s5yield4NekoC4_bow33_BFC072E4B657A1986E9E174ACA620350LLSSvpfi Run #2, stage Guaranteed Passes, pass 2: DiagnoseStaticExclusivity (diagnose-static-exclusivity), Function: $s5yield4NekoC4_bow33_BFC072E4B657A1986E9E174ACA620350LLSSvpfi Run #3, stage Guaran # 中略 Run #135, stage Guaranteed Passes, pass 20: YieldOnceCheck (yield-once-check), Function: $s5yield4NekoC3bowSSvM yield.swift:9:13: error: accessor must not yield more than once yield &_bow ^ yield.swift:8:13: note: previous yield was here yield &_bow ^ Run #136, stage Guaranteed
(edited)func factorial(of n: Int) -> Int { func f(_ n: Int, _ r: Int) -> Int { n <= 1 ? r : f(n - 1, r * n) } return f(n, 1) }
@inline(__always) func factorial(of n: Int) -> Int { func f(_ n: Int, _ r: Int) -> Int { n <= 1 ? r : f(n - 1, r * n) } return f(n, 1) } print(factorial(of: 5))
define i32 @main(i32, i8** nocapture readnone) local_unnamed_addr #0 { entry: ... %._value = bitcast %swift.refcounted* %13 to i64* store i64 120, i64* %._value, align 8 ... ret i32 0 }
120
まで計算されて埋め込まれてる。print(factorial(of: [5].randomElement()!))
Generic<T>
であっても構成する静的な経路によって T
の conformance が変わるんだなあ let topMargin = 190 NSLayoutConstraint.activate([ contentViewController.view.topAnchor.constraint(equalTo: view.topAnchor, constant: topMargin), ...
^ こういう場合の topMargin
をIntじゃなくてCGFloatに推測してくれるようにならないかな。右辺を別の行まで拡大する、みたいな。import scala.language.implicitConversions class A(val value: Int) {} implicit def toA(value: Int): A = new A(value) def f(x: A): Int = x.value * 2 val a = 100 val y = f(a) println(y) // 200
このとき、aの型はIntです。 暗黙的に関数が呼ばれるだけなので、型推論に影響を及ぼしているわけではないと思います。 (久しぶりにScala書きました。間違ってたらすみません) (edited)let topMargin = 190 // ここの左辺の型を右辺からじゃなくて、 ...constraint(equalTo: view.topAnchor, constant: topMargin) // ここの代入から推論してくれてもいいんじゃない?
だったんですけど、let topMargin = 190 // ここは右辺からIntと推論 topMargin) // ここでCGFloat(190) を暗黙的によぶ
ということだと思うので、厳密には違いそう。 (edited)...constraint(equalTo: view.topAnchor, constant: 190)
これと同じ扱いにしてほしい、という考えで要するにリテラルからの場合のみ、ということになるはずなので行けると思ってるんですよね。let mut v = Vec::new(); let a: u32 = 1; v.push(a);
func f() -> Int { print(1); return 0 } func f() -> String { print(2); return "" } let a: Int = f()
↑こういうのは動的にやるのは無理だけど、動的言語でも事前検査してディスパッチを書き換える事はできると思う。objc_direct
とかを使える様になってる。 https://nshipster.com/direct/ (edited)@property(direct)
が通る事を確認した。Notes on Approach The key idea here is using the bytes of a UInt64 in a way similarly to SIMD. When doing ASCII operations the new UTF-8 backing of Strings makes them perfectly suited for this technique. Aside from integer parsing, for example also ASCII case manipulation sees many-X speed-ups when using this approach. Example (details below): let str = 0x3132_3030_3633_3739 // ASCII "12006379" let digits = str &- 0x3030_3030_3030_3030 // Subtract "0" from every lane // … (underflow check omitted for clarity) let c = (0x7f - 9) &* 0x0101_0101_0101_0101 // Constant to check value > 9 let isAnyAbove9 = (digits &+ c) & 0x8080_8080_8080_8080 != 0
@UIApplicationMain
とかをユーザーが自作できるようにするやつ、急にピッチ来たと思ったら急に審査来てた。@UIApplicationMain
が出てきた時、いったいどうやって起動してるのかわからなくなったから、 昔の main.m が生成されて、その中に UIApplicationMain
関数の呼び出しが普通に書いてあるやつのほうが好きだった (edited)func f(_ aa: Int = 0, _ bb: Int) {} f(1)
<stdin>:2:4: error: missing argument for parameter #2 in call f(1) ^ , <#Int#> <stdin>:1:6: note: 'f' declared here func f(_ aa: Int = 0, _ bb: Int) {} ^
func f(_ aa: Int = 0, _ bb: Double) {} f(1.0)
<stdin>:2:3: error: missing argument for parameter #1 in call f(1.0) ^ <#Int#>, <stdin>:1:6: note: 'f' declared here func f(_ aa: Int = 0, _ bb: Double) {} ^
#1
になってる。aa
が missing なのは許されるはずか。func f(_ aa: Int = 0, _ bb: Double) {} let bb: Double = 1.0 f(bb)
<stdin>:4:3: error: missing argument for parameter #1 in call f(bb) ^ <#Int#>, <stdin>:1:6: note: 'f' declared here func f(_ aa: Int = 0, _ bb: Double) {} ^
<stdin>:4:3: error: missing argument for parameter #1 in call f(bb) ^ <#Int#>, <stdin>:1:6: note: 'f' declared here func f(_ aa: Int = 0, _ bb: Double) {} ^
<stdin>:4:5: error: missing argument for parameter #2 in call f(bb) ^ , <#Double#> <stdin>:1:6: note: 'f' declared here func f(_ aa: Int = 0, _ bb: Double) {} ^
bb
は Double
だから省略されてるのは aa
だとラベルなくても判断できるけど、エラーで正しいでいいのかな?-debug-constraints
見ると、masterの挙動だと、 synthesize missing argument fixだけじゃなくて、allow argument to parameter type conversion mismatch fix も生成されていてfunc f(_ aa: Int..., _ bb: Double) {}
なのでこの制限があるんですね。<stdin>:1:22: error: a parameter following a variadic parameter requires a label func f(_ aa: Int..., _ bb: Double) {} ^
func f(_ aa: Int = 0, _ bb: Int) { print(1) } func f(_ bb: Int) { print(2) } f(1)
func f(_ bb: Double) {} func f(_ aa: Int, _ bb: Double) {} f(1.0)
func f(_ aa: Int = 0, _ bb: Int) { print(1) }
にはマッチしないんだから、 func f(_ bb: Int)
が選ばれるのは自然なんじゃないの?func f(_ aa: Int = 0, _ bb: Int)
にマッチしないのがバグだとみなすなら、意地悪だなと思いました。 (edited)func f(_ aa: Int = 0, _ bb: Int) {} // ↑が↓のオーバーロードを意味していると捉えるなら func f(_ bb: Int) {} func f(_ aa: Int, _ bb: Int) {} // 並べるなら下つじゃないと変。
(edited)func f(_ aa: Int, _ bb: Int = 0) { print(1) } func f(_ bb: Int) { print(2) } f(1)
comparing solutions 1 and 0 Comparing declarations func f(_ bb: Int) { } and func f(_ aa: Int, _ bb: Int = 0) { } (isDynamicOverloadComparison: 0) (found solution 0 0 0 0 0 0 0 0 0 0 0 0 0) comparison result: better Comparing declarations func f(_ aa: Int, _ bb: Int = 0) { } and func f(_ bb: Int) { } (isDynamicOverloadComparison: 0) comparison result: not better comparing solutions 1 and 0
protocol P { func f(_: Int) func f(_: Int, _: Int) } struct S: P { func f(_ aa: Int, _ bb: Int = 0) { print(1) } } let s: S = S() s.f(42)
<stdin>:6:8: error: type 'S' does not conform to protocol 'P' struct S: P { ^ <stdin>:2:10: note: protocol requires function 'f' with type '(Int) -> ()'; do you want to add a stub? func f(_: Int) ^
protocol P { func f(a: Int) } struct S: P { func f(a: Int, b: Int = 0) {} }
<stdin>:4:8: error: type 'S' does not conform to protocol 'P' struct S: P { ^ <stdin>:2:8: note: protocol requires function 'f(a:)' with type '(Int) -> ()'; do you want to add a stub? func f(a: Int) ^
protocol P { func f(a: Int) func f(a: String) } struct S: P { func f<T>(a: T) {} }
protocol P { func f(_: Int, _: Int) } extension P { func f(_ aa: Int) { print(2) } } struct S: P { func f(_ aa: Int, _ bb: Int = 0) { print(1) } } let s: S = S() s.f(42)
protocol P { func f(_: Int, _: Int) } extension P { func f(_ aa: Int) { print(2) } } struct S: P { func f(_ aa: Int, _ bb: Int = 0) { print(1) } } let s: S = S() s.f(42) let p: P = s p.f(42)
protocol P { func f(_: Int) func f(_: Int, _: Int) } extension P { func f(_ aa: Int) { print(2) } } struct S: P { func f(_ aa: Int, _ bb: Int = 0) { print(1) } } let s: S = S() s.f(42) let p: P = s p.f(42)
protocol P { func f(_: Int) func f(_: Int, _: Int) } extension P { func f(_ aa: Int) { print(2) } } struct S: P { func f(_ aa: Int) { print(3) } func f(_ aa: Int, _ bb: Int = 0) { print(1) } } let s: S = S() s.f(42) let p: P = s p.f(42)
class C1 { func f(_ aa: Int) { print(1) } func f(_ aa: Int, _ bb: Int) { print(2) } } class C2: C1 { override func f(_ aa: Int, _ bb: Int = 0) { print(3) } } let c2: C2 = C2() c2.f(42) let c1: C1 = c2 c1.f(42)
Comparing declarations func f(_ aa: Int) { } and func f(_ aa: Int, _ bb: Int = 0) { } (isDynamicOverloadComparison: 0) comparison result: not better Comparing declarations func f(_ aa: Int, _ bb: Int = 0) { } and func f(_ aa: Int) { } (isDynamicOverloadComparison: 0) comparison result: better comparing solutions 0 and 1
--- Solution #0 --- locator@0x7fd8578d8e00 [DeclRef@b.swift:15:3] with b.(file).main(a:).a@b.swift:14:11 as a: S --- Solution #1 --- locator@0x7fd8578d8e50 [UnresolvedDot@b.swift:15:5 -> member] with b.(file).P extension.f@b.swift:7:8 as S.f: (Int) -> () Opened types: locator@0x7fd8578d8e50 [UnresolvedDot@b.swift:15:5 -> member] opens τ_0_0 -> $T4
P.f
の呼び出しは実際には func f<Self>(self: Self, _ aa: Int)
の呼び出しだから (edited)print
する値もそろえてみた。 @swift-main
protocol P { func f(_: Int) func f(_: Int, _: Int) } extension P { func f(_ aa: Int) { print(1) } } struct S: P { func f(_ aa: Int, _ bb: Int = 0) { print(2) } } let s: S = S() s.f(42) let p: P = s p.f(42) ////////////////////// class C1 { func f(_ aa: Int) { print(1) } func f(_ aa: Int, _ bb: Int) { print(999) } } class C2: C1 { override func f(_ aa: Int, _ bb: Int = 0) { print(2) } } let c2: C2 = C2() c2.f(42) let c1: C1 = c2 c1.f(42)
func f(_ aa: Int..., bb: String = "", _ cc: Double) {} func main(i: Int, d: Double) { f(i, i, i, d) }
<stdin>:4:9: error: missing argument for parameter #3 in call f(i, i, i, d) ^ , <#Double#> <stdin>:1:6: note: 'f(_:bb:_:)' declared here func f(_ aa: Int..., bb: String = "", _ cc: Double) {} ^ <stdin>:4:14: error: cannot convert value of type 'Double' to expected argument type 'Int' f(i, i, i, d) ^ Int( )
d
だけ #3
に対応させるしか無いはず。func f(_ aa: Int..., bb: String = "", _ cc: Double) {}
は少なくとも現状は通らないようにすべきだ。bb:
を与えて区切れるから書けても良くないですか?func f(_ aa: Int = 0, _ bb: Int) {} f(1, 2)
= 0
は無駄なので警告かエラーがいいかと。func foo(a a1: Int = 1, a a2: Int) {}
(edited)func f(aa a1: Int = 1, aa a2: Int) {} f(aa: 2)
<stdin>:2:8: error: missing argument for parameter 'aa' in call f(aa: 2) ^ , aa: <#Int#> <stdin>:1:6: note: 'f(aa:aa:)' declared here func f(aa a1: Int = 1, aa a2: Int) {} ^
@_disfavoredOverload
使っててウケる。@_disfavoredOverload
が付いてたら、それを呼ぶ側が知らない場合、こっちが呼ばれるはずだけどなぜかこっち、みたいな混乱が起こりますか?Text("hoge")
みたいな、文字列リテラルを与えたケースの優先度がひっくり返ってる@overloadPrecedence(800)
みたいなので決められるのがいいんじゃないか。@favoredOverload(1)
@favoredOverload(2)
とかで数字が大きい方に吸い込まれるならわかりやすそう。protocol P1 { func f(a: Int) } protocol P2 { func f(a: Double) } func main(x: P1 & P2) { x.f(a: 0) }
#2
になるやつ) はめっちゃピンポイントな特別実装がされてた。func f(x: String, _ aa: Int = 0, _ bb: Double) {} f("", 42.0)
<stdin>:2:3: error: missing argument for parameter 'x' in call f("", 42.0) ^ x: <#String#>, <stdin>:1:6: note: 'f(x:_:_:)' declared here func f(x: String, _ aa: Int = 0, _ bb: Double) {} ^ <stdin>:2:3: error: cannot convert value of type 'String' to expected argument type 'Int' f("", 42.0) ^
func f(x: String, _ aa: Int = 0, _ bb: Double) {} f(x: "", 42.0)
<stdin>:2:14: error: missing argument for parameter #3 in call f(x: "", 42.0) ^ , <#Double#> <stdin>:1:6: note: 'f(x:_:_:)' declared here func f(x: String, _ aa: Int = 0, _ bb: Double) {} ^ <stdin>:2:10: error: cannot convert value of type 'Double' to expected argument type 'Int' f(x: "", 42.0) ^ Int()
<stdin>:2:14: error: missing argument for parameter #3 in call f(x: "", 42.0) ^ , <#Double#> <stdin>:1:6: note: 'f(x:_:_:)' declared here func f(x: String, _ aa: Int = 0, _ bb: Double) {} ^ <stdin>:2:10: error: cannot convert value of type 'Double' to expected argument type 'Int' f(x: "", 42.0) ^ Int()
<stdin>:2:14: error: missing argument for parameter #3 in call f(x: "", 42.0) ^ , <#Double#> <stdin>:1:6: note: 'f(x:_:_:)' declared here func f(x: String, _ aa: Int = 0, _ bb: Double) {} ^
#2
と #3
になってない・・・。func f(a: Int, b: String) {} f(a: "a")
<stdin>:2:3: error: missing argument for parameter 'a' in call f(a: "a") ^ a: <#Int#>, <stdin>:1:6: note: 'f(a:b:)' declared here func f(a: Int, b: String) {} ^
a:
は渡してるのにwa
と b
は解消されても a
と a
は元に戻っちゃうよね?ということ。[0]
と [1]
だけに対応が入ってるけど[0]
と [1]
以外でも同じ問題は起こり得るよね?それこそさっきの異なるラベルの第一引数を入れるとか。[0]
と [1]
だけ対応したんだろう?UIView.animate(withDuration: 0.3) { self.view.alpha = 0 } completion: { _ in self.view.removeFromSuperview() }
animations:
は書かないけど completion:
は書くの?animations
が本体で completion
は付随する処理てきなイメージなのかな?そういう場合に使う想定?UIView.animate(withDuration: 0.3, animation: { self.view.alpha = 0 }) { self.view.removeFromSuperview() }
も相変わらず書けるので、想定の呼び出し方を強制するものでもないですね。UIView.animate
の場合は 奇跡的にその仕様でも自然に見えるな・・・.animate(
が animationの指定の部分のタイトルっぽく見えるから・・・UIView.animate(withDuration: 0.3) animation: { self.view.alpha = 0 } completion: { _ in self.view.removeFromSuperview() }
↑こう書きたいな。Button { print("hello world") } label: { HStack { ... } }
SwiftUIだとこんな感じになるのかなaction
後ろの方が良さそうに見えますね。ipAddressPublisher .sink receiveCompletion: { completion in // handle error }
()
ない場合、ラベル書けると気持ち悪いですね。 < Alternatives Consideredで否定_
の場合だけこの機能使えるとかの方がいいんじゃないかな?UIView.animate
の場合は+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion API_AVAILABLE(ios(4.0)); // delay = 0.0, options = 0 + (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations API_AVAILABLE(ios(4.0)); // delay = 0.0, options = 0, completion = NULL
ipAddressPublisher .sink() receiveCompletion: { completion in // handle error }
_
でないと trailing closure 禁止でいい気がする・・・UIView.animate { }
もだめになって:
も省略しちゃえば func if(_ condition: Bool, _ body: () -> Void, else: () -> Void) { ... } if(foo) { ... } else { ... }
とかできるけど、 Swift でやることじゃないね。 (edited){}
省略とかだとなんとかならないかな?LABEL: { }
が今通らないなelse if
を↑の枠組みでどう書くか。else_if
版をオーバーロードかなあ。{}
で書きたいケースもあるからfunc foo(_ x: @autoclosure () -> Int) { print(x()) } foo { 42 }
<stdin>:3:5: error: cannot convert value of type '() -> Int' to expected argument type 'Int' foo { 42 } ^
func foo(_ x: @autoclosure () -> Int) { print(x()) } foo({ 42 })
(edited)<stdin>:2:5: error: function produces expected type 'Int'; did you mean to call it with '()'? foo({ 42 }) ^~~~~~ ()
(edited)func foo(_ x: @autoclosure () -> Int) { print(x()) } foo(42)
String result = MessageFormat.format( "At {1,time} on {1,date}, there was {2} on planet " + "{0,number,integer}.", arguments);
[T]
なのか T, T, T,...
へのsplatなのかわからない。$ cat AmbiguousVarArgs.java public class AmbiguousVarArgs { public static void main(String[] args) { String[] ss = { "XYZ" }; foo(ss); } static <T> void foo(T... xs) { System.out.println(xs); } } $ javac AmbiguousVarArgs.java Note: AmbiguousVarArgs.java uses unchecked or unsafe operations. Note: Recompile with -Xlint:unchecked for details. $ javac -Xlint:unchecked AmbiguousVarArgs.java AmbiguousVarArgs.java:7: warning: [unchecked] Possible heap pollution from parameterized vararg type T static <T> void foo(T... xs) { ^ where T is a type-variable: T extends Object declared in method <T>foo(T...) 1 warning $ java AmbiguousVarArgs [Ljava.lang.String;@7852e922
String[] ss
の文字列表現、に見えます。foo(T... xs) {
のxsには配列が渡るんじゃないですか?printf
は可変長だけど。println(Object x)
が呼ばれたんだな。System.out
が PrintStream
だったか自信がなくなったけど大丈夫でした。 https://docs.oracle.com/javase/jp/8/docs/api/java/lang/System.html#outxs
が String[][]
になる可能性があると思います。 (edited)Object
だからおかしいか。xs
が 第一要素に String[]
が入った Object[]
になるのか、 Object[]
にアップキャストされた String[]
になるのかの曖昧さ?Object[]
に String[]
を入れられるんですけど、ミュータブルなのでぶっ壊れます。 $ cat BrokenCovariance.java import java.util.Arrays; public class BrokenCovariance { public static void main(String[] args) { String[] ss = { "XYZ" }; Object[] os = ss; // OK System.out.println(Arrays.toString(os)); os[0] = 42; // Can be compiled, but causes runtime error System.out.println(Arrays.toString(os)); } } $ javac BrokenCovariance.java $ java BrokenCovariance [XYZ] Exception in thread "main" java.lang.ArrayStoreException: java.lang.Integer at BrokenCovariance.main(BrokenCovariance.java:10)
List
は use-site variance で covariant にしたら add
が消えたりして上手く動くんですけどね。import java.util.*; public class CovariantLists { public static void main(String[] args) { { // Invariant List<String> ss = new ArrayList<>(); ss.add("XYZ"); // OK List<Object> os = ss; // compile error } { // Covariant List<String> ss = new ArrayList<>(); List<? extends Object> os = ss; // OK os.add(42); // compile error } } }
(edited)? extends
の記法の奇抜さが良くなかった気も・・・。Covariance if A is a subtype of B then: Java: L<A> is a subtype of L<? extends B> (use-site) Scala: L[A] is a subtype of L[_ <: B] (use-site) L[A] is a subtype of L[+B] (declaration-site) Contravariance if A is a supertype of B then: Java: L<A> is a subtype of L<? super B> (use-site) Scala: L[A] is a subtype of L[_ >: B] (use-site) L[A] is a subtype of L[-B] (declaration-site)
[_ <: T]
確かに extends superは難しいけど、これはわかる気がしないでもない。_
がいろんなところで出てくるからそういう意味で受け取りやすいかもな。<
, >
はどっちの型が広いかですね。?
は唐突なんだよなList<? super Animal>
とか、 Java 書いてる人の半分は理解してないと思う。[ ]
なのが異端で目が慣れるまでちょっと怖いT
と T?
とかがあるけどOptional
は tagged union だから本来 T
と T?
には型の派生関係はないはずなんよね。Optional
にだけ特別にサブタイピングを認めてる。struct Foo<T> { case bar(T) case baz(T) }
T is Foo<T>
は成り立たない。() -> ()
is () -> throws ()
があります。throws
は認めざるを得ないなぁ。T
is Result<T, Swift.Error>
が、 Func<A, R>
の R
でだけ発生する() throws -> Error
throws E
と -> E
が区別されてるからthrows
は tagged と untagged のあいのこなのか。map { $0 as T }
/ some(T)
の優先順位を定義しなければいけなくなる (edited)import Foundation struct Test: Codable { let a = 5 } struct Test2: Codable { var a = 5 } let json = """ { "a": 10 } """.data(using: .utf8)! let test = try JSONDecoder().decode(Test.self, from: json) let test2 = try JSONDecoder().decode(Test2.self, from: json) print(test.a) print(test2.a)
struct S { let a: Int = 1 } S(a: 2)
<stdin>:2:6: error: argument passed to call that takes no arguments S(a: 2) ^
let
プロパティに初期値設定したらイニシャライザでも書き換えられないから JSON の値が反映されないのは仕方ないとして、 @swift-5.2.5
struct Foo { let a = 5 init(a: Int) { self.a = a } }
<stdin>:4:16: error: immutable value 'self.a' may only be initialized once self.a = a ^ <stdin>:2:9: note: initial value already provided in 'let' declaration let a = 5 ^ <stdin>:2:5: note: change 'let' to 'var' to make it mutable let a = 5 ^~~ var
import Foundation struct Foo: Codable { let a = 5 } print(String(data: try! JSONEncoder().encode(Foo()), encoding: .utf8)!)
struct A { init() { print("A.init") } } struct S { let a: A = A() init() { print("S.init") } } S()
A.init S.init
stderr:<stdin>:12:1: warning: result of 'S' initializer is unused S() ^~~
import Foundation struct Foo: Codable { let a = 5 } let json = """ {"a":2} """ let foo = try! JSONDecoder().decode(Foo.self, from: json.data(using: .utf8)!) print(String(data: try! JSONEncoder().encode(foo), encoding: .utf8)!)
(edited)let
だから Codable
の対象外とかもできないし。func function(@autoclosure @mustCalled completion: () -> Void) { completion() }
もし、関数内で別の関数のクロージャ中で呼ばれないといけないときは、その別の関数のクロージャがmustCalledならコンパイル通る func function1(@autoclosure @mustCalled completion: () -> Void) { function2 { completion() } } func function2(@autoclosure @mustCalled completion: () -> Void) { completion() }
的な(日本語怪しくてすいません)$ swiftc bug.swift bug.swift:7:1: error: the compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions print((value.0 == values.0) && (value.1 == values.1) && (value.2 == values.2) && (value.3 == values.3)) ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
$ swiftc bug.swift bug.swift:7:14: error: value of type 'Int' has no member '0' print((value.0 == values.0) && (value.1 == values.1) && (value.2 == values.2) && (value.3 == values.3)) ~~~~~ ^ bug.swift:7:26: error: value of type '[Int]' has no member '0' print((value.0 == values.0) && (value.1 == values.1) && (value.2 == values.2) && (value.3 == values.3)) ~~~~~~ ^ bug.swift:7:39: error: value of type 'Int' has no member '1' print((value.0 == values.0) && (value.1 == values.1) && (value.2 == values.2) && (value.3 == values.3)) ~~~~~ ^ bug.swift:7:51: error: value of type '[Int]' has no member '1' print((value.0 == values.0) && (value.1 == values.1) && (value.2 == values.2) && (value.3 == values.3)) ~~~~~~ ^ bug.swift:7:64: error: value of type 'Int' has no member '2' print((value.0 == values.0) && (value.1 == values.1) && (value.2 == values.2) && (value.3 == values.3)) ~~~~~ ^ bug.swift:7:76: error: value of type '[Int]' has no member '2' print((value.0 == values.0) && (value.1 == values.1) && (value.2 == values.2) && (value.3 == values.3)) ~~~~~~ ^ bug.swift:7:89: error: value of type 'Int' has no member '3' print((value.0 == values.0) && (value.1 == values.1) && (value.2 == values.2) && (value.3 == values.3)) ~~~~~ ^ bug.swift:7:101: error: value of type '[Int]' has no member '3' print((value.0 == values.0) && (value.1 == values.1) && (value.2 == values.2) && (value.3 == values.3)) ~~~~~~ ^
typealias TestCase = (input: (Bit, Bit, Bit, Bit, Bit, Bit), expected: Bit) let testBitResultBit: [TestCase] = //...
enum
じゃなかったんですよね。enum
の case
が camelCase じゃなく CamelCase だったってのが意外と理由かもしれませんねdeinit
は効かなくなるけど、やれんかなぁ(1, 2)
と (2, 1)
どう比較するんだ? (1) < (1, 2)
?(directionScore, distanceScore)
でソートするってのをやった。 sort
のクロージャを書かないといけなかったけど、これが使えたら書かなくて良さそう。--use-integrated-swift-driver
オプションが追加されています。"".data(using: .utf8) . <= ここで補完にでてくるのは`write(to:)`を選ぶと
"".data(using: .utf8) ?.write(to: savePath)
^ オプショナルの?をつけてくれるんだけどそうするとここで改行ができなくなるからコンパイルエラーになるな (edited)try expected .data(using: .utf8)? .write(to: loadPath)
?.write( ...
の方がベター?sorted ((Result, Result) -> Bool, (Element) -> Result)
ほしい(他の言語にはあった気がする、忘れた) こんなかんじで、比較対象を重複して書かなくていい // 面積でソート [CGRect()].sorted(<, { $0.width * $0.height })
(edited)extension Collection { func sorted<Result: Comparable>(_ comparing: (Result, Result) -> Bool, _ data: (Element) -> Result) -> [Element] { sorted { comparing(data($0), data($1)) } } } // 面積 [CGRect()].sorted(<, { $0.width * $0.height })
とりあえず考えてみたものの単純な例を実装してみた(Comparableだけど) (edited)P
から any P
に変更するという仕様変更ですcat as Hogeable
がアップキャストっぽく見えるけど、 実際には Hogeable
の existential への格納と言ったほうが近いのでcat as any Hogeable
って書いてあったらもうちょっととっかかりやすいんじゃないかなあ。any Hogeable
型のコンテナにオブジェクトを格納するときにメソッドを埋めないといけなくてそれをどこから持ってくるかという話なので。4 as Double // fine 4 as! Double // crashes
https://oleb.net/2020/as/ これ面白かった。foo .bar .baz
って書きますけど、 ?.
のときは↓ですか? foo? .bar? .baz
?.
が不可分じゃないのおもしろいね。 ?
は独立した後置演算子だったし。 (edited)foo?()
とかもあるからfoo?
が廃止されただけで。let f: (() -> ())? = { print("hello") } f? ()
(edited);
がない言語はそのあたりの厳密なルールの理解が難しい。objc_*
を呼んで好き勝手できる(し、ObjCのクラスを呼び出すライブラリもアプリに内蔵されてる)んですが、そういうのが許されているので、(個人的な解釈ですが) Apple的にはたぶんユーザーに書かせる分には良いんじゃないかと思うんですよねlet dict = [ "a": 2, "b": 3, "c": 5 if isFoo, ]
みたいなの。#if
したい みたいな話は見覚えがあるvar
にして組み立てることになる。let dict = { var d = [:] ... return d }()
こうするとvar性の延長は避けられるか。// Function Builder let dict: [String: Int] = .init { ("a", 2) ("b", 3) if isFoo { ("c", 5) } }
(edited)let dict: [String: Int] = .init { [ "a": 2, "b": 3, ] if isFoo { ["c": 5] } }
callAsFunction
と組み合わせれば↓みたいなこともできる? let dict = [ "a": 2, "b": 3, ] { if isFoo { ["c": 5] } }
callAsFunction
版の難点か。VStack { let foo = ... Text(foo) Text(foo) }
if let
はサポートされたはず。 (edited)if foo != nil { Text(foo!) }
if let foo = foo { Text(foo) }
=>
オペレータを自作すれば今も一応・・・!= nil
書く度に //FIXME
付けてるfunc =><T, R>(_ f: (T) -> R) -> R
VStack { ... => { (foo) in Text(foo) Text(foo) } }
=>
の ViewBuilder版が必要だwmap
だと ViewBuilder にならなくないですか?.some(foo).map { }
?extension Optional where Element: View { func map<T, U: View>(_ f: @ViewBuilder (T) -> U) }
extension Optional where Element: View { @ViewBuilder func map<T, U: View>(_ f: @ViewBuilder (T) -> U) }
@ViewBuilder
付ける文法あるんですか?@ViewBuilder var body: some View { ... }
rethrows
的な re@ViewBuilder
がほしくなるねwif let
が使えれば解決なわけで、 5.3 で問題ないはず?ViewBuilder
って 10 個以上要素並べられないの? https://developer.apple.com/documentation/swiftui/viewbuilderlet dict: [String: Int] = .init { [ "a": 2, "b": 3, ] if isFoo { ["c": 5] } }
buildBlock
って可変長引数対応してるのかな?Dictionary
は可変長でいけそう。 (edited)@_functionBuilder public struct DictionaryBuilder<Key: Hashable, Value> { public func buildBlock() -> [Key: Value] { [:] } public func buildBlock(_ c0: [Key: Value]) -> [Key: Value] { c0 } public func buildBlock(_ c0: [Key: Value], _ c1: [Key: Value]) -> [Key: Value] { c0.merging(c1) { _, new in new } } } extension Dictionary { public init(@DictionaryBuilder<Key, Value> _ builder: () -> [Key: Value]) { self = builder() } }
import XCTest @testable import DictionaryBuilder final class DictionaryBuilderTests: XCTestCase { func testExample() { let dictionary: [String: Int] = .init { [ "a": 2, "b": 3, ] [ "c": 5, "d": 7, "e": 11, ] } XCTAssertEqual(dictionary, [ "a": 2, "b": 3, "c": 5, "d": 7, "e": 11, ]) } }
init
はあやしいかと思って static func
にしてみたけど変わらず。buildBlock()
群を static func
にする必要がありますね。 (edited)buildBlock
を定義する」時だけの謎挙動を踏んでる気がする (edited)@_functionBuilder public struct DictionaryBuilder<Key: Hashable, Value> { public static func buildBlock(_ contents: [Key: Value]...) -> [Key: Value] { contents.reduce(into: [:]) { $0.merge($1) { _, new in new } } } }
let dictionary: [String: Int] = .init { [ "a": 2, "b": 3, ] if isFoo { ["c": 5] } }
buildIf
が Alternative Considered になってる一方、 buildDo
とかも載ってて、何が今使えるものなのかわからない・・・。async/await
を比較した場合、 suspendAsync(...)
に相当するのは new Promise(...)
で、 beginAsync
に相当するのは await
なしでのコールかな? https://gist.github.com/lattner/429b9070918248274f25b714dcfc7619beginAsync
だと中に複数の非同期関数のコールを書けるからちょっと違う? beginAsync
相当は↓みたいな感じ? (async () => { await foo(); await bar(); })(); // ここでは await なしでコール
(edited)suspend fun
はコールサイトでのマーク( try
とか await
的な)は特に必要ないのか。 Java の throws
相当に近いな(コールサイトのマークが必要ないけど suspend
/ throws
が静的にチェックされるという意味で)。suspend
を静的にチェックするなら throws
もチェックしてくれればよかったのに・・・。そこが一番辛いんだよなぁ。suspendAsync
と new Promise
に対応してそう。 https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines.experimental/suspend-coroutine.htmllaunch
はこっちか。 https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.htmlawait
のマークが無いな。await
あるほうが可読性高そうだけど・・・。ぱっと見でどこで await
になってるかわからないのって結構怖そう・・・。async func foo() { (await?) f1() (await?) f2() (await?) f3() }
render()
があったとして、 await
の直後には必ず render()
を入れたいとかがあるかなあ? でもそれは状態の変化の方で呼び出しておけばいいしなあ。func foo() async { guard let first = self.values.first else { return } ... bar() if self.values.count == 1 { ... } else { ... } }
みたいなのがあったときに、 bar
が async
だと values
が空でないことが保証できないとか。bar
が async
だったとして、 ほかの非同期タスクの影響でも values が変更されうるようなシナリオって、 そもそも認知負荷が高すぎて考慮しきれないから、避けちゃう。async
じゃなかったときは心配しないでそういうコードを書くことができる」async
に集約されれば async
でないことが同期であることの保証になるのか。async
でも await
が可視なら、 await
から await
までの間は同様の保証が働くということでした。await
が不可視なのは怖いかなぁと。try
がなくてジャンプが不可視なのもだけど、 await
はより怖い感覚があるなぁ。any
導入されたら some Animal
と any Animal
のどっちも "Protocol Type" に見えそうだし(もしくはどっちも見えなさそうだし)、やっぱり Existential Type の方がいいか。 (edited)throw
したくて禁断の技を使ってしまった・・・。 extension Array: Error where Element: Error {}
Set
かもだけど、 Hashable
にしないといけないので。let aToZ: ClosedRange<Unicode.Scalar> = "A" ... "Z" for c in aToZ { print(c) }
↓みたいな extension
書いた。これって標準で付いてたらダメ? extension Unicode.Scalar: Strideable { public func distance(to other: Unicode.Scalar) -> Int { Int(other.value) - Int(self.value) } public func advanced(by n: Int) -> Unicode.Scalar { Unicode.Scalar(UInt32(Int(self.value) + n))! } }
ExpressibleByStringLiteral
じゃなくて ExpressibleByUnicodeScalarLiteral
が付いてるみたい。 https://developer.apple.com/documentation/swift/unicode/scalarStrideable
がついてないって話かStrideable
が欲しい。Unicode.Scalar.init
で nil
になるのかな?
Strideable
であってもおかしくない気が。("a" ... "z").randomElement()!
とかやりたいことは結構あると思うんだけどなぁ。OrderedCharacter
とかあればいいのかな・・・。FunctionBuilder
自体は汎用にしておいて、 Buildable
に適合した型だけその結果を使って build
できるようにしたいってことですか?Buildable
以外にも FunctionBuilder
を使えるようにしたいと。_Builder
があるから任意の型を生成できるのか。 (edited)Pair<Pair<Pair<C0, C1>, C2>, C3>
じゃなくて Pair<Pair<C0, C1>, Pair<C2, C3>>
なのには意図があります?struct Foo { func get() -> Int { 42 } var bar: Int { get() } }
<stdin>:4:12: error: expected '{' to start getter definition get() ^
struct Foo { func get2() -> Int { 42 } var bar: Int { get2() } }
なるほど。struct V<K> { func f(_ k: K) {} } struct S { var name: String = "" } V<KeyPath<S, String>>().f(\.name) // OK V<PartialKeyPath<S>>().f(\S.name) // OK V<PartialKeyPath<S>>().f(\.name) // NG
(edited)<stdin>:9:24: error: type of expression is ambiguous without more context V<PartialKeyPath<S>>().f(\.name) // NG ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~
(edited)V<PartialKeyPath<S>>().f(\S.name)
ならいけるっぽい?Key = PartialKeyPath<Props>
ってやったらKeyPath<Props, String>
だと、 Stringじゃないプロパティが収納できないから駄目。KeyPath<Props, T>
mutating func notEmpty(for key: Key, value: String) -> Bool { if !value.isEmpty { return true } addFailure(for: key, .empty) return false }
struct Validator<T> { typealias Key = PartialKeyPath<T> mutating func notEmpty<X>(for key: KeyPath<T, X> , _ value: String) -> Bool { ... } var validator = Validator<Props>() _ = validator.notEmpty(for: \.name, props.name)
<X>
ださい・・・KeyPath<T, X>
から PartialKeyPath<T>
への変換は暗黙変換だからextension Validator where Key == PartialKeyPath<T> { // ここに生やす }
でいけそうやな<T>
書けなくない?T
にしばる意味がないValidator<Key: Hashable>
だったのだ。\.name
って書けなくなる。 (edited) if validator.failures[\.password]?.isEmpty, validator.failures[\.passwordConfirm]?.isEmpty { }
PartialKeyPath
が見えてるから・・・ 辞書直接さらさずにこれも <X> つけたアクセサ作ればごまかせるけどwextension Validator { subscript<X>(failure: KeyPath<T, X>) -> }
ざっくりこんな感じかvalidator[\.name]
が収集されたエラーであることが自明でないからAPIとして微妙だな〜func failure<X>(key: KeyPath<X, T>) -> [Failure]
かなあ if validator.failures(for: \.password).isEmpty, validator.failures(for: \.passwordConfirm).isEmpty { }
subscript(dynamicMember:)
とかは?validator.name
で nameのエラーが取れるようになるのかなvalidator.failures.name
とかはできそうですねvalidator.name.notEmpty(props.name)
var validator = Validator(target: props) if validator.notEmpty(for: \.password) { _ = validator.minLength( for: \.password, length: setting.passwordMinLength ) } _ = validator.notEmpty(for: \.passwordConfirm) if validator.failures(for: \.password).isEmpty, validator.failures(for: \.passwordConfirm).isEmpty { _ = validator.checkConfirm(for: \.passwordConfirm, original: \.password) }
async/await
入ったら標準ライブラリに Future
も入るのかな? Proposal で触れられてるけど。そしたら、標準ライブラリと Combine と SwiftNIO で Future
が乱立・・・。throw
に対する Result
、 async
に対する Future
とすると、標準ライブラリでは Future
は Failure
を持たないという設計も考えられる。Future<Value, Failure: Error>
にしてしまうと、今後第三のモナドに対する throws/try
, async/await
相当の構文が導入されたときにモメそう。 (edited)async throws
な関数をラップすることを考えると Future
に Failure
がないと厳しいよなぁ・・・。let a = Future { try await foo() } let b = Future { try await bar() } let c = try await a.get() + b.get()
func next() async
で扱えそうasync/await
で generator 作る例を Joe Groff が昔書いてたはず。let a = Future { await Result { try foo() } } let b = Future { await Result { try bar() } } let c = try await a.get().get() + b.get().get()
throws-rethrowsと同じように、async-reasyncがあれば、↑のように書けるはず。let a = Future { await Result { try await foo() } } let b = Future { await Result { try await bar() } } let c = try await a.get().get() + b.get().get()
って まったく同じこと書いてたw (edited)foo
や bar
に await
がいるはず。reasync
されて Future
の方でさらに await
が必要。Future<Result<T, E>>
に対して、 func get() async throws E -> T
な extension
がほしい。get().get()
が get()
でよくなる。 (edited)async/await
導入されるなら、 Future
が同時に導入されないのはきついので、 Parametrized extension はそれまでに入らなさそうな気がするし、 Failure
入れられちゃいそうな気がする・・・。FutureResult
型が導入されればいいのかな。Future
が乱立するか、 Combine.Future
に対する extension
ができるかかな。NIO.EventLoopFuture
は EventLoop の制御が入ってるんでちょっと別ですねCombine.Future
はどうなんだろう。Failure == Never
のときにはasyncだけの振る舞いをもってれば、十分じゃないです?import Combine extension Future where Failure == Error { init(execute: () async throws -> Value) { ... } }
(edited)@escaping
がいりそうextension Future where Failure == Never { init(execute: () async -> Value) { ... } }
現実的にはこれと↑の2つでget() async throws -> Output
か。Never
のときは get() async -> Output
Result
のが。protocol Single: Publisher { ... } extension Future: Single { ... } extension Publishers.Map: Single where Upstream: Single { ... }
async
で取り出せる get
がないと辛いし、やっぱ専用の標準 Future
ほしそう。Future
なしで async/await
入って、オレオレ Future
乱立がありそうだな・・・。Future
が Failure
を持たなくても、 extension<T> Future where Value == Result<T> { init(execute: @escaping () async throws -> T) { ... } }
があれば良い?Result
じゃなくて Optional
だったけど。a: Future<String, Error>
と b: Future<Result<String>, Never
は (edited)a.flatMap { Future.failure(err) }.map { print("出ない") }
b.map { Result.failure(err) }.map { print("出る") }
このへんが違うから。 (edited)do { let a = try await foo() } catch { ... } do { let b: Result<String, Error> = await bar() } catch { ... }
↑この2つの違いに相当する (edited)Future<Result<T, E>>
を Future<T ,E>
の気分で使いたいと考えたら、基本的にそういう挙動をするようにすればいいんじゃないのかなぁ。foo.map { a: Result<T, E> in ... } foo.result.map { a: T in ... }
こういう感じの書き方ができるとlet b: Result<String, Error> = await Result { try await bar() }
foo.map(who: .future) { a: Result<T, E> in ... } foo.map(who: .result) { a: T in ... }
async
と throws
をちゃんと区別してくれたら、 Future
は Future<T, E>
でいい気もします・・・。Future
や Result
は主役ではなくて、 async/await
や throws/try
では解決できないコーナーケースをハンドリングするためのヘルパーなので。reasync
がついてる。init(catching body: () throws -> Success)
↑の Result.init
が↓に変わる。 init(catching body: () async throws -> Success) reasync
init
は async
書けると思ってるんだけどどうなんだろう?Promise
を基本として async/await
を考えた場合、Promise
を返せないから async
にできないけど、Promise
や Future
に基づかずに async/await
を導入する場合、async
になれる。async
付いてるのとは挙動は違うけど(待たずに返るので)。 (edited)async
コンストラクタができる言語ってあるのかな?init(bigEndian:)
と .bigEndian
って挙動同じじゃない? https://developer.apple.com/documentation/swift/uint64/1539824-init
https://developer.apple.com/documentation/swift/uint64/1538836-bigendianlet a: UInt64 = 1 print(a.bigEndian) print(UInt64(bigEndian: a))
72057594037927936 72057594037927936
.endianSwapped
などにはしないほうが良いです.bigEndian
と .littleEndian
の話じゃない? (edited)let a: UInt64 = 1 print(a.bigEndian) // aをLEだと思ってそのBE表現を得ているコード print(UInt64(bigEndian: a)) // aをBEだと思ってそのLE表現を得ているコード // ↑この2つが並んでるのは `a` の解釈が矛盾してるのでおかしい
.littleEndian
は何もしない関数になるけど.bigEndian
が何もしない関数で、 .littleEngian
がスワップする関数に切り替わりますね。.endianSwapped
は .bigEndian
と同じじゃなくて、常にひっくり返すって意味やんね?.bigEndian
と .littleEndian
の二つは必要。init(bigEndian:)
と init(littleEndian:)
はそれぞれ .bigEndian
, .littleEndian
と同じ挙動だから、コードの意図の表明以上の意味はないよね?という疑問。extension UInt64 { var bigEndian: UInt64 { UInt64(bigEndian: self) } }
でも構わないわけだ。 @inlinable public var bigEndian: Self { #if _endian(big) return self #else return byteSwapped #endif }
_endian
#available(*, unavailable)
があるのに。let expectation = XCTestExpectation() var cancellables: [AnyCancellable] = [] observableObject.objectWillChange.sink { _ in expectation.fulfill() }.store(in: &cancellables) wait(for: [expectation], timeout: 3.0)
みたいなコード書いてたけど、最適化を有効にしたら(おそらく)スコープの途中で cancellables
が片付けられてしまって observableObject
が発火しなくなってしまった。cancel
を呼び出すことで解放されなくなりました。cancel
を呼びやすいように元々 store
をなくして戻り値で受けてたんですが、 cancel
を消しても(未使用警告は出ますが)購読解除はされませんでした。store
に戻した上でcancellables.forEach { $0.cancel() }
store
で最適化されるなら戻り値で受けた場合も最適化され得るものとして、末尾 cancel
するのが良さそうに思います。store
のときの挙動が最適化のバグの可能性もあると思います。withExtendedLifetime
を使うのが正しそうvar cancellables: [AnyCancellable] = [] observableObject.objectWillChange.sink { _ in expectation.fulfill() }.store(in: &cancellables)
このinoutに渡した例だと何もでない、ですよね?wait(for: [expectation
は要するにPromiseだからAsync/Await的な書き方にできそうだな。func XCTAsync<Context>(_ context: Context, timeout: TimeInterval = 3.0, _ body: (inout Context, () -> Void) -> Void) { var context = context let expectation = XCTestExpectation() withExtendedLifetime(context) { body(&context, expectation.fulfill) wait(for: [expectation], timeout: timeout) } }
(edited)> GET /builds/swift-5.2.1-release/xcode/swift-5.2.1-RELEASE/swift-5.2.1-RELEASE-osx-symbols.pkg HTTP/1.1 > Host: swift.org > User-Agent: curl/7.64.1 > Accept: */* > < HTTP/1.1 200 OK < Connection: close < Proxy-Connection: close < Via: HTTP/1.1 localhost.localdomain (IBM-PROXY-WTE) < Date: Thu, 17 Sep 2020 05:51:35 GMT < Server: Apache < X-Frame-Options: SAMEORIGIN < Strict-Transport-Security: max-age=15768000;includeSubDomains < Last-Modified: Mon, 30 Mar 2020 11:10:20 GMT < Accept-Ranges: bytes < Content-Length: 3305608957 < Content-Type: application/vnd.apple.installer+xml
# whois.ripe.net inetnum: 169.47.73.0 - 169.47.73.31 netname: NETBLK-SOFTLAYER-RIPE-CUST-MS43377-RIPE descr: IBM - Open Technology and Cloud Performance
.png
を付けたら画像が返るようになっていて、それをOGPのURLにしたHTMLを返している。pod try
的なパッケージをサクッと試せる環境がオンラインで作れると嬉しそうですねswift run
すると30個くらいのファイルがコンパイルされたりするのがよくわからない。Content
protocol ですね、あれは、 Codable
+ ContentType
です。application/json
とか。extension Optional: Content where Wrapped == その型 { ... }
かな?encode
と init(from decoder)
は手書きになるはずsingleValueContainer
で出し入れすればいいけど (edited)extension Dictionary: Content, ResponseEncodable, RequestDecodable where Key == String, Value: Content { public static var defaultContentType: HTTPMediaType { return .json } }
extension Content { public static var defaultContentType: HTTPMediaType { return .json }
↑これ自動で入らないのかな・・・protocol P { func p() -> Int } struct S<T> {} extension P { func p() -> Int { 1 } } extension S : P where T == Int {}
<script> const persons = [ { name: 'Alice' }, { name: 'Bob'}, { name: 'Carol' } ]; </script> <main> {#each persons as p}
<div>{p.name}</div>
{/each}
</main>
<style>
</style>
JSValueConstructible
という名前にしているんですが、JS value to Swift value なのかSwift value to JS valueなのかわかりにくくてリネームしたい。ExpressibleByXXX
っていう案も出たんですが、標準ライブラリ内だとリテラル絡みでしか使われていないのでどうなのかな、と。 (edited)CustomStringConvertible
とかを考えるとConvertibleは Self -> Valueなのかなーと思って今の使い方になってますねBridgable
も ObjectiveCBridgeable
を見るとSelf -> Value と Value -> Selfのペアになっていて微妙にマッチしないextension Bool: SwiftTypeTransformable
ってみたときに違和感がある気がするextension Bool: JSValueTransformable
こっちの方がわかる。とすると元の名前でも良さそうだけど。extension Bool: JSValueConvertible
extension Bool: JSValueBridgeable
これは明らかにto JSValueに見える。
SwiftConvertibleはSwift Type側につけるともう意味不明。だから却下でいいかな。extension Bool: ConstructibleFromJSValue
わかりやすい。自然。ConstructibleFromJSValue
かなぁextension Bool: ExpressibleByJSValue
なんか使い方が違うっぽく見えるんですよね。リテラルを変換するやつに引きずられて。XXXConvertible
: Self -> Target
XXXBrigable
: Self -> Target
& Target -> Self
ExpressibleByXXX
: Literal -> Self
extension Account: ConstructibleFromJSValue
みたいな自分で作ったそこそこの規模のStructに実装するとかもある? (edited)extension Bool: InitializableByJSValue {}
Self
を返す static func
は init
と等価だと思いますし、 init
の方が Swifty な気もします。init(from:)
を持つ Decodable
?XxxableFromJSValue
は良いように思います。 Xxx
に何を入れるか。ConvertibleFromJSValue
でもいいのでは?From
が入ればニュアンス変わるし。JSValueConvertible
と ConvertibleFromJSValue
があっても混乱しなさそう(する?)。ConvertibleToJSValue
と ConvertibleFromJSValue
にすると対応が取れてきれいな気がするけど、悩ましいなDecodable
はインターフェース的には近いけど意味的にはもう少し小さい粒度の値の変換だからdecodeは微妙にマッチしないかなぁtrait From<T>
とtrait Into<T>
が用意されてて羨ましいな (edited)From
と Into
のドキュメントみてみたんですがFrom
trait in crate std
.ConvertibleFromJSValue
かなConvertibleFromJS
ConvertibleToJS
かなあ〜Decodable
は意味は違うけど Xxxable
という形式の名前にするのがやはり良さそうという意味でした。で、今考えている init(from:)
が( decode ではなく)何かと言うとやっぱり convert だよなと。そうすると ConvertibleFromJSValue
かなと。 (edited)XxxConvertible
は to なので、 from であることも明示するには ConvertibleFromXxx
かなと。 (edited)ConvertibleToJSValue
と ConvertibleFromJSValue
がわかりやすそうに思います。Custom
がまず謎だし。Xxxable
前置詞 名詞」自体は ExpressibleByStringLiteral
とかでもあるし、いい気がします。_ObjectiveCBridgeable
は両方向合わせたやつなんだな func _bridgeToObjectiveC() -> _ObjectiveCType
と
static func _forceBridgeFromObjectiveC(
_ source: _ObjectiveCType,
result: inout Self?
)
trait From
っぽいJSValue -> Self
は ConstructibleFromJSValue
or ConvertibleFromJSValue
のどちらかかなと思ってるですが、次の問題として、この場合にSelf -> JSValue
をstdlibのXxxConvertibleに寄せるか FromJSValueと対応をとって ConvertibleToJSValue
にするか。 (edited)CustomPlaygroundDisplayConvertible
LosslessStringConvertible
CustomDebugStringConvertible
Lossless
が付くことからもpublic protocol LosslessStringConvertible: CustomStringConvertible {
init?(_ description: String)
}
RawRepresentable where RawValue == String
っぽいGet<FieldType>()
AndroidJavaObject
が書けるよ。AndroidJavaObject
を指定するのは駄目java.lang.Object
に対応してるってこと。int
とか boolean
は Object
ではないので。Representer
, Constructor
があっての*Representable
,*Constructible
CodingUserInfoKey.init?(rawValue: String)
なんですけどCodingUserInfoKey.init(rawValue: String)
のほうが望ましくないですか?init?
じゃなくて init
であっても、 RawRepresentable
にはconformできます。init?
で conform できなかった事による名残じゃないかと予想してるんだけど--privileged
を付与しないといけないとかあって危険そうでやめちゃったんですが、特に問題ない感じですか? (edited)/var/run/docker.sock
触れる = それがあるなら --privileged
な docker コンテナも作れるのでむしろ DinD のほうがちょっと安全…?Dockerfile
内で外向けアプリを実行する前にUSER
でアカウントを変更した方が良いです。throws
はより軽量だと思いますし、また、例外を throw
するのは Either
/ Result
に対する do
記法だという立場からすると、 treat
が例外を throw
するのと結果を return
するのは同じことだとも言えます。can_treat
を使う方式だと、チェック忘れを静的に検査できず treat
が実行時エラーを起こす可能性を排除できません。Iterator
が next
で throw
して分岐するか、 hasNext
でチェックするまたは next
が Optional
を返すかという話が載っていて後者が望ましいとあるんですけど、 Optional
を Result
の一種だと考えると、 throw
するか Optional
を return
するのは同じことだとも言えます。 (edited)treat
の戻り値の型が Void
だったときに、 throws
なら分岐を強制できるけど、 Bool
か二値 enum
だと警告止まりというのはどうでしょう?var a: ArraySlice<Int> = []
for i in 0 ..< 100 {
a.append(i)
print(a.capacity)
}
1
3
3
7
7
7
7
17
17
17
17
17
17
17
17
17
17
35
35
35
35
35
35
35
35
35
35
35
35
35
35
35
35
35
35
71
71
71
71
71
71
71
71
71
71
71
71
71
71
71
71
71
71
71
71
71
71
71
71
71
71
71
71
71
71
71
71
71
71
71
71
143
143
143
143
143
143
143
143
143
143
143
143
143
143
143
143
143
143
143
143
143
143
143
143
143
143
143
143
143
var a: ArraySlice<Int> = []
for i in 0 ..< 100 {
a.append(i)
print(a.capacity)
_ = a.popFirst()
}
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
capacity
を超えそうのなったときに前に詰めてる?var a: ArraySlice<Int> = []
a.reserveCapacity(10)
for i in 0 ..< 20 {
a.append(i)
print(a.capacity)
_ = a.popFirst()
}
11
10
9
8
7
6
5
4
3
2
1
1
1
1
1
1
1
1
1
1
capacity
からバッファのサイズはわからないな。Array
でもそうかと。 < 既存部分 (edited)append
と popFirst
を繰り返した場合、 endIndex
が capacity
を超えたときにどうなると思う?前に詰める? N 倍のバッファを確保して index
に基づいた場所に格納される?capacity
からわかるかと思ったけど、この capacity
の挙動だと実装みないとわからないかな・・・。ArraySlice
をキューとして使っていたとすると大きなオフセットになることはありえそう。a ... b
で b == a - 1
のときに、実行時エラーじゃなくて空の ClosedRange
になってほしい・・・。a ..< b
だと空の Range
作れるんですよね。print(Array(0 ..< 0))
print(Array(1 ... 0))
Fatal error: Can't form Range with upperBound < lowerBound: file Swift/ClosedRange.swift, line 335
Current stack trace:
0 libswiftCore.so 0x00007f0b11e99d50 swift_reportError + 50
1 libswiftCore.so 0x00007f0b11f0d0c0 _swift_stdlib_reportFatalErrorInFile + 115
2 libswiftCore.so 0x00007f0b11bf27de <unavailable> + 1398750
3 libswiftCore.so 0x00007f0b11bf2337 <unavailable> + 1397559
4 libswiftCore.so 0x00007f0b11bf2013 <unavailable> + 1396755
5 libswiftCore.so 0x00007f0b11bf1a80 _assertionFailure(_:_:file:line:flags:) + 511
7 swift 0x00000000005b4501 <unavailable> + 1787137
8 swift 0x00000000005a1d04 <unavailable> + 1711364
9 swift 0x0000000000587e88 <unavailable> + 1605256
10 swift 0x000000000057b322 <unavailable> + 1553186
11 swift 0x00000000005780ef <unavailable> + 1540335
12 swift 0x0000000000501c2c <unavailable> + 1055788
13 libc.so.6 0x00007f0b13f68740 __libc_start_main + 240
14 swift 0x00000000005017a9 <unavailable> + 1054633
Stack dump:
0. Program arguments: /usr/bin/swift -frontend -interpret - -disable-objc-interop -I /Libraries/.build/x86_64-unknown-linux-gnu/debug -I /Libraries/.build/checkouts/SwiftBacktrace/Sources/CSwiftBacktrace/include -I /Libraries/.build/checkouts/SwiftBacktrace/Sources/Clibunwind/include -I /Libraries/.build/checkouts/swift-nio/Sources/CNIOHTTPParser/include -I /Libraries/.build/checkouts/swift-nio/Sources/CNIOSHA1/include -I /Libraries/.build/checkouts/swift-nio/Sources/CNIOAtomics/include -I /Libraries/.build/checkouts/swift-nio/Sources/CNIOWindows/include -I /Libraries/.build/checkouts/swift-nio/Sources/CNIODarwin/include -I
print(Array(0 ... 0))
/// Because a closed range cannot represent an empty range, this property is
/// always `false`.
@inlinable
public var isEmpty: Bool {
return false
}
なんで、無理ですねr
が 0
だとクラッシュしてしまいます。
func npr(_ n: Int, _ r: Int) -> Int {
(n - r + 1 ... n).reduce(into: 1) { $0 *= $1 }
}
..<
の右の n + 1
が不格好なんですよね・・・。
func npr(_ n: Int, _ r: Int) -> Int {
(n - r + 1 ..< n + 1).reduce(into: 1) { $0 *= $1 }
}
...
使うと実行時エラーを踏みまくるので、 ..<
ばかり使うようにしています。lowerBound == upperBound + 1
の場合だけ空だと、実用上はちょうど良いように思います。ただ、表現として微妙なのはわかります。Strideable
じゃない場合との整合性を考えると微妙ですね・・・。 (edited)!=
を≠にするのはあるけど否定のビックリをみやすくしてくれるのはなかった気がする。error: cannot find operator '!!!' In scope
カスタムオペレーターの弊害とはいえ、悲しい。≠
を表したくて、 縦棒っぽい記号が欲しかっただけと思ってた !=
+=
と +
の関係を考えると、 !=
から !
が取り出せる¬
だextension Bool { var isFalse: Bool { !self } }
!
はないっぽい?protocol
作るときに、型ではなく制約としての利用を前提とするなら、基本的に FooProtocol
の命名の方が良い気がするんですがどうでしょう?
protocol Foo {}
struct Bar<???: Foo> {} // ??? に何と付ける?
protocol FooProtocol {}
struct Bar<Foo: FooProtocol> {} // 型パラメータ名を Foo にすれば良い
(edited)Numeric
みたいな汎用的なプロトコルの場合は struct Bar<Length: Numeric>
みたいに命名できるけど、もっと用途の幅が狭いものの場合。 (edited)var value: Value
とか。VideoSource
というプロトコルを作ってたんだけど、
struct PlayerView<VideoSource: VideoSourceProtocol>: View { ... }
にしたくなった。VideoSource_
(edited)VideoSourceType
Type
suffix 結構使うな。 (edited)V: VideoSource
で良い気もするんだけど主流じゃなさそうだ。associatedtype
や型パラメータって何度も繰り返し使われるから、 associatedtype Iterator: IteratorProtocol
的にプロトコル名を長くした方がよくないですか?associatedtype
はそうかも。 (edited)IteratorProtocol
があるからもう天下り的にいいかなと・・・。I
prefix は賢い気がする。typename
キーワードでそういう事をする場面があってstruct Bar<Foo: MyModule.Foo> {}
struct Bar<Foo: MyModule.Foo> {}
/usr/lib/swift/libswift_Concurrency.dylib
が絶対パスでリンクされて、SIP有効だとDYLD_LIBRARY_PATH
も渡せないから、
DYLD_LIBRARY_PATH=… swift run
はダメだけど、DYLD_LIBRARY_PATH=… .build/x86_64-apple-macosx/debug/ConcurrencyExample
として直接実行するのはイケた。SIP関係ないのかな?DYLD_LIBRARY_PATH
を渡さないようにしてるのかな?
何か条件があるぽい。
$ env DYLD_LIBRARY_PATH=hoge /usr/bin/python3 -c "import os;print('DYLD_LIBRARY_PATH' in os.environ)"
False
$ env DYLD_LIBRARY_PATH=hoge /usr/local/bin/python3 -c "import os;print('DYLD_LIBRARY_PATH' in os.environ)"
True
(edited)PATH
に$HOME/Library/Developer/Toolchains
以下にインストールしたSwiftツールチェインの/usr/bin
を通してDYLD_LIBRARY_PATH=… swift run
してもダメなんですよね。なので「インストーラで入れた」が条件なのかな?と。$ xattr -rv ~/Library/Developer/Toolchains/|grep -v -E "com.apple.(cs.Code(Directory|Requirements|Requirements-1|Signature)|metadata:com_apple_backup_excludeItem|FinderInfo)"|wc -l
0
(edited).build/x86_64-apple-macosx/debug/ConcurrencyExample
をDeveloper ID Applicationで署名してみましたが、DYLD_LIBRARY_PATH
は通りました。
$ swiftnightly build
[1/1] Planning build
[3/3] Linking ConcurrencyExample
* Build Completed!
$ codesign -s "Developer ID Application: Norio Nomura (PK9GMQ772L)" .build/debug/ConcurrencyExample
$ codesign -vv .build/debug/ConcurrencyExample
.build/debug/ConcurrencyExample: valid on disk
.build/debug/ConcurrencyExample: satisfies its Designated Requirement
$ DYLD_LIBRARY_PATH=~/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2021-01-09-a.xctoolchain/usr/lib/swift/macosx .build/debug/ConcurrencyExample
task started
{
"uuid": "32cf6d86-bb2d-4089-8262-9ecfcf9d7418"
}
end of main
mealHandle
と ()
の間に .get
が抜けてる?
func eat(mealHandle: Task.Handle<Meal, Error>) {
let meal = try await mealHandle()
meal.eat() // yum
}
https://github.com/DougGregor/swift-evolution/blob/structured-concurrency/proposals/nnnn-structured-concurrency.mdlet a: [String?:String] = ["Foo":"Bar"]
let b = a as [AnyHashable:String]
print(b["Foo"] == "Bar")
print(b["Foo" as String?] == "Bar")
"foo"
と .some("foo")
がAnyHashable
としてみると違う値なのか?print(AnyHashable("foo") == AnyHashable(Optional<String>("foo")))
(edited)print(AnyHashable("foo") == AnyHashable(Optional<String>("foo")))
let str = "foo"
let ostr: String? = str
let hstr: AnyHashable = ostr as AnyHashable
print(hstr == AnyHashable(str))
print(hstr == AnyHashable(ostr))
(edited)let str = "foo"
let ostr: String? = str
let tempAny: Any = ostr
let hstr: AnyHashable = tempAny as! AnyHashable
print(hstr == AnyHashable(str))
print(hstr == AnyHashable(ostr))
false
true
stderr:<stdin>:3:20: warning: expression implicitly coerced from 'String?' to 'Any'
let tempAny: Any = ostr
^~~~
<stdin>:3:20: note: provide a default value to avoid this warning
let tempAny: Any = ostr
^~~~
?? <#default value#>
<stdin>:3:20: note: force-unwrap the value to avoid this warning
let tempAny: Any = ostr
^~~~
!
<stdin>:3:20: note: explicitly cast to 'Any' with 'as Any' to silence this warning
let tempAny: Any = ostr
^~~~
as Any
true
false
stderr:<stdin>:3:20: warning: expression implicitly coerced from 'String?' to 'Any'
let tempAny: Any = ostr
^~~~
<stdin>:3:20: note: provide a default value to avoid this warning
let tempAny: Any = ostr
^~~~
?? <#default value#>
<stdin>:3:20: note: force-unwrap the value to avoid this warning
let tempAny: Any = ostr
^~~~
!
<stdin>:3:20: note: explicitly cast to 'Any' with 'as Any' to silence this warning
let tempAny: Any = ostr
^~~~
as Any
T??
における .some(.none)
と .none
の区別とかもあるしなあfunc toAny<X>(_ x: X) -> Any { x as Any }
let s = "foo"
let os = Optional(s)
let a1 = toAny(s) as! AnyHashable
let a2 = toAny(os) as! AnyHashable
print(a1 == a2)
(edited)func toAny<X>(_ x: X) -> Any { x as Any }
let s = "foo"
let os = Optional(s)
let a1 = toAny(s) as! AnyHashable
let a2 = toAny(os) as! AnyHashable
print(a1.hashValue, a2.hashValue, a1 == a2)
(edited)let a = Optional.some(1)
let b = 1
print(a.hashValue)
print(b.hashValue)
5998755465171700993
3246083455761462081
4555010388509318116 7560537639487603476 false
let s = "s"
let os=Optional(s)
print(type(of: s), type(of: os), type(of: s as Any), type(of: os as Any))
(edited)let s = "s"
let os = Optional(s)
print(type(of: s), type(of: os), type(of: s as AnyHashable), type(of: os as AnyHashable))
(edited)func toAH<X>(_ x: X) -> AnyHashable { x as! AnyHashable }
let s = "foo"
let os = Optional(s)
print(type(of: toAH(s)), type(of: toAH(os)), type(of: toAH(s) as Any), type(of: toAH(os) as Any))
(edited)print("s" as AnyHashable as? String)
Optional("s")
stderr:<stdin>:1:7: warning: expression implicitly coerced from 'String?' to 'Any'
print("s" as AnyHashable as? String)
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<stdin>:1:26: note: provide a default value to avoid this warning
print("s" as AnyHashable as? String)
~~~~~~~~~~~~~~~~~~~^~~~~~~~~~
?? <#default value#>
<stdin>:1:26: note: force-unwrap the value to avoid this warning
print("s" as AnyHashable as? String)
~~~~~~~~~~~~~~~~~~~^~~~~~~~~~
!
<stdin>:1:26: note: explicitly cast to 'Any' with 'as Any' to silence this warning
print("s" as AnyHashable as? String)
~~~~~~~~~~~~~~~~~~~^~~~~~~~~~
as Any
AnyHashable AnyHashable AnyHashable AnyHashable
func toAH<X>(_ x: X) -> AnyHashable { x as! AnyHashable }
let s = "foo"
let os = Optional(s)
let a1 = toAH(s)
let a2 = toAH(os)
print(a1 == a2, a1.hashValue, a2.hashValue)
false 7411312793998186712 -1838519281677881482
true -7218179261913021143 -7218179261913021143
String?
を動的に AnyHashable
にするときに String?
を包んだものとしてキャストしていてString
をキャストしたものになるfunc toAH<X>(_ x: X) -> AnyHashable { x as! AnyHashable }
let s = "foo"
let os = Optional(s)
let a1 = toAH(s)
let a2 = toAH(os)
let d1: [AnyHashable: Int] = [s: 1]
let d2: [AnyHashable: Int] = [a1: 1]
print(d1[s] ?? 99, d1[os] ?? 99, d1[a1] ?? 99, d1[a2] ?? 99)
print(d2[s] ?? 99, d2[os] ?? 99, d2[a1] ?? 99, d2[a2] ?? 99)
(edited)d1[os]
のときにやってるのは静的な方か?T? as AnyHashable
のとき、アンラップしなかった方のAH
が生成されるんだねswift-5.0.3-RELEASE
は起動できるけど、それ以降の5.1.5, 5.2.5, 5.3.3リリースおよび5.4, mainスナップショット全部起動出来ない。switch rpcMessageType {
case .playAnimation:
<#code#>
case .completeTask:
<#code#>
case .syncSettings:
<#code#>
case .setInfected:
<#code#>
...
今はこんな感じに生成されるけど、<#code#>
のところbreakがいい、気がする。code
に行っちゃうのが不便なときはあるinfix operator ..<?: RangeFormationPrecedence
func ..<?<T>(lhs: T, rhs: T) -> Range<T>? where T: Comparable {
guard lhs <= rhs else { return nil }
return lhs ..< rhs
}
infix operator ...?: RangeFormationPrecedence
func ...?<T>(lhs: T, rhs: T) -> ClosedRange<T>? where T: Comparable {
guard lhs <= rhs else { return nil }
return lhs ... rhs
}
Scheduling for next Monday.
されとる (edited)implicit
が導入されると黒魔術が使えて嬉しいsuffix(while:)
ってなんでないんですっけ?普通にほしい気が。let a: Int
if Bool.random() {
a = 2
} else {
a = 3
}
print(a)
let a: Int?
if Bool.random() {
a = 2
} else {
a = nil
}
print(a)
nil
stderr:<stdin>:7:7: warning: expression implicitly coerced from 'Int?' to 'Any'
print(a)
^
<stdin>:7:7: note: provide a default value to avoid this warning
print(a)
^
?? <#default value#>
<stdin>:7:7: note: force-unwrap the value to avoid this warning
print(a)
^
!
<stdin>:7:7: note: explicitly cast to 'Any' with 'as Any' to silence this warning
print(a)
^
as Any
if let
でシャドーイングされてた・・・。すみません。subscript(index: Int)
が生えててもいい気も。さすがに subscript
は勘違いしそうかもしれないけど。first
が Sequence
に生えてても良さそう?first(where:)
は一応最悪O(N)では (edited)extension Sequence {
var first: Element? {
var iterator = makeIterator()
return iterator.next()
}
}
let a: [Int] = [2, 3, 5]
let i: [Int].Iterator = a.makeIterator()
<stdin>:2:13: error: consecutive statements on a line must be separated by ';'
let i: [Int].Iterator = a.makeIterator()
^
;
<stdin>:2:14: error: member 'Iterator' in 'IndexingIterator<[Int]>' produces result of type 'IndexingIterator<[Int]>.Iterator.Type' (aka 'IndexingIterator<Array<Int>>.Type'), but context expects 'IndexingIterator<[Int]>'
let i: [Int].Iterator = a.makeIterator()
^
let a: [Int] = [2, 3, 5]
let i: Array<Int>.Iterator = a.makeIterator()
.
でつなぐメンバータイプは文法上 type identifier のみに設定されているのです。let a = [Int].Element()
print(a)
ただこれは動いちゃうのです。なぜならこれは文法上 type じゃなくて expression としてパースされるから。let s: String? = .none
let t: String?? = s
let u: String?? = .none
let x = (s as AnyHashable).hashValue
let y = (t as AnyHashable).hashValue
let z = (u as AnyHashable).hashValue
print(s == t, x == y)
print(s == u, x == z)
true false
false true
a == b -> a.hashValue == b.hashValue
のはずですが、
ここでは型が一致していないので、xと
y,zを並べて良いものか怪しい気がします。
s == tと
s==uは暗黙的に
Optional`に包まれるのもありますし。T
∈ Hashable
, ∀a
,b
∈ T
, a
== b
-> a.hashValue
== b.hashValue
定義がこんな感じだとすると、String?
とString??
で型が一致していない場合は前提が崩れるのでhashValue
については何も言えないはずです。var s1 = "Foo"
var s2 = Optional("Foo")
print(s1.hashValue, s2.hashValue)
print((s1 as AnyHashable).hashValue, (s2 as AnyHashable).hashValue)
print((s1 as! AnyHashable).hashValue, (s2 as! AnyHashable).hashValue)
-4610515456940335649 5550570105904624955
-4610515456940335649 5550570105904624955
-4610515456940335649 -4610515456940335649
stderr:<stdin>:5:11: warning: forced cast from 'String' to 'AnyHashable' always succeeds; did you mean to use 'as'?
print((s1 as! AnyHashable).hashValue, (s2 as! AnyHashable).hashValue)
^~~
as
<stdin>:5:43: warning: forced cast from 'String?' to 'AnyHashable' always succeeds; did you mean to use 'as'?
print((s1 as! AnyHashable).hashValue, (s2 as! AnyHashable).hashValue)
^~~
as
.swiftinterface
ですね。.swiftinterface
ですね。 .swiftmodule
は .swiftinteface
のバイナリ表現(キャッシュ)で clang でいうところの .pcm
(edited).swiftinterface
は後方互換性あるけど、 .swiftmodule
は生成したコンパイラバージョンでしか読めない。で、配布しないモジュールは後方互換性を確保する必要が無いので、.swiftinterface
を出す必要がないので出してないノだと思います。.swiftmodule
を入れられて、それが import
できる、つまり .swiftinterface
の代わりに(コンパイラのバージョンが一致していれば) .swiftmodule
を使うことができる状態になっている。.swiftinterface
と .swiftmodule
のどっちが「正」かっていうのは議論あるかも。
https://forums.swift.org/t/explicit-module-builds-the-new-swift-driver-and-swiftpm/36990 ここでは "there are four forms of module"protocol P {}
struct S: P {}
func check(_ maybeS: S?) {
print("maybeS = \(maybeS)")
print("maybeS is P = \(maybeS is P)")
print("maybeS as Any is P = \(maybeS as Any is P)")
print("------------------------------------------")
}
check(S())
check(nil)
maybeS = Optional(main.S())
maybeS is P = true
maybeS as Any is P = true
------------------------------------------
maybeS = nil
maybeS is P = false
maybeS as Any is P = false
------------------------------------------
stderr:<stdin>:6:23: warning: string interpolation produces a debug description for an optional value; did you mean to make this explicit?
print("maybeS = \(maybeS)")
^~~~~~
<stdin>:6:23: note: use 'String(describing:)' to silence this warning
print("maybeS = \(maybeS)")
^~~~~~
String(describing: )
<stdin>:6:23: note: provide a default value to avoid this warning
print("maybeS = \(maybeS)")
^~~~~~
?? <#default value#>
<stdin>:7:35: warning: checking a value with optional type 'S?' against dynamic type 'P' succeeds whenever the value is non-nil; did you mean to use '!= nil'?
print("maybeS is P = \(maybeS is P)")
~~~~~~ ^~~~
!= nil
maybeS = Optional(main.S())
maybeS is P = true
maybeS as Any is P = false
------------------------------------------
maybeS = nil
maybeS is P = false
maybeS as Any is P = false
------------------------------------------
stderr:<stdin>:6:23: warning: string interpolation produces a debug description for an optional value; did you mean to make this explicit?
print("maybeS = \(maybeS)")
^~~~~~
<stdin>:6:23: note: use 'String(describing:)' to silence this warning
print("maybeS = \(maybeS)")
^~~~~~
String(describing: )
<stdin>:6:23: note: provide a default value to avoid this warning
print("maybeS = \(maybeS)")
^~~~~~
?? <#default value#>
<stdin>:7:35: warning: checking a value with optional type 'S?' against dynamic type 'P' succeeds whenever the value is non-nil; did you mean to use '!= nil'?
print("maybeS is P = \(maybeS is P)")
~~~~~~ ^~~~
!= nil
Foundation.Process
で /usr/bin/swiftc
を実行しようとすると、
2021-06-05 15:20:12.963749+0900 swiftc[99910:13408271] Failed to open macho file at /Applications/Xcode12.5.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc for reading: Too many levels of symbolic links
/Applications/Xcode12.5.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc
が
-> swift-frontend
にリンクしてるだけで終わりなんですよね。 (edited)man dyld
見たけど多すぎてよくわからなかった・・・Test Case '-[SE0295PolyfillTests.JSONCodingTests test01]' started.
generate: Command-SE0295.gen.swift
2021-06-07 11:16:01.228423+0900 swiftc[77103:15204344] Failed to open macho file at /Applications/Xcode12.5.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc for reading: Too many levels of symbolic links
Test Case '-[SE0295PolyfillTests.JSONCodingTests test01]' passed (1.409 seconds).
Foundation.Process
で /usr/bin/swiftc
を実行しようとすると、
2021-06-05 15:20:12.963749+0900 swiftc[99910:13408271] Failed to open macho file at /Applications/Xcode12.5.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc for reading: Too many levels of symbolic links
Too many levels...
の文字列はなかったJSONCodingTests.swift
$ cat main.swift
import Foundation
let p = Process()
p.executableURL = URL(fileURLWithPath: "/usr/bin/env")
p.arguments = ["swiftc", "-o", "out", "main.swift"]
try p.run()
p.waitUntilExit()
swift test
で実行すると再現しないっぽい… テストランナーの問題なのかなswift test
のテストランナーは完全に同じっぽいしわけわからんgenerate-xcodeproj
は問題なかったLibrary not loaded: @rpath/lib_InternalSwiftSyntaxParser.dylib
Xcode.app
が焼き込まれてるファイルを見つけたTest Case '-[SE0295PolyfillTests.JSONCodingTests test01]' started.
generate: Command-SE0295.gen.swift
2021-06-07 11:42:14.894107+0900 swiftc[77512:15232794] Failed to open macho file at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc for reading: Too many levels of symbolic links
2021-06-06 19:44:33.440695-0700 swiftc[12611:1786858] Failed to open macho file at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc for reading: Too many levels of symbolic links
(edited)xcodebuild -scheme Example-Package -derivedDataPath build test
で試してる2021-06-06 19:47:34.100871-0700 swiftc[12779:1790755] Failed to open macho file at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc for reading: Too many levels of symbolic links
Apple Swift version 5.4 (swiftlang-1205.0.26.9 clang-1205.0.19.55)
でますねDYLD_FALLBACK_FRAMEWORK_PATH=/Applications/Xcode-12.5.app/Contents/SharedFrameworks:/Applications/Xcode-12.5.app/Contents/Developer/Platforms/MacOSX.platform/Developer/Library/Frameworks
DYLD_FALLBACK_LIBRARY_PATH=/Applications/Xcode-12.5.app/Contents/Developer/Platforms/MacOSX.platform/Developer/usr/lib
DYLD_FRAMEWORK_PATH=/Users/kateinoigakukun/Library/Developer/Xcode/DerivedData/Example-dcyedciowpcsqebafcorbracmhpk/Build/Products/Debug
DYLD_LIBRARY_PATH=/Users/kateinoigakukun/Library/Developer/Xcode/DerivedData/Example-dcyedciowpcsqebafcorbracmhpk/Build/Products/Debug
$ xcodebuild -project SE0295Polyfill.xcodeproj -scheme SE0295Polyfill-Package test
Test Case '-[SE0295PolyfillTests.JSONCodingTests test01]' started.
generate: Command-SE0295.gen.swift
2021-06-07 11:57:01.005930+0900 swiftc[78065:15248887] Failed to open macho file at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc for reading: Too many levels of symbolic links
Test Case '-[SE0295PolyfillTests.JSONCodingTests test01]' passed (2.926 seconds).
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc
を swiftc の代わりに実行するとエラーがでない/usr/bin/swiftc
を Xcode から実行することに問題がある...?/usr/bin/*
のshimはこのライブラリ経由でxcode-selectとDEVELOPER_DIRを見て実体のパスを解決してexecするんですよね$ ls -al /usr/lib/libxcselect.dylib
ls: /usr/lib/libxcselect.dylib: No such file or directory
xcselect_invoke_xcrun
実行してるだけだなあswiftc -v
を lldb swiftc
に置き換えてみたNot allowed to attach to process.
_parse_macho_iterate_slices
_parse_macho_iterate_slices_fd
がエラーだなぁfstat
してるからそれがなんかおかしなことになってしまってる?_parse_macho_iterate_slices
の open
ですでにダメなのか_parse_macho_iterate_slices
にブレイクポイントいれらたら$arg0
($rdi
) をみればパスがわかるはず (edited)0b100000000
let ret = open("/Applications/Xcode-12.5.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc", 0x100)
print(ret)
これは-1が返ってくるprint(String(cString: strerror(errno)))
するとToo many levels of symbolic linksだ#define O_NOFOLLOW 0x00000100 /* don't follow symlinks */
_parse_macho_iterate_slices
呼ばないケースがあるんだと思う syslog$DARWIN_EXTSN(0x3, "Failed to open macho file at %s for reading: %s", r15, strerror(*(int32_t *)__error()));
rax = 0x0;
_parse_macho_iterate_slices_fd
はMach-Oを検証してる感じかなあ_parse_macho_iterate_slices
呼ばれてない?OS_ACTIVITY_DT_MODE=YES
これだ!Test Case '-[SE0295PolyfillTests.JSONCodingTests test01]' started.
generate: Command-SE0295.gen.swift
Test Case '-[SE0295PolyfillTests.JSONCodingTests test01]' passed (1.140 seconds).
Test Case '-[SE0295PolyfillTests.JSONCodingTests test02]' started.
generate: Command-SE0295.gen.swift
Test Case '-[SE0295PolyfillTests.JSONCodingTests test02]' passed (0.935 seconds).
Test Case '-[SE0295PolyfillTests.JSONCodingTests test03]' started.
generate: Command-SE0295.gen.swift
Test Case '-[SE0295PolyfillTests.JSONCodingTests test03]' passed (0.933
env OS_ACTIVITY_DT_MODE=1 swiftc
がminimum reproです(URLResponse, Data)
?let hogeRes = try await URLSession.shared.data(for: hogeReq)
// いろいろ
let hogeData = hogeRes.0
ってなるのはちょっとダサさがあり…throws
なので。let (res, data) = try await URLSession...
で受けると良いかも?(data: Data, response: URLResponse)
とかになってくれるとうれしいstruct DataTaskResult
とかで nominal type でも良い気がするけど(自分はそうラップしている) (edited)async
化されてるんだとしたら、https://github.com/apple/swift-evolution/blob/main/proposals/0297-concurrency-objc.md#asynchronous-completion-handler-methods で議論されなかったのかな。The method itself has a void result type, because all results are delivered by the completion handler block.
に引っかかりそう)(_ data: Data?, _ response: URLResponse?, _ error: Error?) -> Void
というシンタックスはあるので、引数名乗るようにインポートすることは可能なはずです。(data: Data, response: URLResponse)
とかになってくれるとうれしい NS_SWIFT_DISABLE_ASYNC
というのが追加されているのでこれがあるやつはasyncに自動変換されないって感じなんですかね。
// 14.5
- (void)presentViewController:(UIViewController *)viewControllerToPresent animated: (BOOL)flag completion:(void (^ __nullable)(void))completion API_AVAILABLE(ios(5.0));
// 15.0
- (void)presentViewController:(UIViewController *)viewControllerToPresent animated: (BOOL)flag completion:(void (^ __nullable)(void))completion NS_SWIFT_DISABLE_ASYNC API_AVAILABLE(ios(5.0));
default: fatalError()
at then end of it, I have a compiler too slow error. If I put it, I have a Default will never be executed. Best of all, I cannot disable the warning in the package, so I'm left with 4 warnings at all times. Anything I can do?
func readInts() -> [Int] {
return readLine()!.split(separator: " ").map {Int(String($0))!}
}
func main() {
let K = Int(readLine()!)!
if !K.isMultiple(of: 9) {
print(0)
return
}
var dp: [Int] = Array(repeating: 0, count: K+1)
dp[0] = 1
for i in 1...K {
for j in max(0, i-9)..<i {
dp[i] = (dp[i] + dp[j]) % (Int(1e9) + 7)
//print(terminator: "")
}
}
print(dp[K])
}
main()
-Ounchecked
付きでコンパイルされます。(追記) Linux です。 (edited)let K = [9].randomElement()!
にしてここのSwift-5.2.5君に -Ounchecked で食わせても1
にならないreadInts()
は使ってなさそうですね。let K = [9].randomElement()!
にしてここのSwift-5.2.5君に -Ounchecked で食わせても1
にならない -Ounchecked
を外すと起きない。
$ pbpaste
func main() {
let K = Int(readLine()!)!
if !K.isMultiple(of: 9) {
print(0)
return
}
var dp: [Int] = Array(repeating: 0, count: K+1)
dp[0] = 1
for i in 1...K {
for j in max(0, i-9)..<i {
dp[i] = (dp[i] + dp[j]) % (Int(1e9) + 7)
//print(terminator: "")
}
}
print(dp[K])
}
main()
$ pbpaste|docker run -i norionomura/swift:5.2 sh -c 'swiftc -Ounchecked -; echo 9|./main'
1
$ pbpaste|docker run -i norionomura/swift:5.2 sh -c 'swiftc -; echo 9|./main'
256
$ pbpaste|docker run -i norionomura/swift:5.3 sh -c 'swiftc -Ounchecked -; echo 9|./main'
256
$ pbpaste|docker run -i norionomura/swift:5.3 sh -c 'swiftc -; echo 9|./main'
256
(edited)#20 1.569 [2215/2636] Compiling _NumericsShims _NumericsShims.c
#20 1.623 [2216/2637] Compiling _AtomicsShims.c
#20 1.623 [2217/2637] Compiling CSystem shims.c
#20 3.014 [2218/2637] Compiling RealModule AlgebraicField.swift
#20 4.016 [2219/2640] Compiling DequeModule Compatibility.swift
#20 6.883 SIL memory lifetime failure in @$s13ComplexModule0A0V3logyACyxGAEFZ: memory is not initialized, but should
#20 6.883 memory location: %98 = alloc_stack $RealType, let, name "θ" // users: %392, %390, %234, %235, %406, %247, %100
#20 6.883 at instruction: copy_addr %98 to [initialization] %391 : $*RealType // id: %392
#20 6.883
#20 6.883 in function:
#20 6.883 // static Complex.log(_:)
#20 6.883 sil [serialized] [ossa] @$s13ComplexModule0A0V3logyACyxGAEFZ : $@convention(method) <RealType where RealType : Real> (@in_guaranteed Complex<RealType>, @thin Complex<RealType>.Type) -> @out Complex<RealType> {
swift-numericsがこんな感じのエラーでDocker上でだけビルドできないっていうのにずっと悩んでたけど、Dockerに割り当てるリソースを増やしたら解決した。
CIでもちょっと内容は違うけど似たようなところで失敗していてそれは -j 1
を指定したらビルドできるようになった。
SIL memory lifetime failure
ってなんだろうってずっと悩んでいた。func foo(completion: @escaping () -> Void) {}
final class C {
var a: Int = 0
func bar() {
foo { [self] in
a += 1
}
}
}
func foo(completion: @escaping () -> Void) {}
final class C {
var a: Int = 0
func bar() {
foo { [weak self] in
guard let self = self else { return }
foo { [self] in
a += 1
}
}
}
}
<stdin>:8:17: error: reference to property 'a' in closure requires explicit use of 'self' to make capture semantics explicit
a += 1
^
<stdin>:7:20: note: variable other than 'self' captured here under the name 'self' does not enable implicit 'self'
foo { [self] in
^
<stdin>:7:20: warning: capture 'self' was never used
foo { [self] in
^
weak self
を介すると [self]
は使えないのか。preconditionFailure
だけど万が一のプロダクションでのクラッシュを避けるために assertionFailure
& return
してたパターン(このパターン自体に賛否はあるけど)、 async
になったら値を返さないといけないので preconditionFailure
にするしかない?インスタンス生成が簡単なら適当な値を返して握りつぶすことはできなくはないけど。
func foo(completion: @escaping (Foo) -> Void) {
guard checkState(self.state) else {
assertionFailure()
return
}
...
}
(edited)foo() async -> Foo?
にしてnilが返ってたらスルーとかにはできそうですね。
本来ありえないケースのためにOptionalにするのはちょっと微妙そうですが。preconditionFailure
にするのが正しいんだけど、絶対にクラッシュさせたくないから assertionFailure
にしておいて Release ビルドでは握りつぶしたいというテクニックを使っているケースの話ですね。まあ Optional
にして呼び出し側で握りつぶす実装になるのかな。気持ち悪いけど。throws
でいいケースなら↓は良さそうだな。
assertionFailure()
throw CancellationError()
struct APIResponse<Value>: Decodable where Value: Decodable {
var value: Value?
var error: APIResponseError?
func result() -> Result<Value, Error> {
print("result")
switch (value, error) {
case (let value?, nil): return .success(value)
case (nil, let error?): return .failure(error)
case (_, _): return .failure(APIResponseError(code: -1))
}
}
func result<Wrapped>() -> Result<Value, Error> where Value == Wrapped? {
print("result optional")
switch (value, error) {
case (let value?, nil): return .success(value)
case (nil, let error?): return .failure(error)
case (nil, nil): return .success(nil)
case (_, _): return .failure(APIResponseError(code: -1))
}
}
}
struct APIResponseError: Error, Decodable {
var code: Int
}
struct User: Codable {}
let r1: APIResponse<User> = .init(value: nil, error: nil)
print(r1.result())
let r2: APIResponse<User?> = .init(value: nil, error: nil)
print(r2.result())
result
failure(main.APIResponseError(code: -1))
result
failure(main.APIResponseError(code: -1))
r2
の場合 "result optional"
の方が優先度高くならないんですっけ?非ジェネリックとジェネリックだから?result
が表示されるか result optional
が表示されるか。@_disfavoredOverload
の出番か・・・。protocol OptionalProtocol: ExpressibleByNilLiteral {
associatedtype Wrapped
static func some(_ value: Wrapped) -> Self
static var none: Self { get }
}
extension OptionalProtocol {
init(nilLiteral: Void) {
self = .none
}
}
extension Optional: OptionalProtocol {}
struct APIResponse<Value>: Decodable where Value: Decodable {
var value: Value?
var error: APIResponseError?
}
extension APIResponse {
func result() -> Result<Value, Error> {
print("result")
switch (value, error) {
case (let value?, nil): return .success(value)
case (nil, let error?): return .failure(error)
case (_, _): return .failure(APIResponseError(code: -1))
}
}
}
extension APIResponse where Value: OptionalProtocol {
func result() -> Result<Value, Error> {
print("result optional")
switch (value, error) {
case (let value?, nil): return .success(value)
case (nil, let error?): return .failure(error)
case (nil, nil): return .success(nil)
case (_, _): return .failure(APIResponseError(code: -1))
}
}
}
struct APIResponseError: Error, Decodable {
var code: Int
}
struct User: Codable {}
let r1: APIResponse<User> = .init(value: nil, error: nil)
print(r1.result())
let r2: APIResponse<User?> = .init(value: nil, error: nil)
print(r2.result())
result
failure(main.APIResponseError(code: -1))
result optional
success(nil)
self
を shadow しても 暗黙の self
は shadow されないのむずいimport Foundation
print(atan2(1.0, 0.0))
1.5707963267948966
import Foundation
print(atan2(1, 0))
<stdin>:2:7: error: ambiguous use of 'atan2'
print(atan2(1, 0))
^
Foundation.atan2:1:13: note: found this candidate
public func atan2(_ lhs: CGFloat, _ rhs: CGFloat) -> CGFloat
^
Glibc.atan2:1:13: note: found this candidate
public func atan2(_ lhs: Float, _ rhs: Float) -> Float
^
Glibc.atan2:1:13: note: found this candidate
public func atan2(_ lhs: Float80, _ rhs: Float80) -> Float80
^
SwiftGlibc.atan2:1:13: note: found this candidate
public func atan2(_ __y: Double, _ __x: Double) -> Double
^
1.0
なら ExpressibleByFloatLiteral
の優先順位で Double
が優先されるけど、 1
だと他の浮動小数点数に対して Double
が優先されずに ambiguous になるっぽい。1f
とかやらなくていいSwiftでも .0
を明示的に書く意味はちょっとある。 (edited)- http:
paths:
- backend:
serviceName: runner-vnightly-main
servicePort: 80
path: /runner/nightly-main/*
pathType: ImplementationSpecific
- backend:
serviceName: runner-vnightly-55
servicePort: 80
path: /runner/nightly-55/*
pathType: ImplementationSpecific
- backend:
serviceName: runner-vnightly-54
servicePort: 80
path: /runner/nightly-54/*
pathType: ImplementationSpecific
- backend:
serviceName: runner-vnightly-53
servicePort: 80
path: /runner/nightly-53/*
pathType: ImplementationSpecific
- backend:
serviceName: runner-v542
servicePort: 80
path: /runner/5.4.2/*
pathType: ImplementationSpecific
- backend:
serviceName: runner-v541
servicePort: 80
path: /runner/5.4.1/*
こんなルーティングで振り分けています。services:
app:
image: kishikawakatsumi/swift-playground:latest
...
carbonara:
image: petersolopov/carbonara
...
nginx-proxy:
image: nginxproxy/nginx-proxy
...
acme-companion:
image: nginxproxy/acme-companion
...
swift-nightly-main:
image: swiftlang/swift:nightly-main
container_name: swift-nightly-main
swift-nightly-5.5:
image: swiftlang/swift:nightly-5.5
container_name: swift-nightly-5.5
swift-nightly-5.4:
image: swiftlang/swift:nightly-5.4
container_name: swift-nightly-5.4
swift-nightly-5.3:
image: swiftlang/swift:nightly-5.3
container_name: swift-nightly-5.3
swift-5.4.1:
image: kishikawakatsumi/swift:5.4.1
container_name: swift-5.4.1
swift-5.4:
image: kishikawakatsumi/swift:5.4
container_name: swift-5.4
...
こんなdocker-compose.ymlでした。 (edited)private
メソッドからだけ呼ばれるメソッド群(処理に名前を付けるだけ)が他のメソッドから可視なのが気持ち悪い。それらを extension
にまとめた上で extension private にして、そのメソッドからだけ可視にしたい。data-bs-container
っていうオプションを発見してそれでボタンを指定すれば安定するようになりました。actor
を考えると、 Fault Isolation の単位が actor
であるべきかは微妙な気がするんですよね。別の仕組みとして入った方が使い勝手が良さそうな。 Erlang みたいに何でも Actor でやる言語ならともかく。 (edited)Task
かな?Task
ごとに Fault Isolation があるといいかも?init
の中だと self.init
と Self.init
の両方がほぼ同じ意味で書けるけど、意味が違うことを今日知った (edited)extension CodableFromLosslessStringConvertible {
public init(from decoder: Decoder) throws {
let c = try decoder.singleValueContainer()
let string = try c.decode(String.self)
// ここが self.init だと怒られる
guard let value = Self.init(string) else {
throw DecodingError.dataCorruptedError(
in: c,
debugDescription: "invalid string: \(string)"
)
}
self = value
}
}
(edited)self.init
は戻り値がないからかな?self.init
は 別のinitへの転送という意味なので。
しかもこの場合、throwsなinitから optional なinitを呼んでてそこの不一致もある。UIView
とか UIViewController
はパターン決まってるし、たまにクラスを継承して init
書くことあると戸惑う。 (edited)required init
もありますからね。error as Any as? CustomStringConvertible
で警告は消せた。 (edited)Swift.Error
で受けたいんだよね"\(err)"
にして薙ぎ払うとか?w (edited)CustomStringConvertible
すら取れなかったときの最後の手段になってるswift-log
を使うと、 Logger.Metadata
ってのがあってrun
関数が標準ライブラリにあるとうれしい気がしてきた。
func run<T>(_ body: () -> T) -> T {
body()
}
よくあるプロパティの初期化が
var foo: Foo = {
...
return Foo(...)
}()
みたいなのも
var foo: Foo = run {
...
return Foo(...)
}
と書ける。 ()
でクロージャ式即実行の気持ち悪さが緩和されそう。
非同期版の
func run<T>(_ body: () async -> T) async -> T {
await body()
}
もあれば、 MainActor
に戻す処理も
await { @MainActor in
self.foo = foo
}()
じゃなくて
await run { @MainActor in
self.foo = foo
}
と書ける。MainActor
に戻す手段をどこかで見たなぁと思って WWDC のセッションや Proposal 漁ってたんですが、 { @MainActor in ... }
を見つけて、これだったかも?ってなってました。T.self
をデフォルトにするのおもしろいですね。 JSONDecoder.decode
とかもこれやってほしいかも。
static func run<T>(resultType: T.Type = T.self, body: @MainActor @Sendable () throws -> T) async rethrows -> T
import Foundation
extension JSONDecoder {
func myDecode<T: Decodable>(_ type: T.Type = T.self, from data: Data) throws -> T {
try decode(type, from: data)
}
}
let decoded: [Int] = try! JSONDecoder().myDecode(from: "[2, 3, 5]".data(using: .utf8)!)
print(decoded)
MainActor.run
でいいのはなぜ?用途が異なるから?run
はそもそも resultType がない場合は withXxx
系で多用されるパターンですよねInt?
だった場合に、右辺が Int
で推論されるのか Int?
で推論されるのかが、 decode
の場合は重い違いになってきます。T.self
が与えられてるのはありかなぁと。JSONDecoder
は具象型だから関係なくない? (edited)JSONDecoder.decode
はたしかに。 KeyedContainerProtocol.decode(:for)
の話かと思ってました。そっちのほうがたくさん書くのが大変だし。If each `KeyPath` encapsulates the type information, the `decode` methods won't need a `type` parameter.
JSONDecoder
だけの話じゃないか。class UICell {}
func _dequeue(_ type: UICell.Type) -> UICell {
print(type) // MyCellが出てこない
fatalError()
}
func dequeue<Cell: UICell>(_ type: UICell.Type = Cell.self) -> Cell {
_dequeue(Cell.self) as! Cell
}
class MyCell: UICell {}
class MyCell2: UICell {}
func cell(for row: Int) -> UICell {
let cell: UICell
if Bool.random() {
cell = dequeue(MyCell.self)
} else {
cell = dequeue(MyCell2.self)
}
return cell
}
cell(for: 0)
おぼろげな記憶から思い出してみたんですがこんな感じだったかも?func dequeue<Cell: UICell>(_ type: UICell.Type = Cell.self) -> Cell {
_dequeue(type) as! Cell
}
(edited)-Ounchecked
をdeprecatedにするって話があったと思うんですけど、いま調べ直したら特に確定的な事は出てこなくて、どうなったんでしたっけfunc main() {
let a: Int??? = 42
print(a as Any)
guard let a = a else { return }
print(a as Any)
guard let a = a else { return }
print(a as Any)
guard let a = a else { return }
print(a)
}
main()
Optional(Optional(Optional(42)))
Optional(Optional(42))
Optional(42)
42
-Ounchecked
をdeprecatedにするって話があったと思うんですけど、いま調べ直したら特に確定的な事は出てこなくて、どうなったんでしたっけ -Ounchecked
を取り除きたい・・・)-Ounchecked
自体はパフォーマンス追求するなら必要なんじゃないのかなぁ。分岐予測とかでほぼカバーできるにしても。ただ、 99% のケースでは不要。少なくとも AtCoder には要らない・・・。-remove-runtime-asserts
などの指定があるので-O
ファミリーである必要はないと思うんですよね。-Onone
かつ -remove-runtime-asserts
がユースケースとしてあり得るのかや、 assert
が -O
で消えることとの一貫性とか考えると最適化の一種じゃないのかなぁ。 (edited)-Osize
はあり得ると思いますassert
については -O
で消える?消えない?-remove-runtime-asserts
が assert
ではなく precondition
を消すためのものというのが明確だといいかなぁ。remove-runtime-asserts
はassert
を消すだけのものなのかしら? (edited)def RemoveRuntimeAsserts : Flag<["-"], "remove-runtime-asserts">,
Flags<[FrontendOption]>,
HelpText<"Remove runtime safety checks.">;
-remove-safety-checks
のほうがよくね?assert
と precondition
の名前は混乱していて、 Array
のインデックスチェックは precondition
ではなくインターナルななんとか assert 関数が呼ばれてたような気がする。precondition
も広義の assert の一種なのでは。_precondition
になってる。
@inlinable
@inline(__always)
internal func _checkValidSubscript(_ index: Int) {
_precondition(
(index >= 0) && (index < immutableCount),
"Index out of range"
)
}
https://github.com/apple/swift/blob/main/stdlib/public/core/ContiguousArrayBuffer.swift#L589-L596catch
して適切なエラーに包んで投げるとか、ログを吐くとか。do
記法や try
- catch
がボイラープレート削減に寄与しないことがあるのはありえそう。guard ... catch { }
みたいなのほしくなりそう。Optional
では都度書くしかないから、それだったらエラーもそれでいいかなと。まとめてハンドリングできるケースなら do
- catch
したいですが。do
- catch
が活きますよね。do
- catch
が活きそう。guard let x = try foo() catch {
throw BarError(cause: error)
}
let x: Foo
do {
x = try foo()
} catch {
throw BarError(cause: error)
}
になるのが辛くて・・・。try
- catch
を改良したとはいえ、↑のパターンは解決できてないので guard
- try
- catch
がほしい。guard let x = try? foo() else {
throw BarError()
}
はできるけど cause
がとれない。try
- catch
でボイラープレート削減ができないんじゃないかなと。func x() throws {
do {
try a()
} cathc {
throw XError.foo(cause: error)
}
do {
try b()
} cathc {
throw XError.bar(cause: error)
}
do {
try c()
} cathc {
throw XError.baz(cause: error)
}
}
みたいな。Result
なら
func x() -> Result<X, XError> {
guard case .success(let a) = a() else {
return .failure(XError.foo)
}
guard case .success(let b) = b() else {
return .failure(XError.foo)
}
guard case .success(let c) = c() else {
return .failure(XError.foo)
}
return .success(.init(a, b, c))
}
みたいな場合には忘れることは起こらなくない?do
- try
- catch
はあまり役に立たない。case success
ってかいてるところがノイズだと思います。try
- catch
要らなくない?って発想になるのかなと。guard let a = try a() catch { ... }
がほしい。) (edited) try recover { try a() }
catch: { throw XError.foo(cause: $0) }
guard - catch
は良さそう。else
の代わりに catch
キーワードを使えるんですね。try
でも Result
でも変わらないようなコードってのはあって、その Result
の劣化版として if
のチェックでも対して困らないよって考えはまああり得るのかなと。try
- catch
や do
記法がなくていいということにはならないと思う。do
記法的なもの( try
- catch
を含む)があまり有効でない世界というのはあまり考えたことがなかったなと。do
記法と throws
/ try
の話をしていたら、偶然だけど今日 inamiy さんが iOSDC で do
記法と async
/ await
の話をしていた。
https://speakerdeck.com/inamiy/iosdc-japan-2021 public static subscript<EnclosingSelf: AnyObject>(
_enclosingInstance object: EnclosingSelf,
wrapped wrappedKeyPath: ReferenceWritableKeyPath<EnclosingSelf, Value>,
storage storageKeyPath: ReferenceWritableKeyPath<EnclosingSelf, Published<Value>>
) -> Value {
@_disfavoredOverload
みたいに裏技使うから、SwiftUIのためにこっそり入ってたんかねPublished
使ってたらこれがstructなのに違和感を覚えて、色々と気になってきてOpenCombineを調べてみたら見つけたって感じですVStack {
Text("something")
#if os(iOS)
.iOSSpecificModifier()
#endif
.commonModifier()
}
がこうなりConsecutive statements on a line must be separated by a newlineエラーに
VStack {
Text("something")#if os(iOS)
.iOSSpecificModifier()
#endif
.commonModifier()
}
JSON
型が標準で提供されると便利そう。自由なフォーマットの JSON をコード側で扱いたいとき。 JSONSerialization
と比べるとパフォーマンス悪いけど。
enum JSON {
case number(Double)
case boolean(Bool)
case string(String)
case array([JSON])
case object([String: JSON])
case null
}
extension JSON: Codable {
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let value = try? container.decode(Double.self) {
self = .number(value)
} else if let value = try? container.decode(Bool.self) {
self = .boolean(value)
} else if let value = try? container.decode(String.self) {
self = .string(value)
} else if let value = try? container.decode([JSON].self) {
self = .array(value)
} else if let value = try? container.decode([String: JSON].self) {
self = .object(value)
} else if container.decodeNil() {
self = .null
} else {
throw DecodingError.dataCorrupted(.init(codingPath: decoder.codingPath, debugDescription: "Failed to interpret as a JSON value.", underlyingError: nil))
}
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
switch self {
case .number(let value):
try container.encode(value)
case .boolean(let value):
try container.encode(value)
case .string(let value):
try container.encode(value)
case .array(let value):
try container.encode(value)
case .object(let value):
try container.encode(value)
case .null:
try container.encodeNil()
}
}
}
let json = "[true]".data(using: .utf8)!
let decoded = try JSONDecoder().decode(JSON.self, from: json) // .array(.boolean(true))
Codable
の仕組みの上で実現できないんですよね〜。Codable
の仕組みを使いたいとか、 YAML に変換したいとか。Codable
に適合しつつも、 JSONSerialization
を使った高速なデコードが提供されてたらいいのかな。downloadTask
の completion handler に渡される URL は
download(...) async throws -> (URL, URLResponse)
の場合ってどうなるんでしょう? API リファレンスには何も書いていない。
https://developer.apple.com/documentation/foundation/urlsession/3767355-download
もし downloadTask
と同じなら actor context の引き継ぎとかでキューに投入されてる間に消えてしまうし、そうでなければいつ削除されるんでしょう?downloadTask
のときにどうやってファイルの read/write が衝突しないようにすればいいのかも微妙ですね。@escaping
が小文字始まりなのに @Sendable
が大文字始まりなの気持ち悪い気が。@sendable
だったけど、 protocol Sendable
と同じ意味なら @Sendable
のほうがよくない?という話になった@
って Property Wrapper や Global Actor 等に限定されてたと思うのに、 @Sendable
はそのルールを破ってる気がする。Sendable
以外のマーカープロトコルが導入された場合には @Sendable
相当のものが必要になると考えられ、そうするとプロコトル名に @
を付けるのは合理的だし、 Property Wrapper や Global Actor の @
が型名から生成されることとも一貫性があるのか。var a = 2
var b = 3
print(a, b)
(a, b) = (b, a)
print(a, b)
var a = 2
var b = 3
print(a, b)
(a, b) = (b, a)
print(a, b)
2 3
3 2
swap
の方がいいだろうけど、これでも書けたのか。NSError
の code
ではなく、あえて _code
を使っているコードを見かけたのですが、どんな意図が考えられますか?公開できるコードではないので貼れないですが・・・。NSError *error; error->_code;
public protocol Error: Sendable {
var _domain: String { get }
var _code: Int { get }
// Note: _userInfo is always an NSDictionary, but we cannot use that type here
// because the standard library cannot depend on Foundation. However, the
// underscore implies that we control all implementations of this requirement.
var _userInfo: AnyObject? { get }
#if _runtime(_ObjC)
func _getEmbeddedNSError() -> AnyObject?
#endif
}
Swift.Error
って空じゃないんだ・・・NSError._code
じゃなくて、Error._code
が隠しパラメータとして存在していてNSError is Error
だから、 NSError
のじゃなくて Error
の _code
を見ているのかもError
を NSError
にしたときに Error
の _code
を code
として使うのか。CustomNSError
が用意されてるので違うような気もしますね/healthz
を用意するかそこの設定を変える必要はあるかもしれません。let
もできるといいよね。
guard let foo = try bar() catch { ... }
let
もできるといいよね。
guard let foo = try bar() catch { ... }
guard let
が Optional Binding 以外に使われるのは微妙だけど、これ提案したら通らないかなぁ・・・。guard let foo = try? bar() else { ... }
はできるけど、エラーが取れないんよね。guard let
が Optional Binding 以外に使われるのは微妙だけど、これ提案したら通らないかなぁ・・・。 let foo: T
do { foo = try bar() } catch { ... }
で済むのであんまりメリットなさそうですけど,型名を省略できるというメリットならありそうですね. (edited)guard let foo = try bar() else catch {
switch error {
case let FooError as error: print(...)
default: print(...)
}
return
}
こんなイメージです。let foo: T
do { foo = try bar() }
catch let error as FooError { print(...); return }
catch { print(...); return }
let foo: T
switch Result(catching: { try bar() }) {
case .success(let value): foo = value
case .failure(let error as FooError): print(...); return
case .failure(let error): print(...); return
}
do
に catch
を複数繋げられるの知りませんでした!
確かに初期化拒否すると脱出が強制されるのはそうですね。なるほど。let foo = true
let bar = true
outer: if foo {
if bar {
print("bar")
break outer
}
print("not bar")
}
print("end")
let foo = true
let bar = true
outer: if foo {
if bar {
print("bar")
break outer
}
print("not bar")
}
print("end")
bar
end
https://swift.org
do {
print("OK")
}
(edited)https://swift.org
do {
print("OK")
}
(edited)OK
DispatchQueue.main.async { [weak this = self] in
...
}
キャプチャにその場で名前つけられるっていうのも知らんかった。
ブラウザの古いタブを整理していて知らないTipsがいろいろ見つかった。DispatchQueue.main.async { [foo = self.foo, bar = self.bar] in
...
}
というのを典型的な利用例だと思うけどこの場合selfはキャプチャされない、でいいのかな?[foo, bar]
と省略してかけます[foo = foo!]
という感じになりますswift build
とか swift test
とかのようなXcodeプロジェクトが存在しない純粋なSwiftPMプロジェクトって、何か xcresult
もしくはそれに準ずるビルド結果の出力ってあるのかな swift api-digester -sdk "$sdk" -dump-sdk -module "$module" \
-o "$output/$module.json" -I "$repodir/.build/debug"
これかな。_modify
の気持ちを考えていると、yieldで渡ってきた値対して複数の操作をしたいとき、こういうのがstdlibに欲しくなる
func modify<T, ResultType>(_ x: inout T, _ body: (inout T) -> ResultType) -> ResultType {
return body(&x)
}
// Before
var frame = controlStack.last!
self.valueStack.removeLast(valueStack.count - frame.height)
frame.unreachable = true
self.controlStack[controlStack.count - 1] = frame
// After
modify(&self.controlStack[controlStack.count - 1]) { frame in
self.valueStack.removeLast(valueStack.count - frame.height)
frame.unreachable = true
}
@_optimize(none)
func blackhole<T>(_: T) {}
func modify<T, ResultType>(_ x: inout T, _ body: (inout T) -> ResultType) -> ResultType {
return body(&x)
}
struct Element {
var value1: Int64
var value2: Int64
var tails: [Int64]
}
func modifyElement(items: [Element]) {
var items = items
modify(&items[0]) { item in
item.value1 = 42
item.tails[0] = 50
}
blackhole(items)
}
import Foundation
let start = Date()
for _ in 0..<1000000 {
let baseItems = [
Element(value1: 1, value2: 2, tails: Array(repeating: 24, count: 3000)),
]
modifyElement(items: baseItems)
}
let elapsed = Date().timeIntervalSince(start)
print("took \(elapsed)")
(edited)@_optimize(none)
func blackhole<T>(_: T) {}
func modify<T, ResultType>(_ x: inout T, _ body: (inout T) -> ResultType) -> ResultType {
return body(&x)
}
struct Element {
var value1: Int64
var value2: Int64
var tails: [Int64]
}
func modifyElement(items: [Element]) {
var items = items
modify(&items[0]) { item in
item.value1 = 42
item.tails[0] = 50
}
blackhole(items)
}
import Foundation
let start = Date()
for _ in 0..<1000000 {
let baseItems = [
Element(value1: 1, value2: 2, tails: Array(repeating: 24, count: 3000)),
]
modifyElement(items: baseItems)
}
let elapsed = Date().timeIntervalSince(start)
print("took \(elapsed)")
(edited)took 2.2947229146957397
(edited)@_optimize(none)
func blackhole<T>(_: T) {}
struct Element {
var value1: Int64
var value2: Int64
var tails: [Int64]
}
func modifyElement(items: [Element]) {
var items = items
var item = items[0]
item.value1 = 42
item.tails[0] = 50
items[0] = item
blackhole(items)
}
import Foundation
let start = Date()
for _ in 0..<1000000 {
let baseItems = [
Element(value1: 1, value2: 2, tails: Array(repeating: 24, count: 3000)),
]
modifyElement(items: baseItems)
}
let elapsed = Date().timeIntervalSince(start)
print("took \(elapsed)")
(edited)@_optimize(none)
func blackhole<T>(_: T) {}
struct Element {
var value1: Int64
var value2: Int64
var tails: [Int64]
}
func modifyElement(items: [Element]) {
var items = items
var item = items[0]
item.value1 = 42
item.tails[0] = 50
items[0] = item
blackhole(items)
}
import Foundation
let start = Date()
for _ in 0..<1000000 {
let baseItems = [
Element(value1: 1, value2: 2, tails: Array(repeating: 24, count: 3000)),
]
modifyElement(items: baseItems)
}
let elapsed = Date().timeIntervalSince(start)
print("took \(elapsed)")
(edited)took 2.611519932746887
(edited)inout item = &array[index]
item.foo = a
item.bar = b
これが既定路線かなarray
には触れない?item
が生きてる範囲では触れないendScope(item)
を追加しようという話もあるTask
は value: Success { get async throws }
だけど Result
は value: Success { get throws }
にならないのかな Result.value
ってもうありましたっけ?Result.get()
typed throws
周りの議論で止まって?しまったんですね… (edited)ManagedCriticalState
というstructがあり、
https://github.com/apple/swift-async-algorithms/blob/main/Sources/AsyncAlgorithms/Locking.swift
用途としては、複数のactorとかqueueで状態を共有する場合や、前に他のスレッドで話にあったwithTaskCancellationHandlerのcancelHandlerで利用することが想定されているのですが、
https://github.com/apple/swift-async-algorithms/pull/7
actor内部の値にsyncにアクセスしたい場合にも使えるのかなと思ったのですが、どうなんでしょう?withCriticalRegion内部でawaitできないのでデータ競合は起きないのかなーと思ったのですが…
actor A {
let state = ManagedCriticalState(0)
nonisolated var value: Int {
state.withCriticalRegion {
$0
}
}
func update() {
state.withCriticalRegion {
$0 += 1
}
}
}
func test() async {
let a = A()
await a.update()
print(a.value) // 1
}
await test()
ManagedCriticalState
というstructがあり、
https://github.com/apple/swift-async-algorithms/blob/main/Sources/AsyncAlgorithms/Locking.swift
用途としては、複数のactorとかqueueで状態を共有する場合や、前に他のスレッドで話にあったwithTaskCancellationHandlerのcancelHandlerで利用することが想定されているのですが、
https://github.com/apple/swift-async-algorithms/pull/7
actor内部の値にsyncにアクセスしたい場合にも使えるのかなと思ったのですが、どうなんでしょう?withCriticalRegion内部でawaitできないのでデータ競合は起きないのかなーと思ったのですが…
actor A {
let state = ManagedCriticalState(0)
nonisolated var value: Int {
state.withCriticalRegion {
$0
}
}
func update() {
state.withCriticalRegion {
$0 += 1
}
}
}
func test() async {
let a = A()
await a.update()
print(a.value) // 1
}
await test()
func lazyMapCollection<C: Collection, T>(_ collection: C, body: @escaping (C.Element) -> T)
-> <R: Collection where R.Element == T> R {
return collection.lazy.map { body($0) }
}
func lazyMapCollection<C: Collection, T>(_ collection: C, body: @escaping (C.Element) -> T)
-> <R: Collection where R.Element == T> R {
return collection.lazy.map { body($0) }
}
struct S {}
func makePair() -> <T0> (T0, T0) {
(S(), S())
}
// makePair()
sil hidden @$s1i8makePairQr_QrtyF : $@convention(thin) @substituted <τ_0_0, τ_0_1> () -> (@out τ_0_0, @out τ_0_1) for <@_opaqueReturnTypeOf("$s1i8makePairQr_QrtyF", 0) __, @_opaqueReturnTypeOf("$s1i8makePairQr_QrtyF", 0) __> {
...
}
swift demangle '$s1i8makePairQr_QrtyF'
$s1i8makePairQr_QrtyF ---> i.makePair() -> (some, some)
sil hidden @$s1i8makePairQr_QrtyF : $@convention(thin) @substituted <τ_0_0> () -> (@out τ_0_0, @out τ_0_0) for <@_opaqueReturnTypeOf("$s1i8makePairQr_QrtyF", 0) __, @_opaqueReturnTypeOf("$s1i8makePairQr_QrtyF", 0) __> {
こうなってほしいと*S
になってるんですよね
sil hidden @$s1a8makePairQr_QrtyF : $@convention(thin) @substituted <τ_0_0, τ_0_1> () -> (@out τ_0_0, @out τ_0_1) for <@_opaqueReturnTypeOf("$s1a8makePairQr_QrtyF", 0) __, @_opaqueReturnTypeOf("$s1a8makePairQr_QrtyF", 0) __> {
// %0 "$return_value" // user: %5
// %1 "$return_value" // user: %9
bb0(%0 : $*S, %1 : $*S):
(edited)public func makePair1() -> <T0> (T0, T0) {
(S(), S())
}
public func makePair2() -> <T0, T1> (T0, T1) {
(S(), S())
}
// swiftinterface
public func makePair1() -> (T0, T0)
public func makePair2() -> (T0, T1)
public func makePair1() -> <T0> (T0, T0) {
(S(), S())
}
public func makePair2() -> <T0, T1> (T0, T1) {
(S(), S())
}
// swiftinterface
public func makePair1() -> (T0, T0)
public func makePair2() -> (T0, T1)
(T0, T1)
な異なる型のペアを、 (T, T)
な同一の型のペアとして渡すコードを書くと-> (some P, some P)
とかは動くので謎@_opaqueReturnTypeOf
?public protocol P {}
public struct S: P {}
public func makePair() -> (some P, some P) {
(S(), S())
}
// makePair()
sil hidden @$s1i8makePairQr_QrtyF : $@convention(thin) @substituted <τ_0_0, τ_0_1> () -> (@out τ_0_0, @out τ_0_1) for <@_opaqueReturnTypeOf("$s1i8makePairQr_QrtyF", 0) __, @_opaqueReturnTypeOf("$s1i8makePairQr_QrtyF", 0) __> {
$ swift demangle '$s1i8makePairQr_QrtyF'
$s1i8makePairQr_QrtyF ---> i.makePair() -> (some, some)
// .swiftinterface
public func makePair() -> (some i.P, some i.P)
some
が2つ返り値にあるから、これに0番、1番って番号が付いていて、swift_getTypeByMangledNameInContext
で問い合わせる// makePair()
sil hidden @$s1i8makePairQr_QrtyF : $@convention(thin) @substituted <τ_0_0, τ_0_1> () -> (@out τ_0_0, @out τ_0_1) for <@_opaqueReturnTypeOf("$s1i8makePairQr_QrtyF", 0) __, @_opaqueReturnTypeOf("$s1i8makePairQr_QrtyF", 0) __> {
// makePair()
sil @$s1b8makePairQr_QR_tyF : $@convention(thin) @substituted <τ_0_0, τ_0_1> () -> (@out τ_0_0, @out τ_0_1) for <@_opaqueReturnTypeOf("$s1b8makePairQr_QR_tyF", 0) __, @_opaqueReturnTypeOf("$s1b8makePairQr_QR_tyF", 1) __>
(S(), S())
だからだと思う。public protocol P {}
public struct S1: P {}
public struct S2: P {}
public func makePair() -> (some P, some P) {
(S1(), S2())
}
// makePair()
sil @$s1i8makePairQr_QR_tyF : $@convention(thin) @substituted <τ_0_0, τ_0_1> () -> (@out τ_0_0, @out τ_0_1) for <@_opaqueReturnTypeOf("$s1i8makePairQr_QR_tyF", 0) __, @_opaqueReturnTypeOf("$s1i8makePairQr_QR_tyF", 1) __> {
(edited)public protocol P {}
public struct S1: P {}
public struct S2: P {}
public func makePair() -> (some P, some P) {
(S1(), S1())
}
(edited)public protocol P {}
public struct S1: P {}
public struct S2: P {}
public func makePair() -> (some P, some P) {
(S1(), S1())
}
(edited)sil_stage canonical
import Builtin
import Swift
import SwiftShims
public protocol P {
}
public struct S1 : P {
init()
}
public struct S2 : P {
init()
}
public func makePair() -> (some P, some P)
// main
sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):
%2 = integer_literal $Builtin.Int32, 0 // user: %3
%3 = struct $Int32 (%2 : $Builtin.Int32) // user: %4
return %3 : $Int32 // id: %4
} // end sil function 'main'
// S1.init()
sil hidden @$s4main2S1VACycfC : $@convention(method) (@thin S1.Type) -> S1 {
// %0 "$metatype"
bb0(%0 : $@thin S1.Type):
%1 = alloc_stack [lexical] $S1, var, name "self", implicit // user: %3
%2 = struct $S1 () // user: %4
dealloc_stack %1 : $*S1 // id: %3
return %2 : $S1 // id: %4
} // end sil function '$s4main2S1VACycfC'
// makePair()
sil @$s4main8makePairQr_QR_tyF : $@convention(thin) @substituted <τ_0_0, τ_0_1> () -> (@out τ_0_0, @out τ_0_1) for <@_opaqueReturnTypeOf("$s4main8makePairQr_QR_tyF", 0) __, @_opaqueReturnTypeOf("$s4main8makePairQr_QR_tyF", 1) __> {
// %0 "$return_value" // user: %5
// %1 "$return_value" // user: %9
bb0(%0 : $*S1, %1 : $*S1):
%2 = metatype $@thin S1.Type // user: %4
// function_ref S1.init()
%3 = function_ref @$s4main2S1VACycfC : $@convention(method) (@thin S1.Type) -> S1 // user: %4
%4 = apply %3(%2) : $@convention(method) (@thin S1.Type) -> S1 // user: %5
store %4 to %0 : $*S1 // id: %5
%6 = metatype $@thin S1.Type // user: %8
// function_ref S1.init()
%7 = function_ref @$s4main2S1VACycfC : $@convention(method) (@thin S1.Type) -> S1 // user: %8
%8 = apply %7(%6) : $@convention(m
(edited)@_oRTOf(..., 1)
になるswift_getTypeByMangledNameInContext
は@__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s1e8ortTupleQr_QR_tyFQOyQo_MD")
@__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s1e8ortTupleQr_QR_tyFQOyQo__AaBQr_QR_tyFQOyQo0_tMD")
(edited)__swift_instantiateConcreteTypeFromMangledName
は swift_getTypeByMangledNameInContext
をキャッシュ付きにラップするローカル関数なんだけどswift demangle '$s1e8ortTupleQr_QR_tyFQOyQo_MD'
$s1e8ortTupleQr_QR_tyFQOyQo_MD ---> demangling cache variable for type metadata for <<opaque return type of e.ortTuple() -> (some, some)>>.0
opaque return type [0]
をピンポイント問い合わせしていて$s1e8ortTupleQr_QR_tyFQOyQo__AaBQr_QR_tyFQOyQo0_tMD ---> demangling cache variable for type metadata for (<<opaque return type of e.ortTuple() -> (some, some)>>.0, <<opaque return type of e.ortTuple() -> (some, some)>>.1)
(ort[0], ort[1])
っていうマングリングでkind=Global
kind=TypeMetadataDemanglingCache
kind=Type
kind=Tuple
kind=TupleElement
kind=Type
kind=OpaqueType
kind=OpaqueReturnTypeOf
kind=Function
kind=Module, text="e"
kind=Identifier, text="ortTuple"
kind=Type
kind=FunctionType
kind=ArgumentTuple
kind=Type
kind=Tuple
kind=ReturnType
kind=Type
kind=Tuple
kind=TupleElement
kind=Type
kind=OpaqueReturnType
kind=TupleElement
kind=Type
kind=OpaqueReturnTypeIndexed, index=0
kind=Index, index=0
kind=TypeList
kind=TypeList
kind=TupleElement
kind=Type
kind=OpaqueType
kind=OpaqueReturnTypeOf
kind=Function
kind=Module, text="e"
kind=Identifier, text="ortTuple"
kind=Type
kind=FunctionType
kind=ArgumentTuple
kind=Type
kind=Tuple
kind=ReturnType
kind=Type
kind=Tuple
kind=TupleElement
kind=Type
kind=OpaqueReturnType
kind=TupleElement
kind=Type
kind=OpaqueReturnTypeIndexed, index=0
kind=Index, index=1
kind=TypeList
kind=TypeList
(ort[0], ort[1])
って式が書いてあるort
って書くところでopaque return type of ( function, index )
(ortOf( foo: returns (some some) , 0 ), ortOf ( foo: returns (some some), 1 ) )
-> <T0, T1> (T0, T1)
でも -> <T0> (T0, T0)
でも-> (some, some)
になっててortOf
で指定できるindexは 0と1 が対応づいていて<T0, T1>
なのか <T0>
なのか、もしくは 2つ目が <T0, T1 where T1 == T0>
になるのかはわからんけど、ortOf
のindexの対応関係は、
ソースレベルのシグネチャから、IRレベルのシグネチャを対応させてる関係上、
caller側でもcallee側のコンパイル時と同じようにわかるはずだし。public protocol P<A> {
associatedtype A
}
struct S1<A>: P {}
struct S2<A>: P {}
public func makeP() -> <T: P, U: P where T.A == U.A> (T, U) {
return (S1<Int>(), S2<Int>())
}
// swift-interface-format-version: 1.0
// swift-compiler-version: Apple Swift version 5.8-dev (LLVM 515f8ef5b9ec986, Swift 7435c936a6a67d0)
// swift-module-flags: -target x86_64-apple-macosx12.0 -enable-objc-interop -module-name i
import Swift
import _Concurrency
#if compiler(>=5.3) && $PrimaryAssociatedTypes2
public protocol P<A> {
associatedtype A
}
#else
public protocol P {
associatedtype A
}
#endif
public func makeP() -> (T, U)
any Sequence
って self-conform してるんですっけ?
@swift-5.7.3
struct Foo {}
protocol Bar {
associatedtype Foos: Sequence where Foos.Element == Foo
var foos: Foos { get }
}
struct Baz: Bar {
var foos: [Foo] { [Foo()] }
}
let bar: any Bar = Baz()
for foo in bar.foos as any Sequence {
print(foo)
}
any Sequence
って self-conform してるんですっけ?
@swift-5.7.3
struct Foo {}
protocol Bar {
associatedtype Foos: Sequence where Foos.Element == Foo
var foos: Foos { get }
}
struct Baz: Bar {
var foos: [Foo] { [Foo()] }
}
let bar: any Bar = Baz()
for foo in bar.foos as any Sequence {
print(foo)
}
Foo()
some
にするかどうかという議論が最近盛り上がってますね(やるべきなのか、やるとしたらいつどうやるのか)
これまで存在型になって問題が起きる可能性があったのでany
が入ったという動機を考えるとそうなるのかなあとは思いましたが、どうなんでしょう?
https://forums.swift.org/t/discussion-eliding-some-in-swift-6/57918 (edited)some
or any
doesn't really affect the domain of a function, particularly for non-inout
function arguments. With the recent additions to generalize existentials and allow for implicit opening, func foo(_: some P)
and func foo(_: any P)
both accept the same sets of parameters and have the same sets of capabilities operating on their arguments, but func foo(_: some P)
is slightly more efficient as public ABI because it can accept a conforming value as-is without boxing it, and also more flexible by default inside the body of foo
, since you can use all of P
's methods on it without an opening step. It would make sense to favor the more efficient, more expressive interpretation of func foo(_: P)
to mean func foo(_: some P)
, independent of what we choose to do in places where there's an effective semantic difference.
func foo(_: P)
を func foo(_: some P)
にするとして、 func foo(_: [P])
は func foo(_: [some P])
になるのかな?それはまた違う気が・・・。[P]
に異なる型を入れようとした場合コンパイラがエラーにするので、既存のコードを壊すことはないから大丈夫、必要ならany
を付ける、とかなんですかね???func foo(_: [some P])
(func foo<T: P>(_: [T])
)とfunc foo(_: [any P])
は全然シグネチャが違うので変なところで呼び出し優先順位が入れ替わったりしちゃわないかなぁI also think taking this approach will lead to a confusing model because programmers will need to deeply understand where they can omit some and where they cannot. For example, you'd be able to write a parameter of type P, but not of type [P].
Int.self
と \Int.self
など)が対応してないから。
Int.self
Int.Type.self
\Int.self
\Int.Type.self
Int.self // Int.Type
Int.Type.self // Int.Type.Type
\Int.self // WritableKeyPath<Int, Int>
\Int.Type.self // WritableKeyPath<Int.Type, Int.Type>
ややこしいType
になる。
後半はプロパティとかと同じでself
が指すものを対象とするKeyPath
になる.Int.self
は Int.Type
のインスタンスだけど、 \Int.self
は Int.Type
ではなく Int
(から Int
へ)の KeyPath
になり、 Int.Type
の KeyPath
は \Int.Type.self
と書かないといけないけど、 Int.Type.self
は Int.Type.Type
のインスタンスというわかりづらさ。 (edited)extension Int {
static var mySelf: Int.Type = Int.self
var mySelf: Int { self }
}
print(type(of: Int.mySelf))
print(type(of: \Int.mySelf))
extension Int {
static var mySelf: Int.Type = Int.self
var mySelf: Int { self }
}
print(type(of: Int.mySelf))
print(type(of: \Int.mySelf))
Int.Type
KeyPath<Int, Int>
print(Int.self[keyPath: \Int.Type.self])
@available(*, unavailable)
extension ISO8601DateFormatter : @unchecked Sendable {
}
たまたまこういうの見つけたんですが、これってSendableじゃないことを明示的に定義している?extension ISO8601DateFormatter: @unchecked Sendable {}
書いたら上書きできるな。これ書くことにどういう意味があるんだろうTSCBasic.Thread
と Foundation.Thread
のどちらも同じ優先度だけど、initの引数にとるクロージャが Sendable
かどうかでオーバーロード優先順位がFoundationに寄った?struct S {
var _value: Int = 0
var value: Int {
get {
print("get")
return _value
}
set {
print("set")
_value = newValue
}
}
}
var s = S()
s[keyPath: \.value] = 42
struct S {
var _value: Int = 0
var value: Int {
get {
print("get")
return _value
}
set {
print("set")
_value = newValue
}
}
}
var s = S()
s[keyPath: \.value] = 42
get
set
WritableKeyPath
経由で書き込みするときってgetter呼ばれるんですねstruct S {
var _value: Int = 0
var value: Int {
get {
print("get")
return _value
}
set {
print("set")
_value = newValue
}
}
}
var s = S()
s[keyPath: \.value] = 42
struct S {
var _value: Int = 0
var value: Int {
get {
print("get")
return _value
}
set {
print("set")
_value = newValue
}
}
}
var s = S()
s[keyPath: \.value] = 42
set
@LateInit
みたいなpropertyWrapperでこれに遭遇してちょっと困ったんですよねs.foo.bar = x
みたいなアクセスだと、fooをgetしてbarの位置にx書き込んでfooに書き戻すんですけどMutatingWritebackBuffer
が書き戻す君AnyHashable
ってハッシュ値の計算においてmetatypeを混ぜ込まないから、同じレイアウトを持つ2つの異なる型がある時、容易にハッシュ衝突が起きるな (edited)AnyHashable(1) == AnyHashable(1.0)
だからNSNumber
にラップする必要があって同じ値になった挙動を再現している (edited)_HasCustomAnyHashableRepresentation
っていう裏プロトコルがあって Int とかがこれを使ってるわ internal var _canonicalBox: _AnyHashableBox {
// We need to follow NSNumber semantics here; the AnyHashable forms of
// integer types holding the same mathematical value should compare equal.
// Sign-extend value to a 64-bit integer. This will generate hash conflicts
// between, say -1 and UInt.max, but that's fine.
if _value < 0 {
return _IntegerAnyHashableBox<Int64>(Int64(truncatingIfNeeded: _value))
}
return _IntegerAnyHashableBox<UInt64>(UInt64(truncatingIfNeeded: _value))
}
% if bits != 16:
internal struct _${Self}AnyHashableBox: _AnyHashableBox {
internal typealias Base = ${Self}
internal let _value: Base
internal init(_ value: Base) {
self._value = value
}
internal var _canonicalBox: _AnyHashableBox {
// Float and Double are bridged with NSNumber, so we have to follow
// NSNumber's rules for equality. I.e., we need to make sure equal
// numerical values end up in identical boxes after canonicalization, so
// that _isEqual will consider them equal and they're hashed the same way.
//
// Note that these AnyHashable boxes don't currently feed discriminator bits
// to the hasher, so we allow repeatable collisions. E.g., -1 will always
// collide with UInt64.max.
if _value < 0 {
if let i = Int64(exactly: _value) {
return _IntegerAnyHashableBox(i)
}
} else {
if let i = UInt64(exactly: _value) {
return _IntegerAnyHashableBox(i)
}
}
if let d = Double(exactly: _value) {
return _DoubleAnyHashableBox(d)
}
// If a value can't be represented by a Double, keep it in its original
// representation so that it won't compare equal to approximations. (So that
// we don't round off Float80 values.)
return self
}
Int64(exactly:)
つかって _IntegerAnyHashableBox
にすり寄っていくらしいfunc nonThrowing(_ body: @autoclosure () throws -> Void) {
try? body()
}
func rethrowing(_ body: () throws -> Void) rethrows {
try body()
}
func fail() throws {
throw NSError(domain: "", code: 0)
}
func foo() {
nonThrowing(try fail())
}
func bar() {
rethrowing {
nonThrowing(try fail())
}
}
func nonThrowing(_ body: @autoclosure () throws -> Void) {
try? body()
}
func rethrowing(_ body: () throws -> Void) rethrows {
try body()
}
func fail() throws {
throw NSError(domain: "", code: 0)
}
func foo() {
nonThrowing(try fail())
}
func bar() {
rethrowing {
nonThrowing(try fail())
}
}
<stdin>:8:11: error: cannot find 'NSError' in scope
throw NSError(domain: "", code: 0)
^~~~~~~
<stdin>:15:5: error: call can throw, but it is not marked with 'try' and the error is not handled
rethrowing {
^
<stdin>:15:16: note: call is to 'rethrows' function, but argument function can throw
rethrowing {
^
enum HogeError: Error { case hoge }
func nonThrowing(_ body: @autoclosure () throws -> Void) {
try? body()
}
func rethrowing(_ body: () throws -> Void) rethrows {
try body()
}
func fail() throws {
throw HogeError.hoge
}
func foo() {
nonThrowing(try fail())
}
func bar() {
rethrowing {
nonThrowing(try fail())
}
}
enum HogeError: Error { case hoge }
func nonThrowing(_ body: @autoclosure () throws -> Void) {
try? body()
}
func rethrowing(_ body: () throws -> Void) rethrows {
try body()
}
func fail() throws {
throw HogeError.hoge
}
func foo() {
nonThrowing(try fail())
}
func bar() {
rethrowing {
nonThrowing(try fail())
}
}
<stdin>:17:5: error: call can throw, but it is not marked with 'try' and the error is not handled
rethrowing {
^
<stdin>:17:16: note: call is to 'rethrows' function, but argument function can throw
rethrowing {
^
bar
での rethrowing
呼び出しに try
は不要だと思うんですが、これってコンパイラのバグなんでしょうか?
foo
は期待通りコンパイル通るんですが…XCTContext.runActivity(named: "") { _ in // Call can throw, but it is not marked with 'try' and the error is not handled
XCTAssert(try foo())
}
protocol P {
static func equals(a: Self, b: Self) -> Bool
}
class C1: P {
init() {}
static func equals(a: C1, b: C1) -> Bool {
true
}
}
class C2: C1 { }
func start(_ a: any P, _ b: any P) {
open(a, b)
}
func open<T: P, U: P>(_ t: T, _ u: U) {
guard let u = u as? T else {
print("no")
return
}
print("ok")
_ = T.equals(a: t, b: u)
}
func check(_ a: C2, b: C1) {
_ = C2.equals(a: a, b: b)
}
start(C1(), C2()) // ok
start(C2(), C1()) // no
protocol P {
static func equals(a: Self, b: Self) -> Bool
}
class C1: P {
init() {}
static func equals(a: C1, b: C1) -> Bool {
true
}
}
class C2: C1 { }
func start(_ a: any P, _ b: any P) {
open(a, b)
}
func open<T: P, U: P>(_ t: T, _ u: U) {
guard let u = u as? T else {
print("no")
return
}
print("ok")
_ = T.equals(a: t, b: u)
}
func check(_ a: C2, b: C1) {
_ = C2.equals(a: a, b: b)
}
start(C1(), C2()) // ok
start(C2(), C1()) // no
ok
no
any P
が <T: P>
に implicit open されるときの挙動で、
もしインスタンスの型がクラス(C2)で、その P
conformanceが親クラス (C1) で行われていた場合、
openする型はそのまま値の型 (C2) になる。open
の実装は正しいように見えるが、この挙動のおかげで、
tとuにC1とC2を渡すと、tがC1のときは u as? C1
が成功するが、
tがC2のときは u as? C2
は失敗するので実行結果が変わる。C2
の P 準拠は C1 で行われているので、 C2.equals
は 2つの C1
を受け取る関数になっていて、本来は C2 と C1 を渡す事ができる。(check
で確認)C2
の P
への準拠は、 Self = C1
としての準拠になっていると言えるので、
openする時の T
は C1
として open されるほうが自然な気もするし、
実際の値のmetatypeがそのまま出てくる今の挙動のほうが自然な気もする。any P
を多用してコードを書いているんだけど、
struct S: Equatable {
var a: any P
}
↑これが通らないのがダルいP
が Equatable
でも any P
が Equatable
ではないからなんだけど、extension any P: Equatable { ... }
が書けるようになってほしい。。Box<T>
みたいな型を作って any P
じゃなくて Box<any P>
で S
に持たせるようにしたらこれが書けるようになるんですけどね...
extension Box: Equatable where T == any P {
static func == (lhs: Self, rhs: Self) -> Bool {
true // FIXME
}
}
var v: Int?
print(v[keyPath: \.?.description])
これかけてちょっとびっくりしたprint(\Int?.?.description)
print(\Optional<Int>.?.description)
print(\Int?.?.description)
print(\Optional<Int>.?.description)
<stdin>:2:20: error: '>' is not a postfix unary operator
print(\Optional<Int>.?.description)
^
<stdin>:2:21: error: cannot find operator '.?.' in scope
print(\Optional<Int>.?.description)
^~~
<stdin>:2:24: error: cannot find 'description' in scope
print(\Optional<Int>.?.description)
^~~~~~~~~~~
Int?
はOKで Optional<Int>
はNGfunc f(async: Int) {
let _: Int = async
}
func g(throws: Int) {
let _: Int = `throws`
}
func f(async: Int) {
let _: Int = async
}
func g(throws: Int) {
let _: Int = `throws`
}
async
はキーワードじゃないけど、throws
はキーワードasync
は先にメソッド名としても使われてたりしたし、キーワードにはできなかったのか。過去にもキーワードじゃなくなったものとかあったし、 async
ができるなら throws
もやればできそう。 ContextualSimpleDeclAttribute('async', 'Async',
DeclModifier, OnVar, OnFunc,
ABIBreakingToAdd, ABIBreakingToRemove,
APIBreakingToAdd, APIBreakingToRemove,
code=106),
(edited) ExprKeyword('Throws', 'throws', serialization_code=53),
(edited)import Foundation
var f = DateFormatter()
f.dateFormat = "yyyy/MM/dd HH:mm:ss"
f.locale = Locale(identifier: "ja")
f.calendar = .init(identifier: .gregorian)
f.timeZone = TimeZone(abbreviation: "JST")!
print(f.date(from: "2022/07/10 12:00:00") ?? "nil") // ok
print(f.date(from: "2022-07-10 12:00:00") ?? "nil") // macだとok, Linuxだとng
(edited)import Foundation
var f = DateFormatter()
f.dateFormat = "yyyy/MM/dd HH:mm:ss"
f.locale = Locale(identifier: "ja")
f.calendar = .init(identifier: .gregorian)
f.timeZone = TimeZone(abbreviation: "JST")!
print(f.date(from: "2022/07/10 12:00:00") ?? "nil") // ok
print(f.date(from: "2022-07-10 12:00:00") ?? "nil") // macだとok, Linuxだとng
(edited)2022-07-10 03:00:00 +0000
nil
(edited)/
に -
を許してて謎y
みたいな文字以外はなんでも書けるものだと思ってた(Linuxが変 (edited)'
ではさむ#define __swift__
することでインクルー ドが可能になることが判明した.
libgmalloc
が基盤にあって、それが環境変数でコントロールできるようになっていて、leaks
コマンドがそのフロントエンドになっていて、
XcodeのやつもLeaksも本質的には同じポテンシャルがあるって感じか?@codegen
と @end
のプレースホルダマーカーをソースコードに書いておいて、
画像2枚目のようなレンダラーを書いておくと、
(その他いろいろなセットアップを経て)
$ swift package codegen
で、プレースホルダ内に生成コードが挿入される。
swift-format
を組み込んであって、インデントとか綺麗になる。template["as"] = asCast(...)
のところが
// @codegen(as)
// @end
のところに差し込まれて、最終結果が一枚めってことですね。だいぶ高度な高度生成ができそう。 (edited).pascal
とかなんか便利そうなプロパティがあるのもおもしろい。プレースホルダがあるからややこしいロジックがあるコード生成以外の固定のところは普通にテキストで書けるのも使い勝手のバランスがいいのかな。$ swift package init
してから、手動で、CodegenKitを依存に追加する
画像2: $ swift package codegen-kit init
を実行する
画像3: その結果、自動で codegen
がセットアップされる
画像4: $ swift package codegen
でコード生成を実行する
対象のパッケージはswift package initした状態ではない途中からでも codegen-kit init
できる。
SwiftPM の command plugin は、product として公開しておくと、ルートのプロジェクトから、依存先のcommandが呼び出せるので、自分自身をセットアップするコマンドを出荷することができる・・・
codegenのセットアップにおいては、プロジェクトの Package.swift
をswift-syntaxで解析して編集してる。 (edited)extension Value {
func with<Value>(
_ kp: WritableKeyPath<Self, Value>,
_ newValue: Value
) -> Self {
var copy = self
copy[keyPath: kp] = newValue
return copy
}
}
を用意すると
let copy = value
.with(\.name, "John")
.with(\.address.countryName, "Japan")
みたいにできて便利で、 SwiftSyntax はプロパティ毎の withXXX(_:)
APIを全部捨ててこの汎用with(_:_:)
に置き変えますよっていう。 https://github.com/apple/swift-syntax/pull/1253 (edited)var copy = value
copy.name = "john"
copy.address.countryName = "Japan"
って書けるのが良いところの一つだと思うんですけど
レシーバ何度も書くのは良くないので、
value.modified {
$0.name = "john"
$0.address.countryName = "Japan"
}
って僕は書いてますねvalue.with([
\.name: "John",
\.address.countryName: "Japan",
])
出来るようになるかな。value.with([
\.name: "John",
\.address.countryName: "Japan",
])
出来るようになるかな。 Dictionary
ではなく dictionary literal に準拠した何かを作る必要はありそうだけど。address.countryName
の変更に当たるコピーが更に必要ですね。nil
にするのが一番よいんでしょうか?.some(nil)
を渡さないといけないので、つらいなと思っています。nil
にするのが一番よいんでしょうか? Observable
って protocol
でも使えるようになるのかな?
protocol Foo: Observable {
var value: Int { get }
}
みたいな。今って @Published
を protocol
に書けなくて不便だけど、↑ができたら解決される?struct Foo: ExpressibleByArrayLiteral {
var values: [Int]
init(_ values: [Int]) {
self.values = values
}
init(arrayLiteral elements: Int...) {
self.init(elements)
}
}
print(Foo())
struct Foo: ExpressibleByArrayLiteral {
var values: [Int]
init(_ values: [Int]) {
self.values = values
}
init(arrayLiteral elements: Int...) {
self.init(elements)
}
}
print(Foo())
Foo(values: [])
arrayLiteral:
のラベル消せるのかany
必須化されたら、 Result<Int, any Error>
とか PassthroughSubject<Int, any Error>
とか書かないといけなくなるの?Any
とError
は例外じゃないですか?Any
は any Any
と書かずに Any
と書ける特別対応がある、 AnyObject
も同様。any Error
は必須じゃないかな?Error
についての議論は見たことなかった気がするなと。any Error
って書いてましたが…Error
を特別扱いするって書いてないような・・・-enable-upcoming-feature ExistentialAny
を素通りしてくる
https://github.com/apple/swift/issues/65034-enable-upcoming-feature ExistentialAny
を素通りしてくる
https://github.com/apple/swift/issues/65034 any P
修正祭りになる (edited)any P
修正祭りになる (edited)extension any P: P
って書くのがSE-0335のFuture Directionになってるので、その意味でもany Error
がおそらく望まれてる表記で正しいですね (edited)extension any P: P
って書くのがSE-0335のFuture Directionになってるので、その意味でもany Error
がおそらく望まれてる表記で正しいですね (edited)Error
は暗黙の self conformance があるので、 Error
は Any
とかと同じく特別表記もありだったとは思うんですよね。extension any P: P
で書くべきだけど、 Error
についてはそれを書く場面がなく、 Swift の中で例外的に existential として用いられる場面が多いので、 Any
と同じく any
不要でもいいかなと。CheckedContinuation<Foo, Error>
とか、 Error
か Never
かの二択だし。func foo(p: P) = foo(p: some P) = foo<T: P>(p: T)
// 将来↑の仕様が入った時点で
func foo(error: Error) = foo(error: any Error)
// ↑この特別ルールが残るのは混乱を招きません?
(edited)extension any P: P
で書くべきだけど、 Error
についてはそれを書く場面がなく、 Swift の中で例外的に existential として用いられる場面が多いので、 Any
と同じく any
不要でもいいかなと。 Any
は名前に Any
が入っているので any
省略に見える」という説明になっていました。Any
の self conformance はヘッダーでどう記述されるの? (edited)Any
は空のプロトコルで、型制約部分に書けないから、existentialに名前が付いてる特別なもの、という気持ちはわからなくもないです。
しかし AnyObject
と AnyActor
は制約としても使えるので結構怪しいAny
は飛ぶことすらできない・・・public typealias AnyObject = Builtin.AnyObject
Any
って標準ライブラリに存在してないのかもError
は飛べるけど、 Error
のプロトコル宣言になにか意味があるわけじゃないし、 Error
が AnyXxx
系と同じく特別扱いでも不思議じゃないと思うんよね。Error
のプロトコル宣言はちゃんと意味があると思いますよpublic protocol Error : Sendable {
}
今だとSendableが付いてるけど、
ユーザー側でextensionを追加する事もできますany
導入の目的の一つは、不必要に Existential が利用されることが抑制されることだけど、 Error
は Existential として利用することが当たり前なので微妙な気がする。将来的に typed throws が導入されるなら any Error
でもいいかもしれない。AnyObject
も extension
は無理か。なるほど?@objc protocol
かつ staticメンバがない場合」ユーザー定義プロトコルに対しても発動するのでAnyObject
も extension
は無理か。なるほど? Any
はプロトコルとしては空のプロトコルって扱いなんですよね なのでプロトコル部分を持たないtypealias X = P & Q
って合成プロトコルが書けるけど
これを昔は typealias X = protocol<P, Q>
って記法だった時代があって
で、そのころの Any
は typealias Any = protocol<>
だったんですよね。
空の合成プロトコルなのでプロトコル部分がないというニュアンスが読み取れると思います。 (edited)Error
を特別扱いするのは現実的なユースケースを考えるとあり得ると思っていて、 self conformance の記述問題も起きないって話の順序で考えています。any
の導入はそもそも、 P
と <: P>
が同じ見た目なのに意味が違うのがわかりづらい、
それによってユーザーがSwiftを理解するのを困難にしている、という課題から始まった話なのでResult<Int, Error>
←これこそまさに、 Errorのself coformanceがあるせいで、余計に何が起きてるかわかりづらい一例なのでResult<Int, any Error>
と書かなければならないようにすることで、Error
だけは避けようがなくて、その原因は untyped throws に結びついてるんですよね。 Result
はともかく、 CheckedContinuation
は Error
か Never
かの二択になっていて、 throws
に型を付けられないから避けようがない。言語の都合で Existential 使ってるのに any
を書かされるということに釈然としない気持ちがあります・・・。他のケースは、 Existential を使うことに罪悪感を感じるべきで、そのペナルティとして any
を書かされるのは納得なんですが。
(補足: Existential を使うなという意味ではなく、ちゃんと罪悪感を感じた上で選択すべきだと思ってます。) (edited)throws
が意味するのは any Error
を投げるって意味ですね。
なるほど。
「existentialは非推奨だから any
を書く手間が増えるのはマッチしている」という解釈のもとで、
「言語都合でexistentialを使わされるケースで手間が増えるのは嫌だ」は筋が通った意見だと思いましたsome
に省略にする」プランも、「anyよりsomeを使うのを推奨するべきだから望ましいものを簡単に書ける方にしよう」という話を含んでいるのでany
を書くのが一手めんどくさい」のは意図的なペナルティと言えそう。any Error
じゃないといけないので、そう思って納得することにします。any Error
というのはマッチすると思います。enum Result<Success, Failure = any Error>
だとちょうどいいのかも。typealias AnyError = any Error
↑これだったら AnyError
の利用にペナルティは感じます?AnyP
系は撲滅したいですね・・・any
の a
まで打ったら、ny Error
補完候補に出してほしいな。any E
まで行かないと補完が効かないのが今だるいUUID
ってなんで DataProtocol
に準拠してないんだろう?UIView
のリファレンス https://developer.apple.com/documentation/uikit/uiview の Conforms To に Equatable
や Hashable
がないんだけど( NSObject
https://developer.apple.com/documentation/objectivec/nsobject にはある)、これって単にドキュメント上で漏れてるだけ?
Equatable
に準拠したクラスのサブクラスの Equatable
準拠ってどうなるんだったっけ( ==
の Self
がサブクラスを指さずにスーパークラスを指して UIVeiw
にとっての Euatable
準拠になってない?)と思ったけど、↓はできたからサブクラスにとっての Equatable
準拠でいいのかな。
@swift-5.8.1
import Foundation
struct Foo<T: Equatable> {
func bar(_ x: T, _ y: T) -> Bool {
return x == y
}
}
class UIView: NSObject {
}
let foo: Foo<UIView> = .init() // これが通るので UIView は Equatable 準拠
let a: UIView = .init()
let b: UIView = .init()
print(a == a)
print(a == b)
UIView
のリファレンス https://developer.apple.com/documentation/uikit/uiview の Conforms To に Equatable
や Hashable
がないんだけど( NSObject
https://developer.apple.com/documentation/objectivec/nsobject にはある)、これって単にドキュメント上で漏れてるだけ?
Equatable
に準拠したクラスのサブクラスの Equatable
準拠ってどうなるんだったっけ( ==
の Self
がサブクラスを指さずにスーパークラスを指して UIVeiw
にとっての Euatable
準拠になってない?)と思ったけど、↓はできたからサブクラスにとっての Equatable
準拠でいいのかな。
@swift-5.8.1
import Foundation
struct Foo<T: Equatable> {
func bar(_ x: T, _ y: T) -> Bool {
return x == y
}
}
class UIView: NSObject {
}
let foo: Foo<UIView> = .init() // これが通るので UIView は Equatable 準拠
let a: UIView = .init()
let b: UIView = .init()
print(a == a)
print(a == b)
true
false
import Foundation
class Amanojaku: NSObject {
override func isEqual(_ object: Any?) -> Bool {
!super.isEqual(object)
}
}
let a = Amanojaku()
let b = Amanojaku()
print(a == a)
print(a == b)
(edited)import Foundation
class Amanojaku: NSObject {
override func isEqual(_ object: Any?) -> Bool {
!super.isEqual(object)
}
}
let a = Amanojaku()
let b = Amanojaku()
print(a == a)
print(a == b)
(edited)false
true
(edited)UIView
のリファレンス https://developer.apple.com/documentation/uikit/uiview の Conforms To に Equatable
や Hashable
がないんだけど( NSObject
https://developer.apple.com/documentation/objectivec/nsobject にはある)、これって単にドキュメント上で漏れてるだけ?
Equatable
に準拠したクラスのサブクラスの Equatable
準拠ってどうなるんだったっけ( ==
の Self
がサブクラスを指さずにスーパークラスを指して UIVeiw
にとっての Euatable
準拠になってない?)と思ったけど、↓はできたからサブクラスにとっての Equatable
準拠でいいのかな。
@swift-5.8.1
import Foundation
struct Foo<T: Equatable> {
func bar(_ x: T, _ y: T) -> Bool {
return x == y
}
}
class UIView: NSObject {
}
let foo: Foo<UIView> = .init() // これが通るので UIView は Equatable 準拠
let a: UIView = .init()
let b: UIView = .init()
print(a == a)
print(a == b)
==
は Self
型で定義されてるから、サブクラスの式に見えてるときは サブクラス同士でないと比較できないはず (edited)==
は Self
型で定義されてるから、サブクラスの式に見えてるときは サブクラス同士でないと比較できないはず (edited)Foo<UIView>
に対して ==
を UIView
同士の比較に制限し、それが呼び出されたときは NSObject
の ==
(の先にある isEqual
が呼ばれるのはいいとして、その場合 UIView
は Equatable
に準拠していると言えると思うけど、 UIView
のリファレンスに載ってないのはドキュメント上の問題なのかな? (edited)extension
で Equatable
準拠してて表示が漏れるとか?Foo<UIView>
に対して ==
を UIView
同士の比較に制限し、それが呼び出されたときは NSObject
の ==
(の先にある isEqual
が呼ばれるのはいいとして、その場合 UIView
は Equatable
に準拠していると言えると思うけど、 UIView
のリファレンスに載ってないのはドキュメント上の問題なのかな? (edited)UIView
は Equatable
に準拠している」で合ってると思います。
「親クラスを経由して準拠している」のか「自分で準拠している」のかは、違いをもたらさないはず。
SR-103は、「親クラスで準拠する時にデフォルト実装を選択している」だから「子も準拠している」と考えてよくて、特に↑とは矛盾しない。 (edited)NSMutableArray
にも Sequence
とかないですね。true
を返すようにオーバーライドされてるけど、 NSString
にも NSMutableString
にも "Conforms To" に Equatable
がない。
@swift-5.8.1
import Foundation
let a: NSMutableString = "X"
let b: NSMutableString = "X"
print(a === b)
print(a == b)
(edited)true
を返すようにオーバーライドされてるけど、 NSString
にも NSMutableString
にも "Conforms To" に Equatable
がない。
@swift-5.8.1
import Foundation
let a: NSMutableString = "X"
let b: NSMutableString = "X"
print(a === b)
print(a == b)
(edited)false
true
(edited)NSMutableString
を使ったのは、 NSString
だと色んな手を使ったけど同じ文字列に同じオブジェクトが割り当てられて↑みたいなことができなかった。) (edited)NSMutableString
を使ったのは、 NSString
だと色んな手を使ったけど同じ文字列に同じオブジェクトが割り当てられて↑みたいなことができなかった。) (edited).init
してみたり、それで不十分だったから部分文字列から生成とか試した。 NSString
自体の部分文字列は試してない。.init
してみたり、それで不十分だったから部分文字列から生成とか試した。 NSString
自体の部分文字列は試してない。 ==
で比較しても(リテラル同士の範囲で)うまく動いてしまう罠の話、 Obj-Cでも同じ用に罠なのかな。 (edited)Obj-C
で NSString *
のポインタ同士を ==
で比較するって意味ですよね?isEqual:
しないとバグってる。class A: Equatable {
static func ==(lhs: A, rhs: A) -> Bool {
print("A")
return lhs === rhs
}
}
class B: A {}
class C: B {
static func ==(lhs: C, rhs: C) -> Bool {
print("C")
return lhs === rhs
}
}
struct Foo<T: Equatable> {
func bar(_ x: T, _ y: T) -> Bool {
x == y
}
}
let c: C = .init()
print(Foo<A>().bar(c, c))
print(Foo<B>().bar(c, c))
print(Foo<C>().bar(c, c))
class A: Equatable {
static func ==(lhs: A, rhs: A) -> Bool {
print("A")
return lhs === rhs
}
}
class B: A {}
class C: B {
static func ==(lhs: C, rhs: C) -> Bool {
print("C")
return lhs === rhs
}
}
struct Foo<T: Equatable> {
func bar(_ x: T, _ y: T) -> Bool {
x == y
}
}
let c: C = .init()
print(Foo<A>().bar(c, c))
print(Foo<B>().bar(c, c))
print(Foo<C>().bar(c, c))
A
true
A
true
A
true
A.==
を class func
にして、 C.==
を override class func
にする必要があります。import Foundation
struct Foo<T: Equatable> {
func bar(_ x: T, _ y: T) -> Bool {
x == y
}
}
let a: NSMutableString = "X"
let b: NSMutableString = "X"
print(a === b)
print(Foo<NSObject>().bar(a, b))
print(Foo<NSString>().bar(a, b))
print(Foo<NSMutableString>().bar(a, b))
import Foundation
struct Foo<T: Equatable> {
func bar(_ x: T, _ y: T) -> Bool {
x == y
}
}
let a: NSMutableString = "X"
let b: NSMutableString = "X"
print(a === b)
print(Foo<NSObject>().bar(a, b))
print(Foo<NSString>().bar(a, b))
print(Foo<NSMutableString>().bar(a, b))
false
true
true
true
NSObject
の ==
は static func
っぽいけど何が起こってるの??
static func == (lhs: NSObject, rhs: NSObject) -> Bool
https://developer.apple.com/documentation/objectivec/nsobject/2983393 (edited)NSObject
の ==
は static func
っぽいけど何が起こってるの??
static func == (lhs: NSObject, rhs: NSObject) -> Bool
https://developer.apple.com/documentation/objectivec/nsobject/2983393 (edited)isEqual
がオーバーライドされてるのか。[NSString isEqualToString:]
で比較してたから特に違和感なかったけど、Swiftでvar a: NSString
を ==
で比較するのはめっちゃ違和感ありますね・・・==
で同値比較する感覚にもう馴染んだなあ.framework
をマルチアーキテクチャするだけのものだと考えると無理ですよねえ。.framework
は中に.framework
を入れられるのでmacOSだといけるんじゃないかな。let foo: [Character] = Array("Hello, World")
print(foo)
let foo: [Character] = Array("Hello, World")
print(foo)
["H", "e", "l", "l", "o", ",", " ", "W", "o", "r", "l", "d"]
Array
が暗黙的に[Character]
に変換される挙動なんてあったんですねString.Element
のArrayが出てきてるだけかlet bar: [Character] = "Hello, World"
ができないのでそうみたいですね。.map
とかvalidになってしまってよくわからないハマりがたまに起きるwwithExtendedLifetime
のasync版が無いのっていいのかねfunc _fixLifetime<T>(_ x: T)
を直接使うかwithExtendedLifetime(x) { _ in }
で一応代用できるはず、たぶん_fixLifetime
ってstdlib用だと思ってた、ほんとだシンボル見えてるなwithExtendedLifetime(x) { _ in }
←これわかるんだけど、その用法って同期関数でもできるよねfixLifetime
のほうがわかりやすいのに、なんでスコープ関数の withExtendedLifetime
が標準で提供されているのかがよくわからないfixLifetime
だけだったら、最初からasyncも対応できるし。enum E {
case a
case b
}
func body(e: E) {
// OK
if case .a = e {
print("a")
}
// なにこれ?
if case e = .a {
print("a")
}
}
E.a
だったらコンパイルできるので本題としては同じですがlet x = 42
let a = Int(readLine()!)!
switch a {
case .zero:
Print("0")
case x:
print("42")
default:
print("Other")
}
case x
のパターンみたいなもの?let x = 42
let a = Int(readLine()!)!
switch a {
case .zero:
Print("0")
case x:
print("42")
default:
print("Other")
}
switch E.a {
case e:
print("a")
default:
break
}
こういう解釈になる?if a == b
を if case a = b
と書けるって事か? (edited)func eq<T>(a: T, b: T) -> Bool{
if case a = b {
return true
} else {
return false
}
}
func eq<T>(a: T, b: T) -> Bool{
if case a = b {
return true
} else {
return false
}
}
<stdin>:2:13: error: operator function '~=' requires that 'T' conform to 'Equatable'
if case a = b {
^
Swift.~=:1:13: note: where 'T' = 'T'
public func ~= <T>(a: T, b: T) -> Bool where T : Equatable
^
~=
が提供されてるから case a = b
で書けるってことかlet v = if Bool.random() { "World" } else { nil }
print(type(of: v))
let v2 = Bool.random() ? "World" : nil
print(type(of: v2))
let v = if Bool.random() { "World" } else { nil }
print(type(of: v))
let v2 = Bool.random() ? "World" : nil
print(type(of: v2))
<stdin>:1:45: error: 'nil' requires a contextual type
let v = if Bool.random() { "World" } else { nil }
^
<stdin>:2:1: error: type of expression is ambiguous without a type annotation
print(type(of: v))
^~~~~~~~~~~~~~~~~~
if foo { "bar" } else { nil }
.some("bar")
でいけるのか?let v = if Bool.random() { "World" } else { .none }
let v2 = if Bool.random() { .some("World") } else { nil }
let v3: String? = if Bool.random() { "World" } else { nil }
(edited)let v = if Bool.random() { "World" } else { .none }
let v2 = if Bool.random() { .some("World") } else { nil }
let v3: String? = if Bool.random() { "World" } else { nil }
(edited)<stdin>:1:46: error: cannot infer contextual base in reference to member 'none'
let v = if Bool.random() { "World" } else { .none }
~^~~~
<stdin>:2:30: error: cannot infer contextual base in reference to member 'some'
let v2 = if Bool.random() { .some("World") } else { nil }
~^~~~
(edited)let v = if Bool.random() { "World" } else { nil } as String?
let v = if Bool.random() { "World" } else { nil } as String?
let str = "abc"
str.withCString {
print(String(format: "%8s", $0))
}
print(String(format: "%8@", str))
%s
なら幅指定子が使えるのに %@
だと使えない・・・error: unable to invoke subcommand: swift-起きて (No such file or directory)
let str = "abc"
str.withCString {
print(String(format: "%8s", $0))
}
print(String(format: "%8@", str))
<stdin>:3:17: error: incorrect argument labels in call (have 'format:_:', expected 'repeating:count:')
print(String(format: "%8s", $0))
^~~~~~~
import Foundation
let str = "abc"
str.withCString {
print(String(format: "%8s", $0))
}
print(String(format: "%8@", str))
import Foundation
let str = "abc"
str.withCString {
print(String(format: "%8s", $0))
}
print(String(format: "%8@", str))
abc
abc
%8@
みたいな指定って昔ありましたっけ…?%02d
とかがよく使うと思うけど%@
だけなぜか使えない。%@
が使えるのは ObjC です。printf
が多分元祖で大昔からあって@
を追加したわけです。 (edited)%02d
とかはよく整形する時に使ってましたけど、%@
にそれ使うの見た覚えがなくて %02d
とかはよく整形する時に使ってましたけど、%@
にそれ使うの見た覚えがなくて %8@
もできないとダメだと思うけどなあ%@
はそれとは関係ないよ、って感じになってますな%@
はあくまでObj-Cの拡張だから…かなwimport Foundation
print("\\".withCString { String(format: "%s", $0) })
import Foundation
print("\\".withCString { String(format: "%s", $0) })
\
import Foundation
print("あいう".withCString { String(format: "%s", $0) })
import Foundation
print("あいう".withCString { String(format: "%s", $0) })
あいう
%s
と同じように、幅指定子でスペースを挿入してやる事は仕組みとしてはできると思います。 (edited)String
の format
あり init
は未実装みたいですが)any P
は : P
ではないけど、 any Sendable
だけは : Sendable
ですね。struct S {
var a: Int
init(cond: Bool) {
if cond {
a = 1
// self ok (1)
foo()
}
a = 2
// self ok (2)
foo()
}
func foo() {}
}
知らなかった。!Copyable
ではなく ~Copyable
なのか謎に思ったのですが、なるほど厳密には「Copyable
ではない」じゃなくて「Copyable
の保証がない」の意味だったかfunc XCTAssertEqual<T: Equatable>(_ a: T, _ b: T) {
guard a == b else {
print("\(a) != \(b)")
return
}
}
// コ + 半角濁点
let s = "\u{30B3}\u{FF9E}"
XCTAssertEqual(s.unicodeScalars.count, 2)
XCTAssertEqual(s.count, 1)
let indices: [String.Index] = Array(s.indices) + [s.endIndex]
XCTAssertEqual(indices.count, 2)
let range: Range<String.Index> = s.rangeOfCharacter(from: chars)!
XCTAssertEqual(indices.contains(range.lowerBound), true)
XCTAssertEqual(indices.contains(range.upperBound), false) // !?
func XCTAssertEqual<T: Equatable>(_ a: T, _ b: T) {
guard a == b else {
print("\(a) != \(b)")
return
}
}
// コ + 半角濁点
let s = "\u{30B3}\u{FF9E}"
XCTAssertEqual(s.unicodeScalars.count, 2)
XCTAssertEqual(s.count, 1)
let indices: [String.Index] = Array(s.indices) + [s.endIndex]
XCTAssertEqual(indices.count, 2)
let range: Range<String.Index> = s.rangeOfCharacter(from: chars)!
XCTAssertEqual(indices.contains(range.lowerBound), true)
XCTAssertEqual(indices.contains(range.upperBound), false) // !?
<stdin>:17:71: error: cannot find 'chars' in scope
let range: Range<String.Index> = s.rangeOfCharacter(from: chars)!
^~~~~
<stdin>:17:48: error: value of type 'String' has no member 'rangeOfCharacter'
let range: Range<String.Index> = s.rangeOfCharacter(from: chars)!
~ ^~~~~~~~~~~~~~~~
import Foundation
func XCTAssertEqual<T: Equatable>(_ a: T, _ b: T) {
guard a == b else {
print("\(a) != \(b)")
return
}
}
// コ + 半角濁点
let s = "\u{30B3}\u{FF9E}"
XCTAssertEqual(s.unicodeScalars.count, 2)
XCTAssertEqual(s.count, 1)
let indices: [String.Index] = Array(s.indices) + [s.endIndex]
XCTAssertEqual(indices.count, 2)
let chars = CharacterSet(charactersIn: "ァ"..."ヺ")
let range: Range<String.Index> = s.rangeOfCharacter(from: chars)!
XCTAssertEqual(indices.contains(range.lowerBound), true)
XCTAssertEqual(indices.contains(range.upperBound), false) // !?
import Foundation
func XCTAssertEqual<T: Equatable>(_ a: T, _ b: T) {
guard a == b else {
print("\(a) != \(b)")
return
}
}
// コ + 半角濁点
let s = "\u{30B3}\u{FF9E}"
XCTAssertEqual(s.unicodeScalars.count, 2)
XCTAssertEqual(s.count, 1)
let indices: [String.Index] = Array(s.indices) + [s.endIndex]
XCTAssertEqual(indices.count, 2)
let chars = CharacterSet(charactersIn: "ァ"..."ヺ")
let range: Range<String.Index> = s.rangeOfCharacter(from: chars)!
XCTAssertEqual(indices.contains(range.lowerBound), true)
XCTAssertEqual(indices.contains(range.upperBound), false) // !?
s[]
に渡したら濁点だけ取り出せたlet s = "\u{30B3}\u{FF9E}"
let su = s.unicodeScalars
let i0 = su.startIndex
let i1 = su.index(su.startIndex, offsetBy: 1)
let i2 = su.index(su.startIndex, offsetBy: 2)
print(s.distance(from: s.startIndex, to: i0))
print(s.distance(from: s.startIndex, to: i1))
print(s.distance(from: s.startIndex, to: i2))
print(i0 < i1)
print(i1 < i2)
print(i2 == s.endIndex)
let s = "\u{30B3}\u{FF9E}"
let su = s.unicodeScalars
let i0 = su.startIndex
let i1 = su.index(su.startIndex, offsetBy: 1)
let i2 = su.index(su.startIndex, offsetBy: 2)
print(s.distance(from: s.startIndex, to: i0))
print(s.distance(from: s.startIndex, to: i1))
print(s.distance(from: s.startIndex, to: i2))
print(i0 < i1)
print(i1 < i2)
print(i2 == s.endIndex)
0
0
1
true
true
true
let s = "\u{30B3}\u{FF9E}"
let su = s.unicodeScalars
let i0 = su.startIndex
let i1 = su.index(su.startIndex, offsetBy: 1)
let i2 = su.index(su.startIndex, offsetBy: 2)
print(s.distance(from: s.startIndex, to: i0))
print(s.distance(from: s.startIndex, to: i1))
print(s.distance(from: s.startIndex, to: i2))
print(i0 < i1)
print(i1 < i2)
print(i2 == s.endIndex)
print(su.distance(from: su.startIndex, to: i0))
print(su.distance(from: su.startIndex, to: i1))
print(su.distance(from: su.startIndex, to: i2))
(edited)let s = "\u{30B3}\u{FF9E}"
let su = s.unicodeScalars
let i0 = su.startIndex
let i1 = su.index(su.startIndex, offsetBy: 1)
let i2 = su.index(su.startIndex, offsetBy: 2)
print(s.distance(from: s.startIndex, to: i0))
print(s.distance(from: s.startIndex, to: i1))
print(s.distance(from: s.startIndex, to: i2))
print(i0 < i1)
print(i1 < i2)
print(i2 == s.endIndex)
print(su.distance(from: su.startIndex, to: i0))
print(su.distance(from: su.startIndex, to: i1))
print(su.distance(from: su.startIndex, to: i2))
(edited)0
0
1
true
true
true
0
1
2
(edited)func takeSendableClosure(_ c: @Sendable () -> ()) {}
let nonSendable: () -> () = {}
takeSendableClosure(nonSendable) // 警告出る
struct S {
var nonSendableValue: () -> ()
@Sendable func mayUseNonSendableValue() {
nonSendableValue()
}
}
var s = S(nonSendableValue: {})
takeSendableClosure(s.mayUseNonSendableValue) // 警告出ない
(edited)@Sendable
つけるだけで@Sendable
なクロージャとして扱えてしまうんですが、これって正しいんでしょうかね?import Foundation
func takeSendableClosure(_ c: @Sendable @escaping () -> ()) {
Task.detached(operation: c)
}
let nonSendable: () -> () = {}
takeSendableClosure(nonSendable) // 警告出る
struct S {
var nonSendableValue: () -> ()
@Sendable func mayUseNonSendableValue() {
nonSendableValue()
}
}
var count = 0
var s = S(nonSendableValue: {
count += 1
})
takeSendableClosure(s.mayUseNonSendableValue) // 警告出ない
for _ in 0..<10000 {
takeSendableClosure(s.mayUseNonSendableValue)
}
print(count)
sleep(1)
print(count)
(edited)import Foundation
func takeSendableClosure(_ c: @Sendable @escaping () -> ()) {
Task.detached(operation: c)
}
let nonSendable: () -> () = {}
takeSendableClosure(nonSendable) // 警告出る
struct S {
var nonSendableValue: () -> ()
@Sendable func mayUseNonSendableValue() {
nonSendableValue()
}
}
var count = 0
var s = S(nonSendableValue: {
count += 1
})
takeSendableClosure(s.mayUseNonSendableValue) // 警告出ない
for _ in 0..<10000 {
takeSendableClosure(s.mayUseNonSendableValue)
}
print(count)
sleep(1)
print(count)
(edited)9745
9999
<stdin>:7:21: warning: converting non-sendable function value to '@Sendable () -> ()' may introduce data races
takeSendableClosure(nonSendable) // 警告出る
(edited)S
がSendableである上で、funcについた@Sendable
が認められるべきかなと (edited)import Foundation
func takeSendableClosure(_ c: @Sendable @escaping () -> ()) {
Task.detached(operation: c)
}
let nonSendable: () -> () = {}
takeSendableClosure(nonSendable) // 警告出る
struct S {
var nonSendableValue: () -> ()
@Sendable func mayUseNonSendableValue() {
nonSendableValue()
}
}
var count = 0
var s = S(nonSendableValue: {
count += 1
})
takeSendableClosure(s.mayUseNonSendableValue) // 警告出ない
for _ in 0..<10000 {
takeSendableClosure(s.mayUseNonSendableValue)
}
print(count)
sleep(1)
print(count)
import Foundation
func takeSendableClosure(_ c: @Sendable @escaping () -> ()) {
Task.detached(operation: c)
}
let nonSendable: () -> () = {}
takeSendableClosure(nonSendable) // 警告出る
struct S {
var nonSendableValue: () -> ()
@Sendable func mayUseNonSendableValue() {
nonSendableValue()
}
}
var count = 0
var s = S(nonSendableValue: {
count += 1
})
takeSendableClosure(s.mayUseNonSendableValue) // 警告出ない
for _ in 0..<10000 {
takeSendableClosure(s.mayUseNonSendableValue)
}
print(count)
sleep(1)
print(count)
9798
9977
<stdin>:7:21: warning: converting non-sendable function value to '@Sendable () -> ()' may introduce data races
takeSendableClosure(nonSendable) // 警告出る
<stdin>:11:3: warning: instance methods of non-Sendable types cannot be marked as '@Sendable'; this is an error in Swift 6
@Sendable func mayUseNonSendableValue() {
^
Text("Swift!")
.bold() // OK
Text("Swift!")
bold() // OK!ただし実行時エラー
Text("Swift!")
bold() // OK!ただし実行時エラー
bold()
単体はなんで通るんだbold()
がsome View
に生えてるせいでself.bold()
になってるself.
の省略形としてコンパイル通っちゃうは、一般性があるなCGFloat
の生の +inf
か。へえ〜func f() async {}
async let a = f()
await a
func f() async {}
async let a = f()
await a
<stdin>:3:11: warning: constant 'a' inferred to have type '()', which may be unexpected
async let a = f()
^
<stdin>:3:11: note: add an explicit type annotation to silence this warning
async let a = f()
^
: ()
func f() {
defer {
Task {
print("defer:", value)
}
}
let value = 42
}
f()
func f() {
defer {
Task {
print("defer:", value)
}
}
let value = 42
}
f()
func `do`(_ c: () -> ()) {
c()
}
func f() {
defer {
`do` {
print("defer:", value)
}
}
let value = 42
}
f()
func `do`(_ c: () -> ()) {
c()
}
func f() {
defer {
`do` {
print("defer:", value)
}
}
let value = 42
}
f()
defer: 42
func foo(
arg0: String = "\(#function)",
arg1: String = #function
) {
print(arg0)
print(arg1)
}
func main() {
foo()
}
main()
foo(arg0:arg1:)
main()
結果はこうなるんですが、#function
って引数ラベルに書いても直接使わなかった場合は呼び出し側の値が使われないことを初めて知りましたfunc foo(
arg0: String = "\(#function)",
arg1: String = #function
) {
print(arg0)
print(arg1)
}
func main() {
foo()
}
main()
foo(arg0:arg1:)
main()
info: (String, Int) = (#file, #line)
みたいなことをやろうとして同じのを踏みました。不具合かと思っていたら、SE-0422の説明で明示的に書かれていて仕様だったのか……となりました。[1, nil, 3, nil, 5].compactMap(\.self)
self-keypath-as-function.swift:1:32: error: cannot convert value of type 'WritableKeyPath<_, _>' to expected argument type '(Int?) throws -> ElementOfResult?'
[1, nil, 3, nil, 5].compactMap(\.self)
^
self-keypath-as-function.swift:1:21: error: generic parameter 'ElementOfResult' could not be inferred
[1, nil, 3, nil, 5].compactMap(\.self)
^
Swift.Sequence:2:28: note: in call to function 'compactMap'
@inlinable public func compactMap<ElementOfResult>(_ transform: (Self.Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult]
^
self-keypath-as-function.swift:1:32: error: cannot infer key path type from context; consider explicitly specifying a root type
[1, nil, 3, nil, 5].compactMap(\.self)
^
<#Root#>
推論に問題がありそう?\.self
が対応してないのかと思ったけど、↓だと通る。
let values: [Int] = [2, 3, 5]
let convert: (Int) -> Int = \.self
let result: [Int] = values.map(convert)
print(result)
\.self
は実装当初からできないんですよねprint([1, nil, 3, nil, 5].compactMap(\.self))
print([1, nil, 3, nil, 5].compactMap(\.self))
<stdin>:1:38: error: cannot convert value of type 'WritableKeyPath<_, _>' to expected argument type '(Int?) throws -> ElementOfResult?'
print([1, nil, 3, nil, 5].compactMap(\.self))
^
<stdin>:1:27: error: generic parameter 'ElementOfResult' could not be inferred
print([1, nil, 3, nil, 5].compactMap(\.self))
^
Swift.Sequence:2:28: note: in call to function 'compactMap'
@inlinable public func compactMap<ElementOfResult>(_ transform: (Self.Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult]
^
<stdin>:1:38: error: cannot infer key path type from context; consider explicitly specifying a root type
print([1, nil, 3, nil, 5].compactMap(\.self))
^
<#Root#>
\.self
は実装当初からできないんですよね let convert: (Int) -> Int = \.self
print([1, nil, 3, nil, 5].compactMap(\.self))
print([1, nil, 3, nil, 5].compactMap(\.self))
[1, 3, 5]
#54861
はトラッキングが漏れててcloseされてないだけで #55343
で治ったんだなprotocol P {
nonisolated func foo()
func bar()
}
struct S: P {
func foo() {}
func bar() {}
}
actor A: P {
// NG
// func foo() {}
nonisolated func foo() {}
// NG
// func bar() {}
nonisolated func bar() {}
}
protocol P: Actor {
nonisolated func foo()
func bar()
}
actor A: P {
// NG
// func foo() {}
nonisolated func foo() {}
// OK
func bar() {}
}
P: AnyActor
だと変化なし P: Actor
で変化したInferSendableFromCaptures
が実装されているのが 6.0 からになっていて[0, 1, 2, 3, 4, 5].reduce(0, +) // { $0 + $1 }ではなく+だけでいい
人に説明するとき困ってしまって… (edited)func say(_ text: String) { print(text) }
["Hello", "こんにちは"].forEach(say)
.forEach(say)
や .reduce(0, +)
が高階関数の基本的な使い方で、クロージャを渡すのが特殊例で、Trailing Closureはさらに特殊な例だと思います。// 関数を引数に渡せる関数を高階関数と言います。
[0, 1, 2, 3, 4, 5].reduce(0, add)
// Swiftでは演算子も関数なので演算子も渡せます。
[0, 1, 2, 3, 4, 5].reduce(0, +)
// その場でクロージャを宣言して渡すこともできます。
[0, 1, 2, 3, 4, 5].reduce(0, {$0 + $1})
// 末尾のクロージャ引数は()の外に出すことができ、Trailing Closureと呼ばれます。
[0, 1, 2, 3, 4, 5].reduce(0) {$0 + $1}
という順序の話だと思うので、最初の方の例には名前は付いていない(標準的な高階関数の例)なんじゃないでしょうか。 (edited)+
だけ記述するのが普通で、
クロージャーで { $0 + $1 }
とか書くのがイレギュラーパターンだったってことなんですね。 (edited)struct Foo: Encodable { // Type 'Foo' does not conform to protocol 'Encodable'
let value: Encodable
}
encodeを実装したら解消しましたが、これも理由が説明できず。
やりたいことは実現でましたがモヤモヤしています。
struct Foo: Encodable {
let value: Encodable
enum CodingKeys: String, CodingKey {
case value
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(value, forKey: .value)
}
}
let data = try! JSONEncoder().encode([Foo(value: 10), Foo(value: "bar")])
let json = String(data: data, encoding: .utf8)! // [{"value":10},{"value":"bar"}]
try container.encode(value, forKey: .value)
)に渡せるのって仕様的に整合性が取れていないように思えるのですが、これは整合性が取れているのでしょうか?[0, 1, 2, 3, 4, 5].reduce(0, +) // { $0 + $1 }ではなく+だけでいい
人に説明するとき困ってしまって… (edited)@objc
つけて、 ObjC として WebKit 側にエクスポートしているコードをlit
じゃん。この手があったか。func foo(a: Any, b: AnyHashable) {
// Intが出てくる
print(type(of: a))
// Intにキャストできる
print(a as? Int)
// AnyHashableにしか見えない
print(type(of: b))
// Intにキャストできる(なんで?)
print(b as? Int)
// AnyHashable.base は Any型で、Intが出てくる
// これを使えばAnyとの挙動の違いを避けられる
print(type(of: b.base))
// キャストできる
print(b.base as? Int)
}
foo(a: 1, b: 1)
Int
Optional(1)
AnyHashable
Optional(1)
Int
Optional(1)
Program ended with exit code: 0
(edited).base
生えてるの知らなかったわ、今両方知ったAny
は any protocol<>
だから、一級のerasureで、AnyHashable
自体はstructだからなぁas
の挙動だな_ObjectiveCBrideable
とかはあるけどInt -> AnyHashable
のキャストがありえるのであれば AnyHashable as? Int
があっても不思議じゃないAnyHashable
は用済みになるのかなーany Hashable
なら self conformance で作れそうだけどany Hashable
と AnyHashable
の使い分け問題が出てくるんだよなNSDictionary
の interop があるから後者をdeprecatedにもできないし・・・_CJavaScriptKit
の _set_prop
とかのインターフェースの場合、
C API の RawJSValue
とか JavaScriptPayload1
とかに対応しないといけないから、残念ながらめんどくさそう
DOMの描画部分で必要な機能だけでいいから手抜きでMockを書いちゃった方が早そうだ (edited)RawJSValue
じゃなくてもうちょっと上のところでSwiftの型のインターフェースで差し込めるようになってる必要があると思う (edited)[Any]
を Any...
に渡すことができるけど、
[Int]
は Int...
に渡すことができない。anys: [Any]
の要素が、可変長引数に一個ずつ展開される takeVariadicAny(ints)
// (offset: 0, element: [4, 5, 6])
[Int]
の場合は、1個の配列として渡る。 takeVariadicAny(ints as [Any])
(offset: 0, element: 4)
(offset: 1, element: 5)
(offset: 2, element: 6)
package
visibility便利だな・・・ swiftLanguageVersions: [.v5]
でいいんですかね.enableUpcomingFeature("InternalImportsByDefault")
が全く機能していない気がする .enableExperimentalFeature("AccessLevelOnImport"),
.enableUpcomingFeature("InternalImportsByDefault")
これセットで使ってたけど多分動作していなくて.v5
にしてもその挙動変わらなくてエラーがたくさん出るぞ swiftLanguageVersions: [.v5]
でいいんですかね -swift-version 5
が設定されているけど、importの挙動が切り替わっていない.enableUpcomingFeature("InternalImportsByDefault")
が全く機能していない気がする InternalImportsByDefault
は ship されてないですよ.
https://github.com/apple/swift/blob/release/5.10/include/swift/Basic/Features.defInternalImportsByDefault
は Language Steering Group で方針転換があって Swift 6 じゃなくて Swift 7 に見送られたみたいです.
https://github.com/apple/swift/pull/73149 swiftLanguageVersions: [.v5]
が指定されていないけど// swift-tools-version:
によって変わったりするのかなあ?- Stored properties of Sendable type in a global-actor-isolated value type can be declared as nonisolated without using (unsafe).
- Stored properties of Sendable type in a global-actor-isolated value type are treated as nonisolated when used within the module that defines the property.
- @Sendable is inferred for global-actor-isolated functions and closures.
- Global-actor-isolated closures are allowed to capture non-Sendable values despite being @Sendable.
- A global-actor-isolated subclass of a non-isolated, non-Sendable class is allowed, but it must be non-Sendable
@available(*, noasync)
を付けると警告が出せるらしいpublic typealias Validated<Value> = Result<Value, InputErrorCollection>
extension Validated where Failure == InputErrorCollection {
このwhereが必要なのバグっぽいstruct Value{}
struct InputErrorCollection: Error {}
struct OtherError: Error {}
typealias Validated<Value> = Result<Value, InputErrorCollection>
extension Validated where Failure == OtherError {
func hoge() { print("OK???") }
}
struct Value{}
struct InputErrorCollection: Error {}
struct OtherError: Error {}
typealias Validated<Value> = Result<Value, InputErrorCollection>
extension Validated where Failure == OtherError {
func hoge() { print("OK???") }
}
extension AsyncIteratorProtocol {
/// Default implementation of `next(isolation:)` in terms of `next()`, which is
/// required to maintain backward compatibility with existing async iterators.
@available(SwiftStdlib 6.0, *)
@available(*, deprecated, message: "Provide an implementation of 'next(isolation:)'")
public mutating func next(isolation actor: isolated (any Actor)?) async throws(Failure) -> Element? {
nonisolated(unsafe) var unsafeIterator = self
do {
let element = try await unsafeIterator.next()
self = unsafeIterator
return element
} catch {
throw error as! Failure
}
}
}
(edited)extension Result where Success: ~Copyable {
/// Creates a new result by evaluating a throwing closure, capturing the
/// returned value as a success, or any thrown error as a failure.
///
/// - Parameter body: A potentially throwing closure to evaluate.
@_alwaysEmitIntoClient
public init(catching body: () throws(Failure) -> Success) {
do {
self = .success(try body())
} catch {
self = .failure(error)
}
}
}
throws(Failure)
になってるから、それができないならこのシグネチャになってる意味がないので、推論器が未実装なんだと思います。Any
を書く以外で empty protocol composition を表現する方法って存在するのでしょうか?
https://github.com/apple/swift/pull/7222#discussion_r99262673protocol<>
は.@available(*, deprecated, renamed:)
使うとコンパイラがクラッシュするなんてあるんですね・・・@available(*, unavailable, renamed:)
では踏んだことがないですが,何がトリガーなのか気になりますね.protocol P<A> {
associatedtype A
}
protocol Q {}
func f(_ v: any P<Int>) {}
func g(_ v: any (P<Int> & Q)) {}
func h(_ v: any (P & Q)) {}
(edited)protocol P<A> {
associatedtype A
}
protocol Q {}
func f(_ v: any P<Int>) {}
func g(_ v: any (P<Int> & Q)) {}
func h(_ v: any (P & Q)) {}
(edited)<stdin>:6:18: error: non-protocol, non-class type 'P<Int>' cannot be used within a protocol-constrained type
4 | protocol Q {}
5 | func f(_ v: any P<Int>) {}
6 | func g(_ v: any (P<Int> & Q)) {}
| `- error: non-protocol, non-class type 'P<Int>' cannot be used within a protocol-constrained type
7 | func h(_ v: any (P & Q)) {}
8 |
(edited)= .a
に反応してるんですが、問題があるとは思えないfoo(e: .a)
なら怒られないし。self
を暗黙的に定義する方法って、guard let self else { ... }
を定義する(SE-0365)以外に何かあるでしょうか? (edited)