Generating useless classes


#1

Kotlin generates new unique class every time code ::CLASS used.

class AA( @JvmField val name:String )

fun main(args : Array<String>) {
  ::AA
  ::AA

  AA::name
  AA::name
}

For every use of ::AA or AA::name new unique class generated. All this classes absolutelly the same except new number.
Why to generate new class for same source?
The code, which uses these properties (GUI with props bindings) grows in size unreasonable fast because of this duplicates.

Is it known bug and will be fixed?


#2

It is a known problem, described here: https://youtrack.jetbrains.com/issue/KT-15690 It lacks some real-life examples, though, so it would be great if you can add comments there with links to some real-life code.


#3

Ok, its known. Hope will be fixed because its really annoying.
Im not really shure what u mean under “real-life” examples.
F.i. Im currently forced to use reflections to setup bindings in swing GUI because application with references nearly twice as big.
Its little bit hard to create small example for such usage.
As example, here is code from tornadofx with same problem:

class Room(val id: Int, val number: String)

tableview(rooms) {
  column("#", Room::id).contentWidth(10.0, true, true)
  column("Number", Room::number).weigthedWidth(1.0)
...
}

Here used some DSL to constuct GUI model and link it to data using references.
Same data is used in different GUI models, and number of models can be unlimited.
Each referense adds 1.5-2Kb to application size.
With several models which uses same class “dummy” classes takes more space then application logic in final JAR.


#4

A “real-life” == not a small example. A link to some git repo or a gist with some app we can compile and launch would be helpful. The example you’ve posted here does not really have reference to the same field. It has “Room:id” and “Room::number” which refer to different properties, so solving KT-15690 does not help this one. Maybe your problem is different and is not related to KT-15690?

To help you, we need to understand the exact nature of your problem. You say its “twice as big”. That would be a great example to see – some real-life example of the code (it can be a bit synthetic) that becomes twice as big with references. Also, some rationale on why that is a problem for you. Working though references in Kotlin is definitely much faster than via reflection, despite the added size. What is you domain where this added size is annoying so that it trumps performance? What is the total size of your app? How much references add to it? How that is compared to the rest of the stuff you ship? The more context you provide, the better. It adds up to a list of motivations to start working on some kind of fix.


#5

I just developing library and dont have huge examples to show, just care how usage of this library will looks like from the user point of view.

In the upper example you saw only two reference, but, as I mention, its possible what there are MANY usage of references to the same objects.
Imagine not only one table but ten tables, lists and trees each of them display same data in different forms. Plus many inplace editors and form dialogs.
Multiply these two fields by number of GUI representations and youll get unreasonable big part of application contains absolutely useless code.

The whole topic is not about add memory to user workstation or increase its partiotion to allow run application of any size.
Its about a bug in Kotlin code generation.
The referenses to any class, all its fields - are constants so thay must be represented by singletons.
I saw the topic in Kotlin bug-tracker and see the problem is known. Hope it will be fixed soon.

PS: Yep, reflections are slower but most of overhead affects only GUI setup stage, which is not a big deal. Use of Kotlin references a little faster but add huge overhead in size affecting whole application forever.
Plus, I personally hate to use expressions known to be ineffective in the speed or size and, as lib developer, I trying to guard users from such implementations.


#6

I found easy workaround for problem - to declare singletons for references by hand and use them instead of creating new one on every usage.

class Room(val id: Int, val number: String) {
  companion object {
    val ID = Room::id
    val NUMBER = Room::number
    val SELF = ::Room
  }
}

tableview(rooms) {
  column("#", Room.ID).contentWidth(10.0, true, true)
  column("Number", Room.NUMBER).weigthedWidth(1.0)
...
}

May be it will be usefull to someone.