Using push!() on an array with 'nothing' as its only value results in error

I was trying to implement a stack using an array for which I had to create a single value array [nothing]. I needed nothing because my code included peeking the array. But when I tried to push an integer value into the array it resulted in an error. Here is the code and the error:

julia> stack = [nothing]
1-element Array{Nothing,1}:
 nothing

julia> push!(stack, 1)
ERROR: MethodError: convert(::Type{Union{}}, ::Int64) is ambiguous. Candidates:
  convert(::Type{Union{}}, x) in Base at essentials.jl:169
  convert(::Type{T}, x::Number) where T<:Number in Base at number.jl:7
  convert(::Type{T}, arg) where T<:VecElement in Base at baseext.jl:8
  convert(::Type{T}, x::Number) where T<:AbstractChar in Base at char.jl:179
Possible fix, define
  convert(::Type{Union{}}, ::Number)
Stacktrace:
 [1] convert(::Type{Nothing}, ::Int64) at ./some.jl:34
 [2] push!(::Array{Nothing,1}, ::Int64) at ./array.jl:912
 [3] top-level scope at REPL[11]:1

julia>

I want to use nothing similar to None in python. I am not sure if this is a bug or you can’t use nothing in this way.

It’s a weird error but the problem is that 1 doesn’t fit within the eltype of your array:

julia> typeof(1) <: eltype(stack)
false

You can define one with a wider type, either just [] which has Any, or

julia> stack2 = Union{Nothing,Int}[]
0-element Array{Union{Nothing, Int64},1}

julia> push!(stack2, 1, nothing, 42)
3-element Array{Union{Nothing, Int64},1}:
  1
   nothing
 42

(I guess my first line is not the perfect way to think, as push!(stack2, 1.0) works… push! tries to convert if necessary.)

5 Likes

What are you hoping to achieve? Do you want the nothing to be replaced by the integer value? If so, then push! is not the right function to call – you should just assign the value to stack[1]. I am also wondering if an array is actually the most appropriate data structure for your goal.

@mcabbott already posted the solution, so just to elaborate on his first reason. The OPs first line

stack = [nothing]

mentiones afterwars, that it generated an Array{Nothing,1}, that is an array whose elements (eltype(stack)) are only of type Nothing, so you can not push an integer (that’s not of type or a subtype of Nothing, clearly).

So with the Union{Int, Nothing}[], the array consists of either Nothings or integers. then both are allowed to be pushed.
The meta problem is, that from nothing Julia can only infere that the array is of nothings, but not the other types you want to put in there, that’s where you need the Union.

I hope that helps – and of course welcome to Julia discourse :slight_smile:

2 Likes

My gut feeling is that you probably shouldn’t be doing this, and that you should find a way to avoid putting a junk value in the vector.

So what do you mean by ‘peeking’ and why do you need to do it? Can you just check for isempty instead?

1 Like

I mean, it can be fine to use a sentinel value instead of isempty but then, it probably should be something of the same type, and that naturally would evaluate for the answer you want, like zero, a negative number, or the greatest/smallest Int (supposing your code will never reach it).

1 Like

no i want the first element to be nothing because i later use comparison operators and i can’ t do that with an empty array.

That’s the problem, the code is dependent upon external input and i am not sure what else to put instead of nothing because the input can be any integer.

I just have a little question if anyone will please answer that. Is there any other way to impliment a stack so that I don’t have to predefine the types of the elements and the the stack will adapt according to whatever element gets passed in?

The simplest solution is using a Any[]. This will not “adapt”, but will be able to store all types from the beginning.

3 Likes

Just to complement, Any[] will have worse performance than an array of specific type, but for something that reads element by element from an user input this is completely irrelevant.