Python has only one way of saying ‘there is nothing here’: None. Java has the keyword ‘void‘ and the value ‘null‘, kotlin has Unit, Nothing and null. What is the actual difference in meaning for all of these?
The Python None is a singleton object of type NoneType. In fact, python needs only this one way of saying ‘Nothing to see here’. There are several uses of ‘None’.
Firstly, ‘None’ is the default return value for any function that does specify a return type, the equivalent of this in Kotlin is the return type of Unit. If a function in Python ends with the word ‘return’ with value to return, then the function will return a value of ‘None’. If the function has no return statement at all, then it will also return None.
Secondly, ‘None’ can be an alternative value to any expected type, the equivalent use pattern to the ‘null’ in Kotlin or Java.
def add(a:int, b:int=None): if b != None: return a+ b # function ends with no return if it gets here, so will return None
A variable can also be set to ‘None’ there is currently no value for that variable.
Further, a parameter can default to None, to indicate that no value was supplied.
If a python program is actually declaring types (as with the parameter ‘a’ in the above example, then allowing None as an alternate value requires Union types, (e..g union of int and None as the type signature) but most code does not specify types, and Union types are reasonably concise if they are needed. The above example saying ‘b’ is an int, then providing a default value of ‘None’ which is not an ‘int’ would be strictly speaking, breaking the rules. However Python never enforces following rules for types.
Kotlin Unit, null and Nothing.
Unit is the direct equivalent of Python None, however it is not as convenient in Kotlin to use Unit for all normal uses of None in python. The main use of Unit, is that Unit is default return type for functions. The main type Unit actually appears in code is when defining lambda parameters for functions. Normal practice is to declare Unit as the return type for lambda function when the return value is not needed.
null is special value of a pointer indicating no object. This differs from Unit (and the python None) which are actual objects. There is no null object. In Kotlin (and Python) all values are objects accessed via reference pointers, and null is a special value of the reference pointer itself indicating an invalid reference pointer. When a variable has no object to reference, then the referent value null indicates ‘no object’. Unit (or Python None) , is an object so there can be a regular reference pointer to this object. Setting an variable with no object to reference to refer to the Unit object, would be setting the reference to a different type as Unit is its own type. Python can set any reference value to None, as variables are dynamically typed, so any variable can validly reference None. In a strongly typed language, the python approach cannot work since a default object cannot match every desired object type.
Kotlin also has another concept: Nothing. The type Nothing is also a return type, and while Unit return type indicates a function does not return a value of significance, Nothing indicates the function does not return at all. ‘Never Returns’ would be another way of saying this. Any code that follows a call to a function with a return type of Nothing, is code that will never be reached.
Java void and null
void in Java is plays an equivalent role to None in Python or Unit in Java. The difference is the void is not an object or a type, but language syntax. This is inherited from the language C and as an approach is necessary because the language also deals with primitive types which are not objects. Note that a function which returns void in Java implements ‘runable’ while a function which returns a value implements ‘callable’, while in Python and Kotlin all functions are effectively ‘callable’. In place of void, languages having all data being objects (as in Python and Kotlin) use a special singleton object to indicate no real return value type. The singleton object is perhaps a little more elegant than void, but I an not aware of any real problems arising from void as a solution. Since void is not a real type, you cannot declare a variable of type ‘void’ and thus cannot store the value of a void function.
null in java performs as a direct equivalent to null in Kotlin. However, since Java has explicit primitive types such as ‘int‘ in addition to object types such as Integer, not all types can have a null value, as null is only applicable to objects (as objects are access by a pointer).
None/Unit vs null
In both Python and Kotlin, values are always objects, and thus have references or pointers for accessing their value. null is a special reference value that indicates ‘do not even follow this reference to see what is there, this reference is not valid’. So for any value set to null, the reference has this special value. Testing for null is testing the reference pointer contains this special value, testing for None/Unit is following the reference and testing the object that is discovered.
In the end, there is the tiniest of overheads in following the pointer to test what is there in place of simply testing the value of the reference. Null Pointer exceptions occur when an invalid (null) reference value is followed to see what is at the reference location. But in Python if None is used in the manner of null, the effectively equivalent error of NoneType object has no attribute ……’ occurs. This is the Python equivalent of null pointer exception, The fact that variables cannot be declared without assigning them a value (or an object to reference) does reduce these errors. Raising exceptions in place or returning None values also reduces NoneType exceptions, but increases other exceptions.
The concept of Nullable
A significant feature of Kotlin is nullable types. The way Kotlin handles nullable types allows a changed approach to programming, and the foundation requires understanding what nullable means. As an example, an Int has range of numeric values, but a nullable Int (Int?) adds an extra value, null, that is a way to say ‘there is no Integer here at all’. This concept works for any type. Simple add the ‘?’ character at the end of the type specification to indicate that additional value, and the additional value can be detected as not being a valid value of the type specified.
Consider a function to convert a string to an integer. Here is some code in python and kotlin:
// first the python example number = int("123") //now kotlin val number ="123".toInt() val num2 = "456".toIntOrNUll()
The first difference is that the python way is to use a function, and the kotlin way is to use a method. The bigger difference, is in the idiom for handling when the ‘int’ conversion will fail. The standard python approach is to raise an exception, so ‘int(“1ab’) will raise a ValueError exception, which can be caught in a try/except or occur as an error at runtime. The kotlin approach is to facilitate returning a null value and have language support that makes it easy for the programmer to process, in addition to having null safety to ensure whenever a value of null is possible, it is dealt with.
It is easy to add a ‘toIntOrNone’ function in python, and this could emulate the toIntOrNull in Kotlin, but there are some key differences. Firstly, None is a another type of object, making the function return two possible return types( Int or None). Union types can be handled in Ptyhon, but would be more complex in a strongly typed language. Secondly Python does no have ‘None Safety’ which leads to risk of ‘Nonetype Object has no attribute..’ errors.
If we include explicit types, then the superficially equivalent code would be:
// first the python example number:Union[int, None] = intOrNone("123") //now kotlin val numb1: Int = "123".toInt() val num2: Int? = "456".toIntOrNUll()
Python code is not written this way, but Kotlin is. The first reason Python is not used this way is that declaring number as ‘Union[int, None]’ is not only a lot of typing, it also doesn’t actually achieve anything since it doesn’t tell the language itself that number will be one of these two types.
In Kotlin the Int? is not only just one extra character, but even that character is not needed as the language infers the type because it is the return type of ‘toIntOrNull’. But far more importantly, the way ‘null safety‘ works may dealing with these two possible outcomes simpler than any solution available in Python.