How to check that a Numba untyped list is empty?

I created a Numba typed list that is sometimes empty, and I’d like to check that in the course of some code. The natural solutions don’t work. Here is a minimum working example:

from numba import njit
from numba.typed import List

@njit 
def is_empty(my_list):
    if len(my_list) == 0:
        print("empty")
    else:
        print("not empty")
    
non_empty_list = List()
non_empty_list.append(1)
is_empty(non_empty_list)    

empty_list_typed = List()
empty_list_typed.append(1)
empty_list_typed.remove(1)
is_empty(empty_list_typed)

empty_list = List()
print(len(List())) # This correctly prints 0
is_empty(empty_list)

Instead of running as I’d expect, I get the following – as you can see, it only works once the list has been typed:

not empty
empty
0
Traceback (most recent call last):

  File "C:\Users\lnajt\Documents\GitHub\TinyProjects\ConnectedPartitionSampling\untitled0.py", line 15, in <module>
    is_empty(empty_list)

  File "C:\Users\lnajt\anaconda3\lib\site-packages\numba\dispatcher.py", line 604, in typeof_pyval
    tp = typeof(val, Purpose.argument)

  File "C:\Users\lnajt\anaconda3\lib\site-packages\numba\typing\typeof.py", line 30, in typeof
    ty = typeof_impl(val, c)

  File "C:\Users\lnajt\anaconda3\lib\functools.py", line 840, in wrapper
    return dispatch(args[0].__class__)(*args, **kw)

  File "C:\Users\lnajt\anaconda3\lib\site-packages\numba\typing\typeof.py", line 56, in typeof_impl
    return getattr(val, "_numba_type_", None)

  File "C:\Users\lnajt\anaconda3\lib\site-packages\numba\typed\typedlist.py", line 214, in _numba_type_
    raise TypeError("invalid operation on untyped list")

TypeError: invalid operation on untyped list

It is not hard to write my code to avoid this, but it seems like a strange bug.

Thank you for asking about this on the Numba discourse. What you are seeing here, is the result of lack of type specialization. For a numba.typed.List to be “useful” it needs to be typed, which means it must have a specific type associated with it. Without a known type, the list can not be compiled, as the compiler will not know how much space will need to be allocated at runtime for elements which are to be contained in the list. So, why you must do for this to work, is instantiate the List with known Numba type and then you can use it as en empty list in a Numba compiled function. There are a two ways this can be done:

In [1]: from numba import njit
   ...: from numba.typed import List
   ...:
   ...: @njit
   ...: def is_empty(my_list):
   ...:     if len(my_list) == 0:
   ...:         print("empty")
   ...:     else:
   ...:         print("not empty")
   ...:

In [2]: from numba import int64

In [3]: l = List.empty_list(int64)

In [4]: is_empty(l)
empty

In [8]: # or create a list and specialize it with an item and then empty it

In [9]: l = List([1])

In [10]: l.pop()
Out[10]: 1

In [11]: is_empty(l)
empty
1 Like