I think kotlin syntax and the design is overall beautiful. But the distinguish between nullable and non nullable types is unnecessary. Even I doubt that this design is able to protect me from NPEs. I think, introducing these different types, makes the programming more complicated. It has similarities with C++, where on one side you have pointers (nullable) and references (normally non nullable) with different method call semantics. In kotlin, e.g.
foo.bar()
foo?.bar()
foo!!.bar()
When I start a Android Project with kotlin, all the types are nullable types. So that means I use on Activity and Fragments 2) and 3) to call methods.
Null pointers are inavoidable. Considering that projects are very rarely without dependencies. Whatâs about user input in any variation, e.g. web applications etc? Whatâs about data sources, e.g. csv files, excel sheets, database tables etc.?
I donât need to mention a framework⊠it is enough to mention a web service in usage or a developed library important to the domain (developed in java). I see you can isolate every dependency and do it fine. So I donât see the benefit towards java because it is the same effort/work to do.
On the other hand, it is hard to predict when to use nullable types or non nullable types. I fear the people will use nullable types by default.
You are wrong. Nullables are avoidable, but this is not the point. Kotlin encourages to explicitly state nullability of the value when it comes from java and respects nullability annotation from most commonly used systems (including Android nullness annotations).
Absolutely not true. It is arguable whether null pointers are avoidable on a JVM. But keep in mind that the JVM is just one of the possible compilation targets. Kotlin is a higher level language that provides means to 100% avoid nullpointers. This does not mean that you cannot write Kotlin code that throws a nullpointer. It depends on which platform you target and which platformâs stdlib you use.
I 100% agree with you.
That being said, you can create a NPE in kotlin by leaking this from inside a constructor and the compiler so far has no way of preventing this (even when not targeting JVM). In this case it is up to the programmer to ensure that no NPE happens but it is an edge case in which compiler performance trumps safety IMO.
Yeah, I remember something like that from the Kotlin Puzzlers talk.
But I would classify that as a bug in the compiler. It is not an intended or inherent feature of the language. The nullpointer that we are talking about generally are coming from intended features that provide JVM compatibility.
Some data inconsistency with regard to initialization, such as when:
An uninitialized this available in a constructor is passed and used somewhere (âleaking thisâ);
A superclass constructor calls an open member whose implementation in the derived class uses uninitialized state;
I would not call it a bug. It is an intended weakness of the nullability system, because the other alternative would be to either prohibit many calls from within a constructor or increase compile time by a lot, due to complicated static analysis, which is not worth it because this is an edge case.
Because of this problem, Joshua Bloch recommends to make all functions that are called from within a constructor either private or final.
Kotlin could easily have enforced this recommendation, which would have eliminated one of the two causes of the nullpointer exception.
For the other case I donât see a feasible solution. But it is such a specific case, it could be argued that it warrants to have its own exception type, eg UninitializedInstanceAccessException or the already existing UninitializedPropertyAccessException.
This strikes me as very strange. Sometimes you need the a concrete representation of ânothingâ becuase you donât have anything. Sometimes youâre not (and cannot be) furnished with a value until later. Sometimes you want to pass a value along that is nothing on purpose.
I declare ânullâ values for all value types (integers, reals, and custom ones) in addition to reference types becuase I find them so fundamental. It was a good design decision that makes the code conceptually clean and consistent.
Maybe youâre making some other point. If something cannot be null then I check for it, just like other invalid values. It never causes any problems. I find this sort of âcoerciveâ language design annoying, but luckily Kotlin is less aggressive about it than say Swift.
This is not about possibility, but about your personal code style. Even in Java you can avoid nulls by using Optionals. Some languages do not have nulls at all.
Even if nulls were unavoidable, that doesnât mean that the Kotlin type system is bad. There is empirical evidence of teams switching a codebase to Kotlin and it removes most, if not all, of the NPEs the program generated.
As for people defaulting to nullable types everywhere, this is also completely unsubstantiated. People want to avoid having to deal the with null as much as possible, so they default their types to nonnullable until they find out that the variable needs to deal with it. And even if the language makes it easy to deal with null, people tend to transform the null to some sort of default value quickly so they donât have it propogate.
As hard as it may sound, IMO, nulls not only should be avoidable, but not possible at all. All though Kotlin thoughtfully provide as? to cast cast-able, in Java you can downcast null to Object and then cast it to literally any other type.
Integer i = null;
Object o = (Object) i;
Runnable r = (Runnable) o;
One shudders to imagine what inhuman thoughts lie behind that code, but itâs still possible and, ironically, will only work with null.
From this point of view I believe Optional is far superior way to represent âmaybeâ values.
Rustâs way to do that is my favorite: Option in std::option - Rust
Optional has different pros and cons to kotlins null system. I would not call it far superior. I would not even call it superior.
IMO kotlins null system does exactly the same thing as Optionals do. Itâs a way to tell the type system that a value can be null, which enables the compiler to force you to check the existence of a value before accessing it. Kotlins null system does exactly that. Does that mean that kotlins null system prevents all ânormalâ variables from being not null? No, but that is not possible on the jvm as long as you leave the kotlin eco system.
The same would be true for optionals. Optionals donât stop java passing null where it is not supposed to and Optionals donât stop you from doing stupid stuff using reflection.
Could Kotlin prevent the problem with NPEs in constructor calls. Yes, but that also has nothing to do with Optionals vs the nullable types.
I never have used rust before so I canât compare the nullable types with rusts optionals. Does rust have null at all or is rust just using Optionals instead of null? In that case, this is one way of solving the NPE problem, but I would not call it the only way.
Also you have to consider that kotlin is limited by the features of the JVM so comparing kotlin to rust is not always fair. When comparing to system languages though (lets say kotlin native vs rust) I think Optional vs the way kotlin does it, is just a question of syntax. Yes in the background they work differently but this does not really matter to the programmer (in most cases. I wonât argue that knowing those details is not important). The effect of both of them is the same: removing NPEs where not intended by the programmer.
For a system language yes, but on the jvm I donât see how you could prevent all nulls when interacting with java. What stops java from passing null as an argument when a Optional is expected, what stops it when it expects a non null type?
Same goes for your example. I donât see how it can be used as an argument for Optionals. Well yeah I do. Optional.None (or however you might call it) still contains type information while null doesnât. But does that really affect any real world problem. There will always be ways how people can write bad and unnecessarily stupid code. Systems like Optionals or kotlins nullable types arenât supposed to prevent us doing that. They are there to prevent mistakes when we donât pay attention. Nothing will ever stop any programmer who wants to write stupid and bad code. (Also there is a valid argument to be made for the idea that null should not hold any type info).
Optionals, hypothetically, hold type info, nullables in Kotlin as they are donât (Even Optionals in Java as far as I know donât). Thus casting null to Any? and then back to anything else is quite possible.
Casting hypothetical Optional of some type A to Optional of some type B is, ideally, only successful when cast of type A itself to type B is possible.
Rustâs Option is just template union type.
âOptionâ is the only safe way to represent value that might not be there
(Technically there is ptr::null, but it can only be applied to raw pointers, which are uncommon and only in use when some system-level or ffi stuff is taking place)
As long as Optional doesnât hold type info â yes
Null and nullable types, in the very case of its usage (when value is null), donât hold type info.
When some nullable value is actually present â itâs all fine. But null does not have itâs own type nor it knows of which type it should be therefore when nullable value of ambiguous type is not present it theoretically can be casted to anything. So that it is possible to end up with code that works fine as long as nullable value is not present.
And, as far as I know, the problem solved when Optional type holds type info independently of valueâs presence.
Optionals are just type-safe, language supported nulls with features that force you to deal with them in certain restricted ways. You cannot avoid nulls, nor the ânoneâ side of optional values or whatever you want to call nulls, even with type safety or any other form of language safety.
Your example illustrates this. The null value has a null type (which includes only the null value), which is a subtype of all types, so it can be assigned to any type, exactly becuase the concept of null is natural (and logically necessary) for all types.
Youâre confusing the type of a variable with the type of a value. The type of a variable is a constraint on what types of values that variable can hold. Optionals have a type, as do nullables, itâs just they can contain an extra value besides their ânaturalâ values, namely the ânoneâ or null value.