Skip to content

Instantly share code, notes, and snippets.

@airspeedswift
Last active August 29, 2015 14:23
Show Gist options
  • Save airspeedswift/11209c7cbf6b608583e0 to your computer and use it in GitHub Desktop.
Save airspeedswift/11209c7cbf6b608583e0 to your computer and use it in GitHub Desktop.
toString vs String.init
/*:
You used to be able to do this:
[anything].map(toString)
but then String() replaced toString,
which meant you had to write
[anything].map { String($0) }
2.0b2 introduced referring to initializers as static methods
like so:
let oneTwoThree = [1, 2, 3].map(String.init).reduce("", combine: +)
but this doesn't mean String.init can replace toString because...
*/
struct One {
// just one generic constructor
init<T>(_ unnamed: T) {
print("created with a \(T.self)")
}
init(_ i: Int) {
// just to show this doesn't interfere
print("created with an Int")
}
}
One("foo")
One.init("foo")
One.init(1)
// a totally generic constructor is fine, so long
// as it can tell what T is...
let f = One.init as String->One
let x = f("foo")
struct Two {
init<T>(_ unnamed: T) {
print("created with a \(T.self)")
}
init<T>(named: T) {
print("created with a named \(T.self)")
}
}
Two("foo") // fine
Two(named: "foo") // fine
//: But this doesn't work, because names of values aren't part of the type in
//: the same way the types themselves are...
//let g = Two.init as String->Two // nope, ambiguous
//let h = Two.init as (named: String)->Two // also nope
//: Only way I know of to fix is... back to a wrapping closure
let g = { Two($0) } as String->Two
let h = { Two(named: $0) } as String->Two
g("foo")
h("foo")
//: or reintroduce toString
func toTwo<T>(t: T) -> Two { return Two(t) }
func toDebugTwo<T>(t: T) -> Two { return Two(named: t) }
let k = toTwo as String->Two
let m = toDebugTwo as String->Two
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment