My problem comes from an error handler that I need to write. The handler is meant to catch an error, do an action 'A', and then proceed to retry the original function that failed in the first place. The blocker comes when I need to generalise the handler to be able to accept any function definition.
For example:
fun foo(a: Any) {
// Do something and return null if unsuccessful
}
fun bar(b: Any, c: Any) {
// Do something else and return false if unsuccessful
}
fun handler(fn: Function???, args: Array[arguments???]) {
log.warn("Error has been caught at <${functionName}>, doing action A and retrying")
// Do action A
log.warn("Retrying <${functionName}>")
fn(args)
}
fun main() {
val resultFoo = foo('bar')
if (resultFoo == null) {
handler(foo, ['bar'])
}
val resultBar = bar('foo', { 'foo': 'bar' })
if (!resultBar) {
handler(bar, ['foo', { 'foo': 'bar' }])
}
}
As you can see, I have two functions foo and bar with different definitions which I would like to be able to call from handler. Otherwise I would need to copy-paste the body inside handler to each individual function and handle the error inside there. I was hoping to be able to generalise this and be able to reuse it.
If you want to avoid reflection, which would provide no compile-time error checking, you should overload your function to have variants with different numbers of variables. Then you can use generics, and you'll get compile-time checking.
There's not a clean way to pass functions along with their names, so I made the name for logging a separate argument in this example.
// zero args handler
inline fun <R> handler(loggedFunctionName: String?, fn: ()->R): R {
val functionName = "<$loggedFunctionName>" ?: "function"
log.warn("Error has been caught at $functionName, doing action A and retrying")
// Do action A
log.warn("Retrying $functionName")
return fn()
}
// one arg handler
inline fun <A, R> handler(loggedFunctionName: String?, fn: (A)->R, argA: A): R
= handler(loggedFunctionName) { fn(argA) }
// two args handler
inline fun <A, B, R> handler(loggedFunctionName: String?, fn: (A, B)->R, argA: A, argB: B): R
= handler(loggedFunctionName) { fn(argA, argB) }
fun main() {
val resultFoo = foo("bar")
if (resultFoo == null) {
handler("foo", ::foo, "arg")
}
val resultBar = bar("arg1", "arg2")
if (!resultBar) {
handler("bar", ::bar, "arg1", "arg2")
}
}
However, it seems you could reduce boilerplate further by incorporating your logical test of the result as another argument:
// zero args handler
inline fun <R> handler(loggedFunctionName: String?, fn: ()->R, verifyResult: (R)->Boolean): R {
val firstResult = fn()
if (verifyResult(firstResult)){
return firstResult
}
val functionName = "<$loggedFunctionName>" ?: "function"
log.warn("Error has been caught at $functionName, doing action A and retrying")
// Do action A
log.warn("Retrying $functionName")
return fn()
}
// one arg handler
inline fun <A, R> handler(loggedFunctionName: String?, fn: (A)->R, verifyResult: (R)->Boolean, argA: A): R
= handler(loggedFunctionName, { fn(argA) }, verifyResult)
// two args handler
inline fun <A, B, R> handler(loggedFunctionName: String?, fn: (A, B)->R, verifyResult: (R)->Boolean, argA: A, argB: B): R
= handler(loggedFunctionName, { fn(argA, argB) }, verifyResult)
fun main() {
handler("foo", ::foo, { it != null }, "arg")
handler("bar", ::bar, { it }, "arg1", "arg2")
}
First of all you need to know, what exactly you want to generalize.
As I can see from your example, you want to repeat function call with same arguments. So instead all this messing with argument-arrays you can wrap payload (function call with arguments) into lambda and call it twice.
Second question is repeat condition. In foo it's result == null, in bar it's result == false. So condition is different for different functions. You can calculate condition in separate lambda.
So you can write something like this:
fun <T, F: KFunction<*>> F.callAndRepeatOnCondition (
payload: (F) -> T,
condition: (T) -> Boolean,
): T {
var result = payload(this)
if (condition(result)) {
println("log: doing something and repeat function ${this.name} ")
println("some super logic before repeat")
result = payload(this)
}
return result
}
fun foo(a: Int, b: String): String? { return null }
fun bar(c: Int): Boolean { return false }
fun main() {
val resultFoo = ::foo.callAndRepeatOnCondition({ it(1, "a") }, { it == null })
val resultBar = ::bar.callAndRepeatOnCondition({ it(2) }, { !it })
}
PS. If you don't need to log function name or can pass it explicitly, here is a little less ugly solution:
fun foo(a: Int, b: String): String? { return null }
fun bar(c: Int): Boolean { return false }
fun <T> (() -> T).repeatIf(condition: (T) -> Boolean): T {
val result = this()
if (!condition(result)) return result
println("some super logic before repeat")
return this()
}
fun <T> (() -> T).repeatWithLoggingIf(logName: String, condition: (T) -> Boolean): T {
val result = this()
if (!condition(result)) return result
println("log: repeating $logName")
println("some super logic before repeat")
return this()
}
fun main() {
run { // without logName
val resultFoo = { foo(1, "a") }.repeatIf { it == null }
val resultBar = { bar(2) }.repeatIf { !it }
}
run { // with logName
val resultFoo = { foo(1, "a") }.repeatWithLoggingIf("foo") { it == null }
val resultBar = { bar(2) }.repeatWithLoggingIf("bar") { !it }
}
}
What I want to make is a function, that returns itself, so I can call it like this:
foo()()...()
In C# it would be done via delegates:
delegate SelfFunc SelfFunc();
static void Main() {
SelfFunc foo = null;
foo = () => {
return foo;
};
foo()()...();
}
Anticipating questions like "why implement such silly behavior?": I want to sum numbers in a very strange way using single function continues calls: foo(1)(2)(3)() = 6, but in this question I just want to know how to return function itself. Example realization of this method that I made in C#. This is all just for fun and to learn Rust:
static int sum = 0;
delegate dynamic InfFunc(int i = int.MaxValue);
static void InfFuncTest() {
InfFunc f = null;
f = (int i) => {
if(i == int.MaxValue) {
return sum;
}
sum += i;
return f;
};
var g = f;
var value = g(1)(2)(3)();
Console.WriteLine(value);
}
A function that returns itself is possible on nightly.
First you need to enable the features unboxed_closures and fn_traits.
Then you can define a struct which, when called, returns self. The full code looks something like this:
#![feature(unboxed_closures, fn_traits)]
struct SelfFunc;
impl FnOnce<()> for SelfFunc {
type Output = SelfFunc;
extern "rust-call" fn call_once(self, _args: ()) -> Self::Output {
self
}
}
Then you can call the function as many times as you want:
fn main() {
let f = SelfFunc;
f()()()()()();
}
Based on #cameron1024's answer, you can "overload" using traits, but you will need 2 structs to handle the empty case properly of foo() (here called Add) without any arguments returning 0.
#![feature(unboxed_closures, fn_traits)]
struct Add;
impl FnOnce<(u32,)> for Add {
type Output = AddImpl;
extern "rust-call" fn call_once(self, args: (u32,)) -> Self::Output {
AddImpl(args.0)
}
}
impl FnOnce<()> for Add {
type Output = u32;
extern "rust-call" fn call_once(self, _args: ()) -> Self::Output {
0
}
}
struct AddImpl(u32);
impl FnOnce<()> for AddImpl {
type Output = u32;
extern "rust-call" fn call_once(self, _args: ()) -> Self::Output {
self.0
}
}
impl FnOnce<(u32,)> for AddImpl {
type Output = AddImpl;
extern "rust-call" fn call_once(self, args: (u32,)) -> Self::Output {
Self(self.0 + args.0)
}
}
fn main() {
dbg!( Add(1)(2)(3)() );
dbg!( Add() );
}
Playground
If you do not care about the no-args foo() requirement, you can make Add a tuple struct instead and remove AddImpl:
#![feature(unboxed_closures, fn_traits)]
struct Add(u32);
impl FnOnce<(u32,)> for Add {
type Output = Add;
extern "rust-call" fn call_once(self, args: (u32,)) -> Self::Output {
Add(self.0 + args.0)
}
}
impl FnOnce<()> for Add {
type Output = u32;
extern "rust-call" fn call_once(self, _args: ()) -> Self::Output {
self.0
}
}
fn main() {
dbg!( Add(1)(2)(3)() );
//dbg!( Add() ); // doesn't compile
}
Playground
Although I should note that this likely isn't such a great idea, using an slice/iterator would likely result in cleaner code:
fn main() {
dbg!([1, 2, 3].iter().copied().sum::<u32>());
}
Playground
I thought closures and functions are same thing. But when referencing to a property inside local function compiler doesn't require self. But inside closure it requires to write self. What i mean is why this two things are different?
The sample code for clarity:
class Foo {
let bar = "bar"
func baz() {
func localBaz() {
println(bar) // No complain from compiler.
}
let bazClosure = {
println(self.bar) // Here if I write just println(bar), compiler complains.
}
}
}
You expectation is wrong - functions and closures in Swift are not the same thing. A func essentially sets up a lazy var binding with a [unowned self] declaration. Thus, if you want to get rid of func you could transform the following:
class Foo {
let bar = "bar"
// this is not your 'baz'; just an example
func baz () { println (bar) }
}
}
as
class Foo {
let bar = "bar"
lazy var baz = { [unowned self] in println (self.bar) }
}
You can see that func is doing more than just a closure.
Furthermore, and importantly, func sets up a recursive binding environment which allows the body of func bar to reference bar. Thus you can write:
1> class Foo {
2. func fact (x:Int) -> Int {
3. if 1 == x { return x }
4. else { return x * fact (x - 1) }}
5. }
6> Foo().fact(5)
$R0: (Int) = 120
but not
7> class Foo {
8. lazy var fact = { (x:Int) -> Int in
9. if 1 == x { return x }
10. else { return x * fact (x - 1) }}}
repl.swift:10:27: error: variable used within its own initial value
else { return x * fact (x - 1) }}}
^
Indeed, I do not know why closure need self in swift to access instance properties but let's think about it.
Your baz() is a class function, I mean it belongs to the class Foo and the closure like a external function. In Objective-C all class function actually need a self argument to invoke that function.
Therefore a closure need a self pointer (or something named self reference the instance of Foo) to access its property.
i'm trying to create a vary simple game on Swift based on Balloons.playground (that Apple showed on WWDC). There is code that Apple provides:
func fireCannon(cannon: SKNode) {
let balloon = createRandomBalloon()
displayBalloon(balloon, cannon)
fireBalloon(balloon, cannon)
}
let leftBalloonCannon = scene.childNodeWithName("//left_cannon")!
let left = SKAction.runBlock { fireCannon(leftBalloonCannon) }
I do the same (i suppose):
func displayFruit(xPos: CGFloat) -> Void {
let fruit = SKSpriteNode(imageNamed: "Banana")
fruit.size = CGSize(width: 100, height: 100)
fruit.position = CGPoint(x:xPos, y: 800)
fruit.physicsBody = SKPhysicsBody(texture: fruit.texture, size: fruit.size)
fruit.physicsBody?.affectedByGravity = true
self.addChild(fruit)
}
let start = SKAction.runBlock { displayFruit(100) }
This code above i put at override func didMoveToView(view: SKView)
I get an error: Cannot reference a local function with capture from another function
I know there was very the same questions, but solutions there don't seemed helpful for me.
What would be the right way to do this?
Thank you!
This is a local function:
override func didMoveToView(view: SKView) {
func displayFruit() {
// ...
}
}
This is not a local function:
override func didMoveToView(view: SKView) {
// ...
}
func displayFruit() {
// ...
}
Make it look like the second one.
Say I have a class NamedShape defined like this:
class NamedShape {
var numberOfSides: Int = 0
var name: String
init(name: String) {
self.name = name
}
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
func containerFunc() -> Void{
println("strange world")
func subFunc() -> String {
return "sub function returns string"
}
println(subFunc())
}
}
I can initialize it like this:
let someNamedShape = NamedShape(name:"polynomial")
And invoke some method like this:
someNamedShape.containerFunc()
Now how can I invoke method subFunc within containerFunc on its object?
Compiler complains while trying this:
someNamedShape.containerFunc().subFunc()
It looks like it's not possible, unless you return the inner function from its containing function. Here's what the documentation says
Nested functions are hidden from the outside world by default, but can still be called and used by their enclosing function. An enclosing function can also return one of its nested functions to allow the nested function to be used in another scope.
This is how your code should look like in order to be able to call the subfunc
class NamedShape {
var numberOfSides: Int = 0
var name: String
init(name: String) {
self.name = name
}
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
func containerFunc() -> (() -> String) {
println("strange world")
func subFunc() -> String {
return "sub function returns string"
}
println(subFunc())
return subFunc
}
}
let someNamedShape = NamedShape(name:"polynomial")
let subfunc = someNamedShape.containerFunc()
subfunc()