How to use strings as printable stuff in Swift
I am trying to write a function that takes a parameter of type Printable:
func logMessage(message: Printable) {
// ...
}
Strange, it doesn't work as expected when passed in Strings.
This won't compile:
logMessage("some string \(someVariable)")
// Neither does this:
let aString = "aString"
logMessage(aString)
This, however, compiles:
logMessage("A string")
// This works too:
let aString: Printable = "a string"
logMessage(aString)
It's pretty confusing. It seems that in some cases String implements Printable and in others it does not.
Also, it seems that string-interpolation always produces a string that doesn't implement Printable. This leads to runtime crashes with a cast error:
let aString = "a string"
let interpolatedString = "contains \(aString)"
Any idea what's going on here?
source to share
You are right that String
does not correspond Printable
. The reason this compiles is:
let aString: Printable = "Ceci n'est pas une String"
is that you don't create String
with that literal - you create NSString
(which Printable
).
As a general rule, in Swift it is usually better to write general protocol-limited functions. Therefore, instead of
func logMessage(message: Printable) {
// ...
}
you are probably better off writing:
func logMessage<T: Printable>(message: T) {
// ...
}
This approach has several advantages: better security type and style erasure prevention, better performance, etc. You can read more about this stuff here .
But you will still run into a problem because you cannot get through String
. You have two options. First, just don't limit it at all:
func logMessage<T>(message: T) {
// ...then use toString(message) to create a String if you need one,
// or use string interpolation or print()
}
This will work with String
, and in fact will work with anyone that isnt Printable
(although you will end up with completely useless output associated with a malformed class name).
Or you can use Streamable
whose lines match:
func logMessage<T: Streamable>(message: T) {
println(message)
}
let s: String = "hello"
logMessage(s)
I think I have been reading on twitter for a while, one of the Swift teams mentions that the reason is String
not consistent Printable
, precisely because they didn't want people using Printable
, just like that, it's better to always use it toString
or similar.
source to share