> I'm not familiar with the language you are writing in
It's Java (though I don't usually use that language).
> "ListNil<T>" fills exactly the same role a "NULL" so what you have created is exactly a NULLable pointer, only with a different name and more complex syntax.
No, it's not the same thing. As was pointed out multiple times by now, null references can show up everywhere, even in places where they don't make sense and where nobody ever intended or expected them to do. On the other hand, ListNil<T> objects are allowed only allowed where lists are allowed, and any sensible program that operates on lists expects those lists to end at some point (in eager languages at least).
> Your argument against NULL would seem to apply equally to the value '0'.
No, 0 isn't something that somebody just made up. If you don't have 0, you can't add two integers as the only sensible result of adding x and -x is 0. So yes, the fact that you can't divide by 0 is a problem, but getting rid of that is hard. No such argument can be made for null.
I also dislike the fact that null mixes up many different concepts that ought to be separate. null was used to represent optional values, empty lists, empty trees and probably all kinds of other things which don't have anything in common.