I am in the process of learning Kotlin, and reading about the lateinit keyword makes me doubt its usefulness. Consider this code:
var testString: String? = null
lateinit var lateTestString: String
fun print() {
print(testString?.length)
print(lateTestString.length)
}
Here the only difference in getting the length of the string is by checking if it is null or not by using the ?. operator. Is using the lateinit a shortcut for not having to add that extra question mark when accessing properties or invoking methods? Just by that fact I think it is more worth having to add that extra question mark than getting an exception when accessing the lateinit one.
More research showed me that lateinit is good for injections and/or unit tests where the variable has not been initialized yet, but it will be. However, is it not worth having that extra ?. instead of just . to not risk an exception?
lateinit keyword exists to enable one specific scenario: when your field can't be null, but you also can't initialize it in the constructor or with a constant value. It is on you to make sure that you initialize the value before using it. If you don't, you get a special exception with clear meaning.
The difference between lateinit usage and "normal" nullable field with ?. is that the latter conveys a wrong message about the code: "this thing can sometimes be null". When, in fact, it can't. It is just initialized later than usual (with dependency injection instead of constructor, for example).
Is using the lateinit a shortcut for not having to add that extra question mark
Actually it's much closer to a shortcut for !!. I use it a lot in my code, for the reasons I'll try to describe.
Those two !! have been chosen deliberately to attract attention to places in the code where you "take a bet against the type system", so to speak. When used at proper places, that's exactly what you want, but what about all those vars in real-life projects which are effectively non-null, just the type system is too weak to prove it? I'd hate to see the proliferation of !! all around my codebase when I can easily ascertain they are initialized. This noise would weaken the strong signal that !! sends.
When you see a lateinit var in the code, you know you just have to look up whatever initialization method the surrounding context specifies, to convince yourself that everything's fine. It is very easy to check it's used correctly and I've never seen a bug stemming from it.
It is actually very pleasing to see the Kotlin designers putting the concerns of the real-life developer above strict type formalisms.
I'm not from the Jetbrains team, so maybe I don't have a clear picture here, but I agree with you in that lateinit looks like not a good construct.
The original idea when lateinit was added was that we have some frameworks (hint: Android) where occasionally the user of the framework does not have the access to the class's constructors (hint: Android's Activity class), to he can not initialize some property in the constructor or init block. But, due to the fact that these classes have some kind of lifecycle, we can be sure that the property foo will be initialized before it's been used for the first time, because, for example, initialization happens in onCreate(), while the property is used in onResume(), which happens later.
(Somewhere in the past, L - lazy programmer, J - Jetbrains):
L: Hey, Jetbrains! We're lazy, we don't want that extra question mark if we're sure the property will be initialized. Could we please mark it somehow to overcome Kotlin's null safety?
J: Yes, sure! Let's slap in lateinit modifier.
Wonderful idea?
No.
Because in later versions of the language its creators decided to add new syntax for the lateinit properties. I could be wrong (didn't pay much attention to it), but it looks like foo::isInitialized. The reason is that this modifier is being misused (or maybe it's flawed from the very beginning?), so we need to attach some additional checks to it.
So, basically, we're trading the question mark along with the whole null safety for the wonderful opportunity to perform foo::isInitialized checks to prevent UninitializedPropertyAccessException (or something).
lateint means later initialize
in this code you get error.
You have to initialize the lateTestString before calling it.
var testString: String? = null
lateinit var lateTestString: String
fun print() {
print(testString?.length)
print(lateTestString.length)
}
Related
The Gradle docs for lazy configuration states that in extension/DSL classes, properties like var someProperty = "default value" should actually be val someProperty: Property<String> = objectFactory.property(String::class.java).convention("default value"). This is to avoid unnecessary computation during the configuration phase;
I wonder if there is any downside in using plain types for simple values. The benefits are clear to me in case of computation or I/O, but if anything, for simple values I’d say a plain type would result in slightly less resource use during configuration (one less object created and no method calls).
The main reasons I prefer plain property types for simple values is simplicity and especially that the assignment operator can be used in a build script with Kotlin DSL, e.g. someProperty = "foo". I find this cleaner than someProperty.set("foo") and the latter is also imperative, while Gradle DSLs are otherwise mostly declarative.
It seems to work fine and in the task there would still be a Property<String> counterpart that can be initialized with someProperty.set(extension.someProperty), but since the documentation doesn’t mention it as a possibility for simple values, I’m wondering if there is a good reason for it that I couldn’t think of.
In addition to avoiding unnecessary computation during the configuration phase, using a property allows you to avoid race conditions with afterEvaluate clauses. Extension values set by build scripts are NOT available at configuration time.
Therefore, your example of task.someProperty.set(extension.somePlainField) will not work.
Using task.someProperty.set(extension.someProperty) (the method with signature set(value: Provider<T>)) makes sure that extension.someProperty.get() is not invoked until the task executes and reads its Property.
in order to achieve your goal of a fluent extension api, the recommended approach is to add a method to your extension such as
fun someProperty(value: String) {
someProperty.set(value)
}
then, build scripts can use it like:
myExtension {
someProperty("my value")
}
I've seen the following Kotlin code, which to me seems just like a more verbose way to do what a function can do. Why would anyone choose to do:
private val foo: Rect
get() = memberField
instead of doing this:
private fun foo(): Rect = memberField
It seems like the fun version is more straightforward to read, but maybe I'm missing something?
When I see the Kotlin byte code and decompile it, I see no difference between the two, so I'm mostly sure there is no difference between them. It might come down to readability, but you should be thinking in terms of state and behaviour. If you think any candidate should describe the state of the class, you should go for the getter, and if you think it should be describing a functionality or behaviour, you should go for functions.
private static final Rect getFoo() {
return memberField;
}
private static final Rect foo() {
return memberField;
}
Using a function instead of a property to simply return something is unconventional code in Kotlin. So, the downside of the function is that the code is a little less readable and easy to follow (more so at call sites than at the declaration site). Maybe not for you specifically if that’s your own style of writing code, but people might not like having to collaborate with you. :)
If the value is unchanging, you don’t need a custom getter. You can just write
private val foo: Rect = memberField
Though I’m not sure what the point of this property is if it just passes through the value of another property.
In practice you don’t frequently need to write custom getters and setters except when implementing interfaces that have properties.
I’m assuming memberField is actually a property. Fields in Kotlin are only accessible via field and it wouldn’t be possible to use it in your getter if you don’t provide an initial value for the property.
It's good to think of this from the user's perspective. Properties make sense when describing the state of an object, for example city.population rather then city.population().
This is not a hard rule, more of a heuristic.
It seems Kotlin core Data Structures (i.e. Map, List, Set) are really an interface and not really immutable.
If I have:
fun <K,V> foo(map: Map<K, V>) {
...
}
Can map change after I received it - from outside?
In which cases is it possible?
No.
The Map interface does not provide any mutator methods, so an implementation could be completely immutable.
But other implementations aren't — in particular, MutableMap is a subinterface, so anything implementing that is a mutable Map. This means that code with a reference to a Map could potentially see the data changing, even though it couldn't make those changes itself.
Similarly, MutableList is a subinterface of List, and MutableSet is a subinterface of Set.
There are immutable implementations of those top-level interfaces (such as the kotlinx.collections.immutable and Guava libraries) — and you could write your own. But the Kotlin language and type system don't yet provide strong support for deep immutability, only for read-only interfaces to data that may or may not be immutable.
(That's not to say that such support couldn't be added in future. There is a lot of interest in it, and JetBrains have been considering it.)
Let's run an experiment:
class Foo {
#Test
fun foo() {
val items = mutableListOf("A")
run(items)
Thread.sleep(1000)
items.add("B")
println("Foo")
Thread.sleep(2000)
}
fun run(items: List<String>) {
thread(start = true) {
println("Run ${items.count()}")
Thread.sleep(2000)
println("Run ${items.count()}")
}
}
}
This test case will create a mutable list of 1 item, it will then pass a reference to this list into a method whose type is for an immutable list.
This method called run will diplay the length of the list.
Outside of the run method a new item will be appended to the list.
sleeps have been added ensure that the addition to the list happen after run's first statement but before the second print statement.
Let's examine the output:
Run 1
Foo
Run 2
As we can see, the list contents did indeed change, even though run took in an immutable list.
This is because MutableList and List are merely interfaces and all MutableList implementations also implement List.
When Kotlin refers to mutable and immutable it simply references whether the methods to modify the collection are present, not whether the contents can be changed.
So if you take in a list to a method using List as the parameter type then yes, the contents can vary if they are altered by another thread, if that is a concern then make a copy of the list as the first thing your method does.
As other have indicated, the map could be modified while you're using it in another thread... however that would already be broken unless your access to the map was #Synchronized, which would indicate that you knew it would change, so this possibility is not really a problem. Even if your method took a MutableMap parameter it would be wrong if it was changed while your method was in progress.
I think you're misinterpreting the purpose of the read-only collection interfaces.
When your method accepts a Map as a parameter, you are indicating that the method will not change the map. The purpose of the read-only Map interface is to allow you to say such things. You could do (map as? MutableMap)?.put(...), but that would be wrong since you promised not to do that. You could also crash the process in various ways or run an infinite loop, but that would also be wrong. Just don't do it. The language does not provide protection against malicious programmers.
Similarly, if your method returns a Map, that indicates that the receiver must not change it. Usually in such cases, you also promise (hopefully in a comment) that the returned map will not change. You can't keep this promise if anyone who receives the map can change it themselves, and that is why you return the Map instead of the underlying MutableMap
Lombok has a neat feature to use var instead of local variable datatype declarations. Is there a way to "refactor" your entire code base automatically to use var whenever applicable? I'm using IntelliJ IDEA and the Lombok plugin. I didn't find a feature like this.
Also, does it even make sense since var is still considered "experimental" so it might "mess up" the code base when it gets deprecated/is somehow bugged/gets replaced/moved?
No.
Moreover, I wouldn't recommend this.
Being explicit is always better so IMHO var is only good when the cost of being explicit is too high. This is only the case with lengthy LHS where the same information is repeated on the RHS.
Use diamond operator (or factories). Not that var list = new ArrayList<>() can't work as you removed the type parameters from both sides.
Prefer val to var. With val not being longer than var, there's no reason not to use it (unlike when separate final is needed). This way, you can see what variables may change.
I'd bet the Lombok authors would agree with me, so they won't support such a feature. I hope the same holds for the plugin author.
Is there an elegant/convinient way (without creating many "empty" classes or at least they should be not annoying) to have fluent interfcaes that maintain order on compilation level.
Fluent interfaces:
http://en.wikipedia.org/wiki/Fluent_interface
with an idea to permit this compilation
var fluentConfig = new ConfigurationFluent().SetColor("blue")
.SetHeight(1)
.SetLength(2)
.SetDepth(3);
and decline this
var fluentConfig = new ConfigurationFluent().SetLength(2)
.SetColor("blue")
.SetHeight(1)
.SetDepth(3);
Each step in the chain needs to return an interface or class that only includes the methods that are valid to use after the current step. In other words, if SetColor must come first, ConfigurationFluent should only have a SetColor method. SetColor would then return an object that only has a SetHeight method, and so forth.
In reality, the return values could all be the same instance of ConfigurationFluent but cast to different interfaces explicitly implemented by that class.
I've got a set of three ways of doing this in C++ using essentially a compile time FSM to validate the actions. You can find the code on github.
The short answer is no, there is no elegant or convenient way to enforce an order of constructing a class that properly impelemnts the "Fluent Interface" as you've linked.
The longer answer starts with playing devil's advocate. If I had dependent properties (i.e. properties that required other properties to be set first), then I could implement them something like this:
method SetLength(int millimeters)
if color is null throw new ValidationException
length = millimeters
return this
end
(NOTE: the above does not map to any real language, it is just psuedocode)
So now I have exceptions to worry about. If I don't obey the rules, the fluent object will throw an exception. Now let's say I have a declaration like yours:
var config = new Fluent().SetLength(2).SetHeight(1).SetDepth(3).SetColor("blue");
When I catch the ValidationException because length depends on the color being set first, how am I as the user supposed to know what the correct order is? Even if I had each SetX method on a different line, the stacktrace will just give me the line where the config variable was declared in most languages. Furthermore, how am I supposed to keep the rules of this object straight in my head compared to other objects? It is a cocophony of conflicting ideals.
Such precedence checks violate the spirit of the "Fluent Interface" approach. That approach was designed for conveniently configure complex objects. You take the convenience out when you attempt to enforce order.
To properly and elegantly implement the fluent interface there are a couple of guidelines that are best observed to make consumers of your class thank you:
Provide meaningful default values: minimizes need to change values, and minimizes chances of creating an invalid object.
Do not perform configuration validation until explicitly asked to do so. That event can be when we use the configuration to create a new fully configured object, or when the consumer explicitly calls a Validate() method.
In any exceptions thrown, make sure the error message is clear and points out any inconsistencies.
maybe the compiler could check that methods are called in the same order as they are defined.
this could be a new feature for compilers.
Or maybe by means of annotations, something like:
class ConfigurationFluent {
#Called-before SetHeight
SetColor(..) {}
#Called-After SetColor
SetHeight(..) {}
#Called-After SetHeight
SetLength(..){ }
#Called-After SetLength
SetDepth(..) {}
}
You can implement a state machine of valid sequence of operations and on each method call the state machine and verify if the sequence of operation is allowed or throw an exception if not.
I will not suggest this approach for Configurations though, it can get very messy and not readable