I have a function like below:
func delay(_ description: String, deadline: Double = 2.0, timeout: Double = 3.0) {
...
}
It'd make sense for the timeout parameter to be based on the deadline parameter as below to make it more foolproof:
func delay(_ description: String, deadline: Double = 2.0, timeout: Double = deadline + 1.0) {
...
}
This will say however two errors:
Cannot find 'deadline' in scope
Failed to produce diagnostic for expression; please submit a bug report (https://swift.org/contributing/#reporting-bugs) and include the project
The official doc doesn't say anything about this: https://docs.swift.org/swift-book/documentation/the-swift-programming-language/functions/#Default-Parameter-Values
I guess it's unsupported. I know how to workaround it within the function body, but I just want to make sure that I'm trying it in the proper way. Is there a way to make it work like this? I couldn't find explicitly this being discussed elsewhere.
I also tried to not make the other parameter to have a default value, but it's the same outcome:
func delay(_ description: String, deadline: Double, timeout: Double = deadline + 1.0) {
...
}
This question below is somewhat similar and the accepted reply is somewhat covering my question as well, however I'm still not convinced that my above try is a bad expectation. Swift: Class parameter as default function parameter
And this might answer my question, but I'm just more confused: When are Swift function default parameter values evaluated?
This has been discussed here on forums.swift.org, and your guess is correct - it is not supported.
Implementing such a feature would affect the ABI. To quote one of the comments,
I think this might pose fun ABI problems. Specifically, Swift function default arguments are produced by little function thunks that the caller can call. These functions are currently zero-argument: to have them depend on earlier arguments, they'd need to take earlier arguments as their own arguments. Put another way, these little thunks would now be able to have an arity other than 0.
This change would mean that function default arguments sometimes leak into the ABI, at least in terms of whether they depend on a previous value. That seems like a bit of a subtle footgun to me. It's definitely manageable (tooling can report it if you get this wrong), but I do think it would be quite hard to communicate and likely surprising to people.
What this basically means is that when you don't pass an optional parameter in your source code, the compiler actually inserts a call to a thunk (a little function that evaluates the default parameter):
delay("foo")
// is actually
delay("foo", deadline: thunkForParam2(), timeout: thunkForParam3())
// thunkForParam2 and thunkForParam3 are generated by the compiler
If timeout now depends on deadline, the thunks now needs to be changed take parameters:
let param2 = thunkForParam2()
delay("foo", deadline: param2, timeout: thunkForParam3(param2))
Anyway, a simple workaround in your case is to just make the parameter optional and compute it inside the function:
func delay(_ description: String, deadline: Double = 2.0, timeout: Double? = nil) {
let actualTimeout = timeout ?? deadline + 1
// ...
}
Many existing APIs do something like this too, using nil to mean "some implementation-defined default behaviour".
It is not possible in Swift to have a default parameter depend on the value of another parameter. But you can achieve the same effect by having two versions of your function:
func delay(_ description: String, deadline: Double = 2.0) {
delay(description, deadline: deadline, timeout: deadline + 1.0)
}
func delay(_ description: String, deadline: Double = 2.0, timeout: Double) {
...
}
The second version does all the work. Note that its timeout parameter does not have a default value. The first version is a wrapper which calculates the timout based on the deadline.
I saw @Sweeper’s answer after I posted mine. I think that solution is better because it does not duplicate the default value for deadline.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With