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 の方向性は正しかったんだ〜/
書く時はトラウマが呼び起こされてミスしない体になった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:
入れると勝手に 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 はできないんですね…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
になってる・・・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