# Nullable with an unknown type

**URL:** <https://discourse.julialang.org/t/nullable-with-an-unknown-type/3078>\
**Category:** General Usage\
**Created:** [April 6, 2017, 12:43am UTC](https://discourse.julialang.org/t/nullable-with-an-unknown-type/3078 "2017-04-06T00:43:48Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![cstjean](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cstjean/32/1444_2.png) [@cstjean](https://discourse.julialang.org/u/cstjean)\
**Post date:** [April 6, 2017, 12:43am UTC](https://discourse.julialang.org/t/nullable-with-an-unknown-type/3078/1 "2017-04-06T00:43:48Z")

</div>

Suppose I have this function,

```julia
function foo(x)
    if g(x)
        h(x)
    else
        nothing
    end
end

```

where x can be of many different types, and `h(x)` is type-stable, in the sense that given `x`’s type, `h(x)`'s type is correctly inferred by the compiler. How can I make `foo` type-stable? I should be able to use `Nullable`, but how can I refer to `h(x)`'s return type in the `else` branch?

```julia
function foo(x)
    if g(x)
        Nullable(h(x))
    else
        Nullable{T}() # what should T be?
    end
end

```

I suppose I could use a generated function with `Base.return_type`, but that seems like overkill for such a common scenario.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [April 6, 2017, 5:29am UTC](https://discourse.julialang.org/t/nullable-with-an-unknown-type/3078/2 "2017-04-06T05:29:42Z")

</div>

See [this discussion](https://discourse.julialang.org/t/combinators-on-nullables/1481/7), especially the end. TL;DR: your best bet now is to rely on the type inference of the compiler (as you do above), but this may change in the future.

---

<div class="post-metadata">

**Author:** ![cstjean](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cstjean/32/1444_2.png) [@cstjean](https://discourse.julialang.org/u/cstjean)\
**Post date:** [April 7, 2017, 1:13am UTC](https://discourse.julialang.org/t/nullable-with-an-unknown-type/3078/3 "2017-04-07T01:13:06Z")

</div>

Thank you for the reference, that was a very useful read.

> [@](#):
>
> ```julia
> function and_then{T}(f, x::Nullable{T})
> if isnull(x)
> Nullable{return_type(f, Tuple{T})}() # hypothetical
> else
> Nullable(f(get(x)))
> end
> end
> 
> ```

I just tried this solution on 0.6, and it’s not (inferred as) type-stable. As for generated functions, calling `Base.return_types` there triggers an error: `code reflection cannot be used from generated functions`.

However, I found an alternative, type-stable solution with `broadcast`:

```julia
nullify(b::Bool) = b ? Nullable{Bool}(true) : Nullable{Bool}()
function foo(x)
    h.(nullify(g(x)), x) # the first argument to `h` is a dummy to trigger broadcasting to Null
end
# It works for arbitrary `g` and `h`, eg.:
g(x) = x < 10
h(_, x) = sin(x)

```

Broadcast’s handling of Nullable is done in [`broadcast_c`](https://github.com/JuliaLang/julia/blob/18e864b8283c2686c254973d8f77a59287104167/base/broadcast.jl#L300). It calls `Base._return_type(f, arg_types)`, which gets evaluated at compile-time. If I replace `return_type` with `Base._return_type` in your example, `and_then` becomes type-stable.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [April 7, 2017, 12:01pm UTC](https://discourse.julialang.org/t/nullable-with-an-unknown-type/3078/4 "2017-04-07T12:01:14Z")

</div>

neat workaround, but possibly you should file the inference problem as an issue

---

<div class="post-metadata">

**Author:** ![fengyang.wang](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fengyang.wang/32/104_2.png) [@fengyang.wang](https://discourse.julialang.org/u/fengyang.wang)\
**Post date:** [April 15, 2017, 11:40pm UTC](https://discourse.julialang.org/t/nullable-with-an-unknown-type/3078/5 "2017-04-15T23:40:41Z")

</div>

It’s a little verbose, but instead consider

```julia
function and_then(f, x::Nullable)
    if isnull(x)
        S = Base.Broadcast._nullable_eltype(f, x)
        if isleaftype(S)
            Nullable{S}()
        else
            Nullable()
        end
    else
        Nullable(f(unsafe_get(x)))
    end
end

```

This is better for performance. Among possible inferred results `Union{Nullable{Int}, Nullable{Union{}}}` we prefer `Nullable{Int}`, so if inference can return a leaf type, then that’s what we return. Among possible inferred results `Union{Nullable{Int}, Nullable{Union{}}}` and `Union{Nullable{Int}, Nullable{Integer}}`, we prefer `Union{Nullable{Int}, Nullable{Union{}}}`, because this prevents type instability from propagating very far (since `get` can be inferred to return `Int` on that).

In summary:

- Only use the result of type inference for the empty case
- Only use the result of type inference if it is a leaf type; otherwise use `Union{}`

Note that this is the behavior also of `broadcast`: we guarantee that we never return a `Nullable{T}` where `T` is abstract. This is very important for performance.

By the way, you should not use anything that calls inference from generated functions. This includes `broadcast` and the implementations of `and_then` in this thread. There is no workaround besides avoiding the use of generating functions.

(Of course, in this particular case, just use `broadcast` 🙂)
