[swift-users] How to store ref to any kind of function, and call with it argument list?
C. Keith Ray
keithray at mac.com
Sun Nov 5 12:26:54 CST 2017
Thanks, that's working for me, though I have to specify the return type explicitly to avoid compile error.
typealias TwoArgsFunction = (Any,Any)->Any
func intToInt(_ i: Int, d: Double) -> Int {
print("intToInt \(i) \(d)")
return 4
}
func typeEraseTwo<Arg1T,Arg2T,R>(r: R.Type,
fn: @escaping (Arg1T,Arg2T)->R) -> TwoArgsFunction {
return {
guard let arg1 = $0 as? Arg1T else {
fatalError("\(Arg1T.self) wrong type \(type(of:$0)) \($0) ")
}
guard let arg2 = $1 as? Arg2T else {
fatalError("\(Arg2T.self) wrong type \(type(of:$1)) \($1) ")
}
return fn(arg1, arg2)
}
}
var function : TwoArgsFunction = typeEraseTwo(r: Int.self, fn: intToInt)
let r = function(12, 5.5)
print(r)
// prints "intToInt 12 5.5" and "4"
...and Xcode just crashed while I was typing in a playground.
--
C. Keith Ray
Senior Software Engineer / Trainer / Agile Coach
* http://www.thirdfoundationsw.com/keith_ray_resume_2014_long.pdf
> On Nov 3, 2017, at 10:31 PM, Slava Pestov <spestov at apple.com> wrote:
>
> (Int) -> Int is not a subtype of (Any) -> Any, because a value of the latter type can be called with an argument type that is not an Int, for example a String:
>
> let fn: (Int) -> Int = …
> let fn2 = (Any) -> Any = fn // pretend this works
>
> fn2(“hi”) // what does this do?
>
> I think you’ll need to do something with generics where you wrap the original function value in a thunk that tests the argument type first, eg
>
> func erase<T, U>(fn: (T) -> U) -> (Any) -> Any {
> return { any in fn(arg as! T) }
> }
>
> I haven’t thought this through properly since it’s late, but it might be a good starting point.
>
> Slava
>
>> On Nov 3, 2017, at 7:01 PM, C. Keith Ray <keithray at mac.com <mailto:keithray at mac.com>> wrote:
>>
>> um... how can I cast functions taking one argument to a "generic function pointer" type?
>>
>> typealias OneArgsFunction = (Any)->Any
>>
>> func intToInt(_ i: Int) -> Int { return 4 }
>> func floatToFloat(_ f: Float) -> Float { return 0.4 }
>>
>> var function : OneArgsFunction = intToInt
>> function = floatToFloat
>>
>> error: f.playground:4:34: error: cannot convert value of type '(Int) -> Int' to specified type 'OneArgsFunction' (aka '(Any) -> Any')
>> var function : OneArgsFunction = intToInt
>> ^~~~~~~~
>>
>> error: f.playground:5:12: error: cannot assign value of type '(Float) -> Float' to type 'OneArgsFunction' (aka '(Any) -> Any')
>> function = floatToFloat
>> ^~~~~~~~~~~~
>>
>>
>> --
>> C. Keith Ray
>> Senior Software Engineer / Trainer / Agile Coach
>> * http://www.thirdfoundationsw.com/keith_ray_resume_2014_long.pdf <http://www.thirdfoundationsw.com/keith_ray_resume_2014_long.pdf>
>>
>>
>>
>>> On Nov 3, 2017, at 2:24 PM, Slava Pestov <spestov at apple.com <mailto:spestov at apple.com>> wrote:
>>>
>>> Unfortunately we don’t have a way to invoke a function with a runtime argument list because that would require runtime code generation in the most general case.
>>>
>>> I would hack around it by handling the common cases of no arguments, 1 argument, 2 arguments, etc up to some fixed number of arguments that you consider “enough”. Use a switch on the type of the function.
>>>
>>> Slava
>>>
>>>> On Nov 3, 2017, at 2:21 PM, C. Keith Ray via swift-users <swift-users at swift.org <mailto:swift-users at swift.org>> wrote:
>>>>
>>>> In the code below, I'm trying to store a reference to a function with any number of arguments, with any return type. And I want to be able to invoke it.
>>>>
>>>> Help?
>>>>
>>>> See the comments with "*******"
>>>>
>>>> typealias Void = ()
>>>>
>>>> func equalTypes(_ me: [Any.Type], _ other: [Any.Type]) -> Bool {
>>>> guard me.count == other.count else { return false }
>>>>
>>>> for i in 0 ..< me.count {
>>>> if me[i] != other[i] { return false }
>>>> }
>>>> return true
>>>> }
>>>>
>>>> struct Function {
>>>> var returnType: Any.Type
>>>> var argTypes: [Any.Type]
>>>> var function: Any // ******* any function *******
>>>>
>>>> func perform(_ args: [Any]) -> Any {
>>>> // ******* call function() with args, return result *******
>>>> return 0
>>>> }
>>>>
>>>> func isCompatible(_ other: Function) -> Bool {
>>>> return self.returnType == other.returnType &&
>>>> equalTypes(argTypes, other.argTypes)
>>>> }
>>>> }
>>>>
>>>> func vToV() {
>>>> print("vToV")
>>>> }
>>>>
>>>> func intToInt(_ i: Int) -> Int {
>>>> print("intToInt")
>>>> return 4
>>>> }
>>>>
>>>> let f = Function(returnType: Void.self,
>>>> argTypes: [],
>>>> function: vToV)
>>>> let r = f.perform([])
>>>> print(r)
>>>>
>>>> let f2 = Function(returnType: Int.self,
>>>> argTypes: [Int.self],
>>>> function: intToInt)
>>>> let r2 = f2.perform([12])
>>>> print(r2)
>>>>
>>>> assert(f.isCompatible(f))
>>>> assert(!f.isCompatible(f2))
>>>>
>>>>
>>>> --
>>>> C. Keith Ray
>>>> Senior Software Engineer / Trainer / Agile Coach
>>>> * http://www.thirdfoundationsw.com/keith_ray_resume_2014_long.pdf <http://www.thirdfoundationsw.com/keith_ray_resume_2014_long.pdf>
>>>>
>>>>
>>>>
>>>> _______________________________________________
>>>> swift-users mailing list
>>>> swift-users at swift.org <mailto:swift-users at swift.org>
>>>> https://lists.swift.org/mailman/listinfo/swift-users <https://lists.swift.org/mailman/listinfo/swift-users>
>>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20171105/37e43e14/attachment.html>
More information about the swift-users
mailing list