Help with having an OPTIONAL closure as a function parameter

I often like to have methods that take an optional closure as a callback if one is needed. So far, with Silver I am unable to do this. Here is a short Android example that does work, although a callback MUST be provided.

public class MainActivity: Activity {

public override func onCreate(savedInstanceState: Bundle!) {
	super.onCreate(savedInstanceState)
	ContentView = R.layout.main
	
	doSomethingWithACallback() {
		println("And I made it to the callback.")
	}
}

private func doSomethingWithACallback( completion: () -> ()  ) {
	println("I did something!")
	completion()
}

}

LogCat: I/System.out( 2448): I did something!
LogCat: I/System.out( 2448): And I made it to the callback.

However, If I try to make the callback optional, a compiler complains “No Matching Overload”

public class MainActivity: Activity {

public override func onCreate(savedInstanceState: Bundle!) {
	super.onCreate(savedInstanceState)
	ContentView = R.layout.main
	
	doSomethingWithAnOptionalCallback() { <------- No matching overload!
		println("And I made it to the callback.")
	}
}

private func doSomethingWithAnOptionalCallback( completion: ( () -> () )?  ) {
	println("I did something!")
	if completion != nil {
		completion!()
	}
}

}

Instead of using an optional parameter to receive the closure, I tried setting it to an empty closure as a default if no callback was provided, but this yielded the compiler error, constant expected.

private func doSomethingWithACallback( completion: () -> () = { }  ) { <- Constant expected
	println("I did something!")
	completion()
}

For now, my workaround is to always provide a callback and pass an empty closure when no callback is required.

public class MainActivity: Activity {

public override func onCreate(savedInstanceState: Bundle!) {
	super.onCreate(savedInstanceState)
	ContentView = R.layout.main
	
	// I don't need a callback, but I have to pass it something!
	doSomethingWithACallback() { }
}

private func doSomethingWithACallback( completion: () -> () ) {
	println("I did something!")
	completion()
}

}

LogCat: I/System.out( 2538): I did something!

Not a huge problem, but I’ve gotten so used to just omitting the closure when I don’t need a callback that I keep forgetting to add the { } after the function call. Plus, it’s not very pretty.

Am I missing something?

A nullable parameter isn’t really optional. it just allows you to pass nil, but you still need to pass it. That’s as designed, IMHO?

Yeah, only literals can be used as default parameters. what’s wrong with using nil as default value, i.e.:

private func doSomethingWithACallback( completion: () -> () = nil ) {

does that work?

Thanks. That does work. I didn’t think to try that because in xCode, without explicitly declaring a parameter as an optional, it would never allow it to be set to nil.

In other words, xCode required version would be

func foo ( completion: ( () → () )? = nil ) { …

While the Silver required version appears to be

func foo ( completion: () → () = nil ) { …

No big whoop, but these are the kind of Syntax things that iOS developers who are used to xCode will have to learn by experience.

I probably also need to do some reading up on the differences between optionals and nullable, as it sounds like, in Silver, optionals are really nullables.

In any event, code is working and I’m happy. Thanks.

Hmm, the same should hold true in Silver. That sounds like a bug, if block types are always treated as nullable (“Optional” in Apple parlance, which is a confusing term in this context of course, because “optional = can be null” is not the same as “options = has a default value and can be omitted from the method call’s parameter list” ;). I’ll log an issue for that, Silver should, too, require that ?. but the = nil is still needed, to make the parameter optional in the second sense.

Apple (and Swift) just use the term “optional” interchangeable with “nullable”. which is fine, but an nullable parameter is only ‘optional’ in the sense that you can pass nil, not optional in the sense that you can just leave it out of the call. a parameter with a default value is truly ‘optional’ in that you don’t have to pass it. :wink:

Thanks, logged as bugs://73906: Silver: block types are always nullable?

bugs://73906 got closed with status fixed.