lcompilers / lpython

Python compiler
https://lpython.org/
Other
1.51k stars 164 forks source link

Introduce constants like None #108

Open namannimmo10 opened 2 years ago

namannimmo10 commented 2 years ago

I think we also need to implement Constant so that we support simple types such as None. Now the question is, how to represent that in ASR? Do we need a Constant node in ASR?

certik commented 2 years ago

We could create a None type, so you could use it like this:

a: NoneType
a = None

But it wouldn't be very useful this way.

The only usage could be with pointers, where None represents nullptr.

What is some usecase that you have in mind?

namannimmo10 commented 2 years ago

None is used to define a null value or 'no' value. So, here are some of its common use-cases I notice in the Python codebase:

  1. Very often used in function arguments,
    >>> def func(a, b=None):
    ...   if b is None:
    ...     b = []
    ...   b.append(a)
    ...   return b
    ...
    >>>
  2. When a variable has no meaningful initial value, we assign None to it.
  3. Generally is and is not operators are used in comparing None with other values. I implemented these two in !27, but your comment says something different. What do you have in mind, in regards to handing None elsewhere?
certik commented 2 years ago

Right. 3. is just the syntax if we introduce None. The 1. and 2.are the use cases, and to implement those, we effectively have to introduce a new type system in ASR that allows to define a type like list | NoneType. Possibly some types like list or any instance of a class could have a value of "null", which is represented by None. However, None is also used for things like integers, and for those the new type would be i32 | NoneType and then internally it would have to be represented somehow: either as a special integer value, or using a pointer; and in both cases we would have to insert checking at runtime, so there is a performance hit. So at least initially I would not allow i32 | NoneType until we get more experience with LPython and the performance. The list is currently representing as a 1D array. One can implement None as "unallocated", but it doesn't map exactly when you return an allocatable array, as it can be assign to an unallocatable one. The idiom:

>>> def func(a, b=None):
...   if b is None:
...     b = []
...   b.append(a)
...   return b

can be implemented in ASR using optional arguments, which is what this is. And one can use present(b) to check if the argument b is present.

Anyway, these are the issues. If you can think of some good way forward, then we can discuss it. Otherwise I suggest to wait with this until we implement more of Python, and return back to this in couple of weeks.