Are there some fundamental restrictions for operators in kotlin, that they don’t support nulls?
It seems quite intuitively for me, if one of arguments is null, result become null.
I want to create own class for decimals Deci.kt, which would solve for me division operator (scale, rounding HALF_UP).
In addition I am thinking to allow to use nulls, but I am wondering, why kotlin doesn’t support such thing for other operators.
My personal experience is (and I think many will agree with that) that null values in math environments often mean that you have an error somewhere else in your code. In that case you want to detect that error as soon as possible.
That said kotlin is a null safe language so maybe that is an outdated view of things and could be changed.
In any case you can always create your own operators that work on nullable values using extension functions, eg:
operator fun Int?.plus(other: Int?): Int? if(this == null || other == null) null else this!! + other!!
You could also create an issue at https://kotl.in/issue to get those operators added to the stdlib. Not sure if they will be. If you do create an issue make sure to post a link here so people can find it.
The problem I see is that if operators all handled nulls silently, then there would be a real risk of forgetting about them.
We see this in Java, where the compiler doesn’t do anything to stop you trying to handle a potential null in an unsafe way.⠀(The resulting NullPointerException is probably the most common exception, showing just how badly this works.)
Kotlin improves on this not by making every access safe, but by giving a compile-time error on unsafe access (and by giving you tools to easily handle potential nulls in various ways).
Having the compiler give an error when doing something unsafe with a nullable value is useful: it forces you to think, to consider what a null would mean at that point, and how it should be handled.
And no, simply propagating the null is often not the right thing to do.⠀A null could mean many things: ‘not initialised yet’, ‘not provided’, ‘not overridden’, ‘failed’, ‘not present’, ‘empty’, ‘not authorised’, or a variety of other subtly-different things.⠀Sometimes you should substitute a default value, or avoid the whole block, or perform a calculation or DB fetch, or treat it as ‘all’ or ‘none’, or raise an error, or add a new item, or various other actions.
Kotlin is great at focusing your attention on the things that need it, and smoothing away the things that don’t.⠀I’d suggest that nulls fall into the first category.
It’s NOT intuitive. This depends heavily on the context. It may be null, may be infinity, may be uncertainty, may be undefined behavior, may be just error.
I would agree that operations with nulls makes little sense. As most of things with nulls.
But… Kotlin, as a language, allows to use nulls and provides nullable types for that. And Kotlin supports easy usage of nullables (elvis and etc) in other places.
So, even if most of things looks better w/o nulls, but in real life they still are used. An example, sometimes in practice we have mutable object with nullable fields (e.g. jpa entity) and smart cast doesn’t work for them.
Usually we need to add “!!” in formula for those fields in each place.
I would say it isn’t a big problem, as they do not pollute a code, but still it is a philosophical question, should language forbid nullables in formulas, while they are allowed in other places.
And, btw, yes, I usually try to use non-nullable variables where is possible, e.g. using no-arg-constructor plugin.
Kotlin doesn’t forbid nullable values in forumlars though. It’s just currently not allowed by the functions in the std-lib. Both @Beholder and @gidds raised a good point, that even in math enviornment null can have very different meanings and shouldn’t automatically be propogated. If this is different in your library you can always add extension methods to allow nullable values.
If the compiler won’t smart-cast a field, then there are very probably conditions in which it could be null, and so !! could throw a NullPointerException. If you’re not prepared to handle that, then you should probably look at something other than !!.
Yes, there are some situations in which you really do know something the compiler doesn’t. But in most of those cases, it’s better to tell the compiler — e.g. by using an immutable value or let or a temporary variable — than to fight it. Even if you can see that !! should never fail, it’s easy for a future code change to introduce that possibility without realising the problem.