Closure (With Default Value) as Function Parameter

Can swift closures be set to a default value when used as a parameter in a function?

Yes, functions are just values, so you can supply them as defaults

// just to show you can do it with inline closures or regular functions
func doNothing<T>(t: T) -> Void { }

func sendBody(
body: NSData? = nil,
success: (data: NSData) -> Void = { _ in return },
failure: (data: NSData?) -> Void = doNothing
)
{ }

Alternatively, you could make them optional, that way you can detect if the caller passed one:

func sendBody(
body: NSData? = nil,
success: ((NSData) -> Void)? = nil,
failure: ((NSData?) -> Void)? = nil
)
{ success?(NSData()) }

sendBody(success: { _ in print("ah, yeah!") })

Also worth noting if you’re doing this: if the caller uses the trailing closure syntax, this will be the last closure in the argument list. So you want the last one to be the one the user is most likely to want to supply, which is probably the success closure:

func sendBody(
body: NSData? = nil,
success: ((NSData) -> Void)? = nil,
failure: ((NSData?) -> Void)? = nil
)
{
if success != nil { print("passed a success closure") }
if failure != nil { print("passed a failure closure") }
}

// this prints "passed a failure closure"
sendBody { data in
print("which closure is this?")
}

Other than this, the order in the function declaration doesn’t matter to the caller – defaulted arguments can be supplied in any order.

How to optionally pass in values to a closure in Swift?

For a regular method, you can provide a default value for a parameter:

func myCallback(#error: NSError!, samples: [HKQuantitySample]? = nil, average: Double? = nil) {
}

myCallback(error: nil)

These parameters with default values should be at the end of the argument list.

This doesn't work in your case, since you're not defining a method; you're just specifying the method signature that callers need to pass in for the callback. You can say "pass in a method that takes an Int", for example, but there's no way currently to say "pass in a method that takes an Int and uses a default of 0 if I don't pass anything in".

Remember, optional values just mean the existence of a value is optional and the thing can be nil.

The closure as parameter behind the default parameter in Kotlin

Kotlin don't know exactly what mutableMapOf("key" to "value") is.

Clarify whether it's params or headers

get("/somePath", headers = mutableMapOf("key" to "value")){ httpResponse -> ......some code(Last line is a List<SomeClass>)

or

get("/somePath", mutableMapOf<String, Any>("key" to "value")){ httpResponse -> ......some code(Last line is a List<SomeClass>)

How to specify default function parameter which is a function in PHP?

One way to go about it is to set the default parameter to null, then check if the parameter was in fact null - if it was, define a "default" function to be used instead.

Then check if the parameter is callable or not - if it is not callable, raise an exception - otherwise, call the function!

function foo($func = null) {
// If $func is null, use default function
if ($func === null) {
$func = function() {
echo "Default!\n";
};
}
// Verify that whatever parameter was supplied is a valid closure
if (!is_callable($func)) {
throw new Exception('Invalid parameter supplied');
}
// Call the function!
$func();
}

function bar() {
foo(); // Default parameter is supposed to be here

foo(function(){
echo "Non default func param \n";
});
}

bar();

Output of the above would be

Default!

Non default func param

  • Live demo at https://3v4l.org/ZTpn3

Cannot set default function closure

All the arms of a match statement must resolve to the exact same type.

With that in mind, let's replace impl Fn() -> () (which is also the same as impl Fn() BTW) with the generics that it represents:

fn bar<T>(baz: Option<T>) where T: Fn() {
// ...
}

impl Trait (in a function parameter) is syntactic sugar for regular generics, so this is "what the compiler sees".

Then let's look at the match:

fn bar<T>(baz: Option<T>) where T: Fn() {
let f = match baz {
Some(f) => f,
None => foo,
};
}

This can't work, because the type of foo is a special thing called a "function item" (essentially a unique type), but the type of f is a generic parameter T: it could be any type imaginable (as long as it implements Fn()). Clearly, these might be different, so Rust rejects the match statement as "having incompatible types".

What you're looking for is a trait object (though this comes at the cost of a heap allocation and vtable dispatch):

fn bar(baz: Option<impl Fn()>) {
let f: Box<dyn Fn()> = match baz {
Some(f) => Box::new(f),
None => Box::new(foo),
};

f();
}

Or, you can call the function immediately without storing in a variable:

fn bar(baz: Option<impl Fn()>) {
match baz {
Some(f) => f(),
None => foo(),
};
}

This is likely to be faster than the dyn Fn() approach above, though of course, if you are later storing it in a struct, this will not work.



Related Topics



Leave a reply



Submit