Reputation: 23500
I have the following code:
class Function<T> {
var ptr: () throws -> T
init<Func>(block: Func, args: AnyObject...) {
self.ptr = {() throws -> T in
let result: AnyObject? = nil
if T.self == Void.self {
return Void() as! T
}
return result //Error Here.. Cannot as! cast it either.. Cannot unsafeBitCast it either..
}
}
}
postfix operator ^ { }
postfix func ^ <T>(left: Function<T>) throws -> T {
return try left.ptr()
}
func call() {
let block: (String) -> String? = {(arg) -> String? in
return nil
}
let fun = Function<String?>(block: block, args: "Hello")
fun^
}
The function Block.execute
returns AnyObject?
. My Generic class Function<T>
expects a return type of T
.
If T
is already String?
why can't I return nil?
Is there any way to return nil as type T which is already Optional?
If I make T
Optional, then the return type becomes Optional<Optional<String>>
which is not what I want.. then the compiler complains that OptionalOptional
is not unwrapped with ??
That is how I know that T
is already optional.
Upvotes: 3
Views: 1284
Reputation: 452
After a long hunt on google I have finally found an elegant way to do this. It's possible to write a class extension with type constraints.
class Foo<T> {
func bar() -> T {
return something
// Even if T was optional, swift does not allow us to return nil here:
// 'nil' is incompatible with return type 'T'
}
}
extension Foo where T: ExpressibleByNilLiteral {
func bar() -> T {
return nil
// returning nil is now allowed
}
}
The appropriate method will be invoked depending on whether T is optional or not.
Upvotes: 2
Reputation: 444
This does the trick as of Swift 3.1. Modification of user3763801's answer.
func cast<T>(_ v: Any) -> T {
return v as! T
}
Upvotes: 0
Reputation: 395
The following casts Any?
to T
returning nil
only if T
is optional and from
is nil
. It crashes, if from
cannot be cast to T
.
func cast<T>(from v: Any?)->T {
return v as! T
}
func cast<T>(from v: Any?)->T where T: ExpressibleByNilLiteral {
guard let v = v else { return nil }
return v as! T
}
Upvotes: 0
Reputation: 23500
I solved it with a nasty work around.. I throw an exception for nil return type. Then in the generic function operator I catch that specific exception and return nil
if T
is NilLiteralConvertible
.. Otherwise I just execute normally..
class Function<T> {
var ptr: () throws -> T
init<Func>(block: Func, args: AnyObject...) {
self.ptr = {() throws -> T in
let result: AnyObject? = execute(block, args...)
if T.self == Void.self {
return Void() as! T
}
throw BlockError.BlockReturnsNil
}
}
}
postfix func ^ <T>(left: Function<T>) throws -> T {
return try left.ptr()
}
postfix func ^ <T : NilLiteralConvertible>(left: Function<T>) throws -> T {
do {
return try left.ptr()
}
catch BlockError.BlockReturnsNil {
return nil
}
}
Upvotes: 0