Reputation: 4819
Let's say I have this code:
func hello<T>(thing: T) -> String {
return "hello \(thing)"
}
Can I write a version of the hello
function that won't compile if it's passed an optional?
let foo = "some"
let bar: String? = nil
print(helloNoOptional(foo)) // should compile
print(helloNoOptional(bar)) // should not compile
I'm thinking maybe it's doable with a protocol conformance or where
clause on T but I can't think of how exactly that would work.
The reason I want to do this is because I'm dealing with a actual function in legacy codebase that has no sensible behavior if thing
is nil. So I'd rather prevent hello
from being called on an optional rather than deal with unwrapping thing
inside of hello and trying to figure out a sensible error behavior.
Update:
A possible path...I realized that the Optional enum conforms to the NilLiteralConvertible
protocol. So if I can find a way to constrain my generic to not conform to a type, I can exclude optionals de facto. But I don't know if it's possible to do something like
<T where !T: NilLiteralConvertible>
Upvotes: 18
Views: 2065
Reputation: 30428
Building on @Airspeed Velocity's answer, I personally prefer to keep everything in one place, like so...
func hello<T>(_ thing: T) -> String {
if T.self is ExpressibleByNilLiteral.Type {
fatalError("Optional types not supported")
}
return "hello \(thing)"
}
Upvotes: 1
Reputation: 40963
Best I can think of is overload and check at runtime:
func hello<T>(thing: T) -> String {
return "hello \(thing)"
}
fun hello<T>(thing: T?) -> String {
fatalError("No optionals allowed!")
}
hello("swift") // fine
hello(2) // fine
hello(Int("2")) // fatal error
But I don't know of a way of generating a compile-time error instead.
Upvotes: 5