Accidentally omitting get silently results in wrong behavior

I often use read-only calculated properties, like this:

var sizeInBytes = 0
val sizeInBits get() = sizeInBytes * 8

The problem is that I often accidentally omit get() = and get this instead:

var sizeInBytes = 0
val sizeInBits = sizeInBytes * 8

It compiles without a single warning and what I get is a simple constant read-only property. Testing catches this, naturally, and it’s not that big of a problem, but it’s still somewhat annoying.

I’m not sure whether it’s possible to fix it without too much effort. One idea is to forbid placing getter on the same line, like when both initializer and getter are present. But it will waste some vertical space and force a lot of people to reformat a lot of existing code, so it’s far from a perfect solution.

I don’t think there is any solution to this (except for proper testing). It is impossible to detect for a program if you made a mistake or not in this case. Also I don’t think any syntax restriction (like putting the getter on a new line) would help, as you forget to type this just as easily.

It would be nice if we could have a Color Scheme rule for this in IntelliJ. Then everyone could decide how they want this to look like in the IDE.

1 Like

Actually, there is a solution: move non-essential properties to extensions. You can’t access fields from extensions so you can’t make those errors. Of course, sometimes you need for property to be in class…

Extensions are somewhat inferior. They are good for extending 3rd party classes and for providing generalized algorithms for a set of classes implementing an interface, but for something that belongs to a class by design? It makes perfect sense to have sizeInBytes and sizeInBits together. The fact that one of them is a field and another is a calculated property is just an implementation detail. Maybe I will revert it later so that sizeInBits will be a field and sizeInBytes will be a calculated property (sizeInBits divided by 8, round up).

I really like the idea of a color scheme, though! Perhaps different highlightings for a read-only field and a calculated property?

Have you read the latest article by @elizarov?

Not until now. An interesting point of view, but debatable. Certainly not applicable in my example. I do use extensions heavily, but I do use read-only calculated properties as well, whatever makes sense design-wise.

I am not saying that you should move everything to extensions, but it is the way things tends to be done in kotlin. I also gradually moved from traditional inheritance oriented design to extension-oriented one even before diving deeper into stdlib and reading this article. The extensions are just more powerful. Static dispatch and ability to declare them on the use site instead of class declaration site is very hard to underestimate. The only bad thing about extensions is that they are hard to navigate without IDE.

That’s not the only thing that is hard in Kotlin without an IDE. One must accept that Kotlin is not usable without an IDE. Especially when reading code.

Well, this is probably an off-topic, but still, I do not completely agree with you. Have you tried to read large multi-cmake-module c++ project? Or JS project with external library dependencies?

I’ve recently read a lot of kotlin code from github (i.e. without IDE), and I can say, that it is reasonably readable. You have to jump between files a lot, but it is the problem with any highly modularized code. Explicit imports also help a lot.

I am not criticizing Kotlin for this. I think it is a good development that modern languages are designed with IDEs in mind.

How is the extensions are more powerful? I’ve read this article and I’m not convinced. I can provide default method implementation in interface. And, what’s more important, I can override that implementation if it makes sense. Simple example: length property for collection could be implemented by simply iterating over entire collection and counting items. And it might make sense for linked list, for example. But, obviously, you would want to override it for arraylist. For me extension function only makes sense for types that I can’t alter. The fact that they are separate from the class definition is only makes them less discoverable.

Custom highlighting of the declaration with getters might be a good idea, please submit a feature request at http://kotl.in/issue. Somewhat similar: https://youtrack.jetbrains.com/issue/KT-13578.

Created feature request at https://youtrack.jetbrains.com/issue/KT-30806

2 Likes

Do we even need another issue? KT-13578 seems to cover this pretty well.

I would like to highlight the opposite: a property that has no get, and keep the get without special highlight.

That’s personal taste I think.

The new feature request will give developer most flexibility to decide for himself.

The article is interesting, but I disagree with most of it.
Defining extension functions to separate state properties from calculated is IMHO misuse of the feature. Instead define calculated ones as methods. The example is very much artificial, so arguing about detail makes no sense, but proposed mix in the single interface would rase big question in my mind.

Extension functions allows to do many other things like functional programming, DSL programming, etc. They are very helpful, but not in the way suggested in the article.

@stachenov in your case I would define base property in constructor to accomplish distinction made by article. It won’t help with typing correct definition :wink:

Isn’t the thing to detect here that you have a val field initialised from a var field (and/or constructor param, perhaps)? That seems like something which is quite likely to be a mistake, and might merit a compiler warning. But maybe people can come up with enough examples of when you really would want to do this…

1 Like