Something that has been bugging me for a while. Wh...
# announcements
g
Something that has been bugging me for a while. What is the reasoning behind not allowing
latinit val
in Kotlin?
s
If you have set up the dependencies of the class that has this
val myLateVal
correctly, you can use
by lazy
to postpone evaluation of this val.
val myLateInitFullName by lazy { dep1.firstName + "." + dep1.lastName }
m
Fundamentally,
val
implies immutable. But
lateinit
means it won't be set right away, and will be changed at some point to point to something real.
var
makes that aspect clear. I also suspect
var
was chosen as we're being trained to not want to see
var
, so we'll be more inclined to look at alternatives. Constructor injection,
lazy
or other approaches so that we don't have a
var
in our code.
☝🏻 3
g
In a local function, you don't have to set a
val
immediately, so technically all local
val
variables are optionally
lateinit
. The only thing I can think of is that they did it because of concurrency reasons. For instance, in Dart, they allow late final fields, but Dart is single-threaded.
d
lateinit
was designed primarily for interop with "injection by magic" frameworks, e.g. DI without constructor injection. In those cases
lateinit
marks a property as publicly accessible and designed to be modified by third party code. Because it's third party code you cannot guarantee that it's not going to be modified more than once. So it's a
var
g
Sure, with setter injection that makes sense. But why not have a
lateinit val
also just for everyday use? It doesn't have to be final when it compiles to Java. It can be a normal variable but the immutability is enforced by the Kotlin compiler.
d
That's what
by Delegates.notNull()
is for.
lateinit
fundamentally only works for reference types
g
I just read about
Delegates.notNull()
, and that is not what its for at all. It is basically
lateinit
for primitive types. How does it allow you to do a
lateinit val
exactly?
d
Maybe I am misunderstanding you then...
And
notNull
is definitely not just for primitive types.
g
Thats what it was designed for... if its not a primitive type you might as well just use
lateinit
. https://americanexpress.io/advanced-kotlin-delegates/
d
lateinit
is a kludge for interaction with "lets inject stuff into fields" frameworks.
Delegates.notNull()
is a standard built-in delegate for properties that will be initialized at a later point in time.
lateinit
is not just "this will be initialized later", it also has
@JvmField
built-in.
g
Ok, but it is used quite regularly just for the purpose of initializing the variable at a later time. So it would be nice if
val
had that as well. Other languages do, and the only reason I can see Kotlin not having some sort of feature like that is for concurrency reasons.
d
This sounds like the job for a built-in delegate, maybe
Delegates.initializedOnce
.
In general you don't want a new language syntax for every small feature
g
And that would only work at runtime, no developtime or compiletime catching
d
lateinit var
also has no compile-time checking.
What kind of compile-time checking do you propose? How would the compiler "know"?
g
I don't claim to be a compiler expert, but other language have this feature I am speaking of, with development time and compile time checking, so it is do-able
d
What kind of compile-time checking is done? Like, which kind of errors are reported?
g
lets you know if it was initialized twice
or if you try to use it and it hasnt been initialized
d
There is no way for a compiler to proof that, unless we are speaking about local values, which already have this.
g
there is a way
d
No, it's the halting problem effectively.
g
You can do it right here
d
What am I looking at?
g
I will create it for you and send the link
d
ok
g
well I feel like an idiot, looks like you are correct. I guess I didn't play around with this as much last night as I thought. This is what I was thinking would get development time and compile time checking though:
Copy code
class Test {
  late final String value;
  
  init(){
    value = "test";
    value = "test";
  }
}
If you copy and paste that into https://nullsafety.dartpad.dev/ you'll see that you are correct, my mistake
d
No worries. But think about it, as soon as you have complex conditions involved (possibly even involving things like network requests) there is no way for the compiler to prove this.
It's effectively the halting problem.
g
Havent had any actual CS since I got my BS in CS about 10 years ago now, so didnt consider the halting problem. But I understand now