ckeithray
(C. Keith Ray)
1
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
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@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
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users
ckeithray
(C. Keith Ray)
3
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
On Nov 3, 2017, at 2:24 PM, Slava Pestov <spestov@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@swift.org <mailto:swift-users@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
_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users
(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@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
On Nov 3, 2017, at 2:24 PM, Slava Pestov <spestov@apple.com <mailto:spestov@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@swift.org <mailto:swift-users@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
_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users
ckeithray
(C. Keith Ray)
5
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@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@mac.com <mailto:keithray@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
On Nov 3, 2017, at 2:24 PM, Slava Pestov <spestov@apple.com <mailto:spestov@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@swift.org <mailto:swift-users@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
_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users