Marc Knaup
06/06/2019, 3:28 PMdata class
a lot - but mostly for automatically generating toString()
and equals()
, sometimes hashCode()
, rarely `copy`().
I never care about componentX()
for destructuring but noticed that their existence can be confusing to people (and me changing the order of properties breaking their code).
The general idea of having less boilerplate for simple repetitive tasks / common idioms is good. It would be awesome if developers could express with more detail what auto-generated functionality is actually desired and which is not. This also makes the actual capabilities and the intended usage of a class clearer than using a data class
that adds functionality which may not always make sense.
I know that I may be misusing data classes here and I guess I'm not the only one using them to avoid manual and repetitive implementation of toString()
, equals()
and hashCode()
. In addition to having less boilerplate the compiler can generate well-optimized implementations which are even more work & code when done manually (think for example a good hashCode()
implementation over multiple properties without boxing or platform dependency Γ la Java's Objects.hashCode(β¦)
).
I like Swift's approach where a developer can for example state that a struct
is Equatable
or even Hashable
and if all properties are too then the implementation is auto-generated by the compiler. Kotlin could do the same to make adding these method simpler.
E.g. if I add : AutoEquatable
to a class the compiler could auto-generate equals()
for me over all properties - just like a data class and potentially using the same constraints as for these.
Same for AutoHashable
-> hashCode()
, AutoStringConvertible
(or alike) -> toString()
, AutoCopyable
-> copy()
and AutoDestructurable
-> componentX()
.
A data class
is automatically AutoEquatable
, AutoCopyable
, AutoDestructurable
, AutoHashable
and AutoStringConvertible
.
@gildor suggested to use annotations instead of interfaces, which is also a good option.
There would be no need to change the language itself. The Standard Library would merely add a few interfaces and the compiler use them for auto-generating some code.
Another alternative could be to use data classes but opt out to some of its functionality, e.g. data(nocopy, nocomponents) class β¦
. That would require syntax and language changes though.
What do you think? π€Oleg Yukhnevich
06/06/2019, 3:32 PMian.shaun.thomas
06/06/2019, 3:34 PMMarc Knaup
06/06/2019, 3:35 PMOleg Yukhnevich
06/06/2019, 3:38 PMMarc Knaup
06/06/2019, 3:39 PMMarc Knaup
06/06/2019, 3:41 PMian.shaun.thomas
06/06/2019, 3:41 PMMarc Knaup
06/06/2019, 3:42 PMequals
and not hashCode
then there must be a reason for it. Just because you can compare to objects doesn't mean that they have a meaningful identity and that you can generate any meaningful hash code.Marc Knaup
06/06/2019, 3:43 PMMarc Knaup
06/06/2019, 3:43 PMkioba
06/06/2019, 3:44 PMkarelpeeters
06/06/2019, 3:49 PMequals
and hashcode
, rarely the componentX
functions and even more rarely the copy
function. There's some discussion from a couple of days ago here: https://kotlinlang.slack.com/archives/C0922A726/p1559163411143400?thread_ts=1559161518.140900&cid=C0922A726karelpeeters
06/06/2019, 3:50 PMcopy
function is not only useless sometimes, it is actively harmful: it disallows private constructors for data classes.ian.shaun.thomas
06/06/2019, 3:52 PMMarc Knaup
06/06/2019, 3:52 PMkarelpeeters
06/06/2019, 3:58 PMgildor
06/06/2019, 4:00 PMequals(), sometimes hashCode()
? Isn't they should be always implemented together to follow contract of hashCode?karelpeeters
06/06/2019, 4:01 PMgildor
06/06/2019, 4:04 PMMarc Knaup
06/06/2019, 4:09 PMhashCode
unless it makes sense to have an object as a map key or in a set or alike. I handle that more like Swift does (Hashable implies equatable but not the other way round).
I always found it unfortunate that everything in Java is both equatable and hashable even if there is no meaningful way to do so. I wish there would be proper interfaces for that.
In most classes hashCode is provided though because I use data classes for sake of being lazy with equals implementations πMarc Knaup
06/06/2019, 4:10 PMequals()
, hashCode()
and toString()
they can be stated in the interface.
It's impossible for copy()
and componentX()
though π
What would you suggest? Annotations?
I don't think that this is worth additional keywords.karelpeeters
06/06/2019, 4:12 PMjava.lang.Clonable
. I'd be happy with annotations either like @Derive("equals")
or @GenerateEquals
(both implying hashcode
too).karelpeeters
06/06/2019, 4:13 PM@Derive("component")
and @Derive("copy")
.Marc Knaup
06/06/2019, 4:14 PMisEqual
and hash
.
With Swift that was changed to Hashable
being an explicit trait rather than being implicit. I don't know if that's possible with Kotlin though looking at backward-compatibility πgildor
06/06/2019, 4:15 PMMarc Knaup
06/06/2019, 4:15 PMkarelpeeters
06/06/2019, 4:15 PMkarelpeeters
06/06/2019, 4:16 PMMarc Knaup
06/06/2019, 4:16 PMMarc Knaup
06/06/2019, 4:17 PMHashable
is probably a looot of work for everyeone.gildor
06/06/2019, 4:18 PMMarc Knaup
06/06/2019, 4:18 PMHashable
and Equatable
interfaces and added them to all classes where it made sense, to tell class users about the intended use of the class - whether it makes sense to equate/hash them or not π΅Marc Knaup
06/06/2019, 4:19 PMSet
?
I don't like the current state of that πgildor
06/06/2019, 4:20 PMMarc Knaup
06/06/2019, 4:27 PMMarc Knaup
06/06/2019, 4:31 PMraulraja
06/06/2019, 5:01 PMraulraja
06/06/2019, 5:01 PMraulraja
06/06/2019, 5:02 PMkarelpeeters
06/06/2019, 5:02 PMraulraja
06/06/2019, 5:02 PMraulraja
06/06/2019, 5:02 PMraulraja
06/06/2019, 5:03 PMmap
it can also get for free lift
and othersraulraja
06/06/2019, 5:03 PMraulraja
06/06/2019, 5:04 PMMarc Knaup
06/06/2019, 5:05 PMraulraja
06/06/2019, 5:05 PMraulraja
06/06/2019, 5:05 PMList.map
raulraja
06/06/2019, 5:06 PMFunctor
so you can match structurally and then inject in members or as extension functions whatever is more convenient for usageMarc Knaup
06/06/2019, 5:06 PMraulraja
06/06/2019, 5:06 PMmap
for freeraulraja
06/06/2019, 5:08 PMMarc Knaup
06/06/2019, 5:08 PMraulraja
06/06/2019, 5:11 PMMarc Knaup
06/06/2019, 5:20 PMraulraja
06/06/2019, 5:39 PMequals
etc implementations are hardcodedraulraja
06/06/2019, 5:39 PMMarc Knaup
06/06/2019, 5:40 PMequals
is always hardcoded as it's a method overridden from `Object`/`Any` π€raulraja
06/06/2019, 5:41 PMraulraja
06/06/2019, 5:42 PMAutoEquatable
raulraja
06/06/2019, 5:42 PMMarc Knaup
06/06/2019, 5:43 PMdata class
an equals
will be generated based on all stored properties.raulraja
06/06/2019, 5:43 PMraulraja
06/06/2019, 5:44 PMMarc Knaup
06/06/2019, 5:46 PMdata class
would just be syntactic sugar for a class which is AutoEquatable
, AutoCopyable
, etc. because that's all it is.Dico
06/06/2019, 5:47 PMcopy
. The visibility of copy
should be the same as the constructor it calls. I don't think anyone is harmed by the generation of componentX functions, hashcode equals contract complying functions and toStringDico
06/06/2019, 5:47 PMMarc Knaup
06/06/2019, 5:48 PMMarc Knaup
06/06/2019, 5:49 PMcopy
nor `componentX`/destructuring just to make a class equatable. Or maybe not even a custom toString()
.
Or have equals
be implemented differently just because I get my toString()
generated by the compiler.Dico
06/06/2019, 5:49 PMMarc Knaup
06/06/2019, 5:49 PMDico
06/06/2019, 5:50 PMMarc Knaup
06/06/2019, 5:51 PMcopy
, not because of equals
.Dico
06/06/2019, 5:51 PMDico
06/06/2019, 5:52 PMDico
06/06/2019, 5:52 PMDico
06/06/2019, 5:52 PMMarc Knaup
06/06/2019, 5:52 PMDico
06/06/2019, 5:52 PMraulraja
06/06/2019, 5:53 PMequals
if they are not final unless codegen account for all super properties.raulraja
06/06/2019, 5:53 PMDico
06/06/2019, 5:53 PMMarc Knaup
06/06/2019, 5:54 PMDico
06/06/2019, 5:54 PMraulraja
06/06/2019, 5:54 PMMarc Knaup
06/06/2019, 5:55 PMequals
or not.Marc Knaup
06/06/2019, 5:56 PMequals
and/or toString
. That doesn't mean I want the other one. Or copy. Or destructuring. It just messes with the API for the user of the data class.Dico
06/06/2019, 5:56 PMMarc Knaup
06/06/2019, 5:56 PMMarc Knaup
06/06/2019, 5:56 PMThen don't use data classesThat's why I raise this ideaβ¦
Dico
06/06/2019, 5:57 PMMarc Knaup
06/06/2019, 5:57 PMDico
06/06/2019, 5:57 PMDico
06/06/2019, 5:58 PMDico
06/06/2019, 5:59 PMMarc Knaup
06/06/2019, 5:59 PMDico
06/06/2019, 5:59 PMMarc Knaup
06/06/2019, 5:59 PMDico
06/06/2019, 5:59 PMDico
06/06/2019, 6:00 PMMarc Knaup
06/06/2019, 6:00 PMMarc Knaup
06/06/2019, 6:00 PMDico
06/06/2019, 6:01 PMDico
06/06/2019, 6:02 PMDico
06/06/2019, 6:02 PMDico
06/06/2019, 6:02 PMDico
06/06/2019, 6:02 PMMarc Knaup
06/06/2019, 6:05 PMAutoEquatable
, AutoToString
or however they're called as interfaces or annotations shouldn't be difficult to learn and can even be derived from their name (you learn them once per language).
Having to learn NOT to use some methods/destructuring of a class just because they happen to be part of a data class is much more learning (1+ per data class).
Having to manually implement these is a lot of work (1+ per no-longer-data class).
Having them generated by the IDE has its own downsides (see above).Dico
06/06/2019, 6:06 PMMarc Knaup
06/06/2019, 6:07 PMMarc Knaup
06/06/2019, 6:08 PMDico
06/06/2019, 6:13 PMTimmy
06/09/2019, 10:35 AMTimmy
06/09/2019, 10:42 AM