interface ExampleInterface {
val x: Int
}
class ExampleClass : ExampleInterface {
override val x = 5
// override val x get() = 5
}
If I look at the decompiled code, the uncommented override without get() creates a field in ExampleClass. I understand why that happens for non-primitive values, but is it necessary for primitive values? For primitives and Strings, I would expect to get:
public final class ExampleClass implements ExampleInterface {
public int getX() {
return 5;
}
}
instead of:
public final class ExampleClass implements ExampleInterface {
private final int x = 5;
public int getX() {
return this.x;
}
}
It seems like an obvious optimization and a way to make code look cleaner, for example I vastly prefer this:
Why would it be cleaner? The exposed API is absolutely identical in both kt and Java, there’s now way to tell the difference unless you decompile, I believe.
I think what @al3c means is: Do you only care about optimization or do care about the look of the decompiled code?
As you stated, you can already write it the way you want and behind the scenes, it creates a getter–however your comment about the look makes it seem like you care about it even though you’ll never see the code any other way (unless you decompile or look at bytecode).
As far as optimization goes, it’s always good to avoid pre-optimizing. The JVM has a way of making code that should have poor performance run great–you don’t know until you profile. There’s a chance there could be no noticeable slow down unless you heavily tuned a benchmark to find it in an edge case. It would also vary by platform.
This kind of optimization should be possible for internal code but couldn’t be done to an exposed API as normal changes would be a breaking changes.
You can do some profiling. If it turns out to be a noticeable performance issue then people will take interest. A while back someone noticed a String method had terrible performance and showed the evidence and people on the forum contributed a fix.
Optimizations are made on evidence of performance not on speculation of performance.
EDIT: Made the mistake of which part is private. This optimization isn’t impossible for exposed APIs–my bad
I care about not using memory on a field when a simple constant load and return would suffice in this case. I’m unable to find any indication that the JIT will eliminate non-static final fields only used in returns so that they don’t take any space in memory, and I cannot imagine how it could even do that.
A single int isn’t a big deal, but give the class a few longs and make a million instances of it, from my testing 4 longs and 1M instances without get() waste about 30 MB (which checks out with the math of 4×8×1M bytes).
I guess to clarify, I want to be able to write code on the first screenshot
override val a = 45
override val b = 0
because it looks cleaner than get() everywhere, without having to worry about wasting memory if I do this in a class that will have many instances. I understand why Kotlin works the way it does to support the difference between these two lines
override val a = Object()
override val b get() = Object()
but for primitives and Strings (and I suppose whatever else will end up in the class’ constant pool) these two approaches seem semantically identical, with the caveat that one “secretly” uses more memory.
Maybe someone can correct me if I’m wrong but I think this kind of optimization is possible for any value-type that doesn’t produce side-effects. Literals are the easy ones since no side effects are a given.
I’d have to look through the value-type KEEP again to see if there’d be some hidden gotcha’s I’m forgetting. It would be interesting to see how value types would add to this.
EDIT: I’m still suspicious that there’s something missing. I haven’t run any useful tests so I’ll just join with speculation
This would be a breaking change due to reflection. There are enough libraries out there that use reflection to access private fields that this is not a pure optimization.
That’s true, then the question is if it’s okay to make this breaking change. I see no issue if it’s done with a major version bump. The only reason I can think of why you’d reflect into the field instead of the method is if you wanted to change its value, but then you’re relying on an implementation detail - not always the best idea, as a lot of people found out when Java 9 arrived.
Keeping the documentation simple is a compelling reason to not introduce such a change IMO.
The idea that val x = <something> means different things based on the type of x is not something that will make learning Kotlin easier.
The proposal also has a “do what I want, not what I say” feel to it that seems out of step with Kotlin’s direction of requiring coders to be explicit.
In my project it happens a lot. The field in question is a descriptor that provides some metadata for tge concrete instances and the return values are enums. There is a huge number of instances and I need to use get() to avoid wasting memory.
I’m not actually suggesting that this feature should be implemented. I’m personally OK with the current behaviour and I just wanted to mention a case where this difference is actually important.