# Usage of Nullable in function arguments

#1

I guess this is something simple, but I can’t quite understand, how to use `Nullable` in function arguments.
May be I am doing it wrong from the start, but I want the following: have a function which has not nullable argument or `nothing` on outside and `Nullable` in function body. Unfortunately something like this do not work

``````function f(x::Nullable{Int} = nothing)
get(x, 0)
end

f(1)   # Error
f()     # Error
``````

Of course, I can add something like this

``````f(x:Int) = f(Nullable(x))
f() = f(Nullable{int}())
``````

than it works fine, but if I have a function with more than one argument (like ten for example), then number of such additional functions explode exponentially.

Requiring from end user to wrap everything in Nullable looks inconvenient to me, because

``````f(Nullable(5))
``````

looks too long, but may be I am wrong.

#2

Make `f` an interface that does the wrapping and then calls an implementation, say `faux`, that takes the nullables? Just a thought.

``````function f(; x::Union{Int,Void} = nothing,
y::Union{String,Void} = nothing)
faux(x == nothing ? Nullable{Int}() : Nullable(x),
y == nothing ? Nullable{String}() : Nullable(y))
end

function faux(x::Nullable{Int}, y::Nullable{String})
println(isnull(x) ? "no x" : "x == \$(get(x))")
println(isnull(y) ? "no y" : "x == \$(get(y))")
end

f(x = 31)
f(y = "31")
f(x = 3, y = "14")
f(x = "31") # error
``````

#3

I would say your suggested way is the way to do it. If you want to make sure that all your arguments are wrapped in nullables, you could

``````function asnullable(x)
isa(x, Nullable) ? x : Nullable(x)
end
``````

and apply this to all your arguments as the first thing inside the function. If you want the function `f` to be specific about input types (e.g. `Int`), you can give them type `Union{Int, Nullable{Int}}`. But what exactly are you meaning to achieve?

#4

Thank you for your replies. I am trying to rewrite in julia some python code, which heavily uses functions like this: “`def f(x=None, y=None, z=None)`” where values of `x`, `y`, `z` either defined by user or calculated in run time. On julian side, types of arguments are known, so I thought that it would be more idiomatic to use `Nullable{T}` types instead of `Union{Void, T}`. Also, I’ve read this advice http://docs.julialang.org/en/stable/manual/style-guide/?highlight=nullable#avoid-type-unions-in-fields, but it looks that it is applicable only for type declaration, not methods.

#5

Yes, very often when you find something ‘missing’ from Julia syntax it derives from porting code written in a language with subtly different logic.
Could you consider creating the same functionality by using multiple dispatch, i.e. functions with different numbers and types of arguments? Also, is there a reason you don’t just calculate the run-time values as a default value in the function definition, e.g. `f(x = 2, y = 2x, z = 3x + 2y) = x + y + z`

#6

One important distinction between Python and Julia is that in Python default function arguments are evaluated when the function is defined, but in Julia they are evaluated when the function is called. That’s why @mkborregaard’s suggestion works in Julia, but wouldn’t work in Python.

As a result, I’ve found that the `f(x=None)` pattern is much less necessary than it was for me in Python.

But if you do want to use that pattern, there’s no performance downside to having a `Union{Int, Void}` argument. As you’ve seen from the docs, the performance issues with `Union` are all related to holding a Union within a `type` or `Array`, which is why we use `Nullable` in those situations.

#7

I see, it makes more sense now. Syntax with f(x = 1, y = x) really useful.

One last question, what should be done in case when function behavior depends on whether argument has some value or not defined at all? Something like this

``````function f(n = nothing)
# if n is nothing then loop indefinitely, else run from 1 to n
...
end
``````

In this case defining `n` as `n::Union{Void, Int}` looks somewhat excessive, and three functions

``````function inner_loop end

function f(n::Int)
for i in 1:n
inner_loop()
end
end

function f()
while(true)
inner_loop()
end
end
``````

looks like too much boilerplate.

In types some field can be undefined and checked later with `isdefined`, which is exactly what I want, but it is not possible in methods.

#8

I think that implementation looks right

#9

There’s nothing wrong with your 3-function implementation, and it very cleanly separates the different behaviors. It also makes it easy to add some other way to call `inner_loop()` in the future, and it lets Julia decide at compile-time which version of the function will be used. If I were writing this code, I would probably structure it in that way.

But, if you really want only one function definition, you can always do something like:

``````function f(n::Union{Int, Void}=nothing)
if n === nothing
while true
inner_loop()
end
else
for i in 1:n
inner_loop()
end
end
end
``````

#10

I always have to double check if this way will compute the branch at compile time, but note that type checking (in type-stable function) is always done at compile time. So if you write a conditional with `if typeof(x)<:Void`, it will compile into a function for which it’s true, and a function for which it’s false, depending on the type of `x`, so there is no runtime cost.

This works for any type except for those in keyword arguments. But the problem with keyword arguments is being addressed:

#11
``````function f(n::Number=Inf)
i = 0
while (i+=1) <= n
inner_loop()
end
end
``````

#12

You don’t even need to write `if typeof(x) <: Void`: as can be checked e.g. by calling `@code_llvm`, `x === nothing` is also computed at compile time.