Sometimes I want to provide a fallback value for a...
# getting-started
m
Sometimes I want to provide a fallback value for a nullable function argument, and this works well:
Copy code
fun example(argument: Int?) {
    val argument = argument ?: 5
        ...
}
But it generates the "name shadowed" lint warning. Is there an alternative that is better?
e
aside from changing the signature to
Copy code
fun exmaple(argument: Int = 5)
?
m
This prevents the caller from passing in null
This could be a
showUserAvatar(avatar: Avatar?)
and the user might not have an avatar, in which case the function shows a default, but the caller can just pass in the avatar property without having to do a null check.
e
I understand that there are times that you need to accept null, removing it is just the easiest course of action in the limited example
anyhow, I just ignore shadowed name warnings when I'm intentionally shadowing something like that
m
That's what I do as well, but it's sometimes annoying. And suppressing the warning is an extra "useless" line of code.
e
working with some other languages, you get used to shadowing names
m
This prevents the caller from passing in null
you can also have a default on a nullable type
Copy code
fun example(argument: Int? = 5) {

}
m
This also prevents the caller from passing in null (and getting the default value as expected). Imagine the call site is
showUserAvatar(user.avatar)
and
avatar
is nullable.
e
if we had https://youtrack.jetbrains.com/issue/KT-18695 then perhaps it would be possible for the caller to
Copy code
showUserAvatar(user.avatar ?: _)
👍 1
r
Going back to the original question, why do you have to use the same name again? Something like
Copy code
showUserAvatar(nullableAvatar: Avatar?) {
 val avatar = nullableAvatar ?: DEFAULT_AVATAR
 ...
}
or
Copy code
showUserAvatar(avatar: Avatar?) {
 val avatarOrDefault = avatar ?: DEFAULT_AVATAR
 ...
}
would also be readable code, wouldn't it?
m
That is certainly as solution. I don't like the first one, as it makes the argument name unnecessarily verbose for the caller, but
orDefault
for the internal version works indeed.
👍 1
l
What you put in your original post is fine, and I'd argue the warning is bogus. I'd just disable these warnings.
j
would also be readable code, wouldn't it?
It would be readable and more likely to be buggy. There are now 2 avatars and I might reference the wrong one later down
l
@Jacob that's my argument too. Shadowing is perfectly fine, and should be encouraged when the entire purpose is to, well, shadow the other name so it can't be used.
j
fun showUserID(uid: Int? = 5) {
...
}
works. You can pass in null or nothing and it behaves as expected. Your code generates the shadowing warning because it is indeed shadowing the argument. That is, val argument = ... creates another variable called argument that now occupies that namespace in this scope. It hides the parameter called 'argument'. To do it your way, this would be better:
fun example(argument: Int?) {
val nonNullID: Int = argument ?: 5
...
}
That will eliminate the warning.
j
Behaves as who expected? It doesn't convert null to 5 which was what op asked for. Your other approach of changing the variable name has already been discussed above.
m
Nice, voted for the issue.
l
I actually had a bug in my code due to exactly this recently. I had not used shadowing because the warning was annoying, and then of course I ended up using the wrong variable in one place. Very tricky to detect.