Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I constrain a generic parameter to *not* be optional?

Tags:

generics

swift

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>
like image 901
rogueleaderr Avatar asked Dec 15 '15 21:12

rogueleaderr


People also ask

Can generic classes be constrained?

You can constrain the generic type by interface, thereby allowing only classes that implement that interface or classes that inherit from classes that implement the interface as the type parameter.

What are generic constraints?

The where clause in a generic definition specifies constraints on the types that are used as arguments for type parameters in a generic type, method, delegate, or local function. Constraints can specify interfaces, base classes, or require a generic type to be a reference, value, or unmanaged type.

What is generic type parameter in C#?

The type parameter is a placeholder for a specific type that the client specifies when they create an instance of the generic type. A generic class cannot be used as-is because it is simply a blueprint for that type.


1 Answers

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.

like image 197
Airspeed Velocity Avatar answered Sep 20 '22 16:09

Airspeed Velocity