# Union{Some{T}, Nothing} behaviour

I cannot figure out how to obtain a non-nothing output from the following code.

``````julia> struct B
a::Union{Some{T}, Nothing} where {T<:Integer}
end

julia> b = B(nothing)
B(nothing)

julia> b = B(5)
ERROR: could not compute non-nothing type
Stacktrace:
[1] error(s::String)
@ Base .\error.jl:33
[2] nonnothingtype_checked(T::Type)
@ Base .\some.jl:31
[3] convert(#unused#::Type{Union{Nothing, Some{T}} where T<:Integer}, x::Int64)
@ Base .\some.jl:36
[4] B(a::Int64)
@ Main .\REPL[99]:2
[5] top-level scope
@ REPL[101]:1
``````

Can you elaborate what you want to achieve?

The default constructor is trying to convert `5` to a `Union{Some{T}, Nothing} where {T<:Integer}`, but it doesnâ€™t know how:

``````julia> convert(Union{Some{T}, Nothing} where {T <: Integer}, 5)
ERROR: could not compute non-nothing type
Stacktrace:
[1] error(::String) at ./error.jl:33
[2] nonnothingtype_checked(::Type{T} where T) at ./some.jl:29
[3] convert(::Type{Union{Nothing, Some{T}} where T<:Integer}, ::Int64) at ./some.jl:34
[4] top-level scope at REPL[1]:1
``````

You could provide a constructor for your type. Perhaps something like this:

``````B(x::Integer) = B(Some(x))
``````
1 Like

I would write this as the following, which reveals why this pattern is harder to use in practice unless you make `T` explicit more often:

``````julia> struct B{T <: Integer}
a::Union{Some{T}, Nothing}
end

julia> B(nothing)
ERROR: UndefVarError: T not defined
Stacktrace:
[1] B(a::Nothing)
@ Main ./REPL[1]:2
[2] top-level scope
@ REPL[2]:1

julia> B(Some(1))
B{Int64}(Some(1))

julia> B{Int}(nothing)
B{Int64}(nothing)
``````

The problem is that you canâ€™t figure out what `T` is without explicitly specifying it or providing a concrete input value that lets it be determined. Itâ€™s like the problem of assigning a type to an empty array â€“ the thing that would give you the relevant information isnâ€™t present, so you need to make up for that absence.

1 Like

In this particular case I am trying to model a drive train. Think of a motor driving a gearbox driving a machine. Sometimes it may be more than one gearbox. Letâ€™s call:
the motor: shaft 1
the coupling: connector 1
the gearbox input : shaft 2
the gearbox: connector 2
the gearbox output: shaft 3
the coupling: connector 4
the driven machine: shaft 4

I would like a structure that holds the information for each shaft and another that holds the information for each component.
The shaft structure has information for the previous shaft, the following shaft and the component that connects between the current shaft and the following shaft. My thought was to use nothing as the previous shaft for the motor, where there is no previous shaft. Perhaps a better way would be a separate structure for this shaft, where the absence of that field would indicate that there is no previous shaft?

In reading the documentation and on discourse, it seemed that the Union{Some{T}, Nothing} might be a good way of indicating that there is a shaft present or that nothing is present.

Thanks johnmyleswhite, that is most helpful.

For my purposes, {T::Int} may be just as good as {T<:Integer}, if this makes life easier for the compiler. Experimenting shows {T <: Int} works but {T :: Int} does not.

I see an inconsistency in passing nothing versus something to the field. So I experimented with doing away with Some and using the following which seems to provide a more consistent interface:

``````julia> struct B{T <: Int}
a::Union{T, Nothing}
end

julia> B{Int}(5)
B{Int64}(5)

julia> B{Int}(nothing)
B{Int64}(nothing)

julia> isnothing(ans.a)
true

julia>
``````

There is no point in parametrizing `T` here.

``````struct B
a::Union{Int, Nothing}
end
``````

should be functionally equivalent.

Edit: Spoke to soon, `B{Union{}}(nothing)` is still valid with your version, but not with mine, so that might be a reason to explicitly parametrize `T`.

This seems to me like the best approach. Donâ€™t be afraid to introduce new types for components that are different from each other. I try to avoid types that are filled with `nothing` values. If a type is filled with a bunch of `nothing` values, then it probably should be a different type without the `nothing`s.

Types normally have some semantic meaning beyond just the structure of their fields. So if you have a `Motor` type, without looking at the fields you know that it does not have a previous shaft, because motors simply donâ€™t have previous shafts.

I think the use of `Some` is overkill here. In my understanding, `Some` is only used in fairly specialized situations where you are trying to distinguish between the value `nothing` and literal nothingness. From the docstring, `Some` is

a wrapper type used in `Union{Some{T}, Nothing}` to distinguish between the absence of a value (`nothing`) and the presence of a `nothing` value (i.e. `Some(nothing)`).

As an example, suppose you have a dictionary of type `Dict{Int, Union{Int, Nothing}}`. Thereâ€™s a difference between keys that donâ€™t exist in the dictionary and keys that do exist in the dictionary but which have the value `nothing`.