anyone want to give me their philosophy of when to...
# announcements
a
anyone want to give me their philosophy of when to use data classes vs interfaces?
i.e., for a config would you use a data class or an interface?
I think data class to discourage unnecessary polymorphism… but at the same time having a config be polymorphic is kinda nice … if I wanted to say a config is a subset of another
idk if you understand what I am saying… a lot of this is just late night rambling
lmao
k
I use data classes for my configurations although not for polymorphism.
d
Use an interface if you can forsee different implementations being used. data classes are really just that: they hold data, maybe with some minimal behavior attached. An interface actually models some behavior, usually.
👍 4
c
I was just explaining my take to a coworker yesterday! Basically, interfaces are useful for mandating certain behavior in an application, or for having multiple implementations of the same behavior. Any “data” (properties) in an interface are really just a manifestation of behavior, rather than actual data itself. So use an interface when you expect to “call” an object and be returned as result. Additionally, interfaces can be used to ensure that classes conform to the contract, and a compiler error will be thrown if the contract changes and the implementations do not update to handle the new api. In contrast, data classes should be the opposite, just data and (ideally) no behavior. You shouldn’t really do much to the object itself other than pass it from one place to another. They are good for packing data, serializing it, passing it around, copying/manipulating it, etc. But you cannot guarantee that a given class will use all the fields of the data class passed to it correctly, so they cannot reliably mandate any kind of behavior.
👍 3
a
So if I were to make something to encapsulate other behaviors? (i.e., group interfaces) think I should use a data class? I guess you could say this is kind of like a “god object” but it really makes everything soooo much cleaner in a lot of instances.
c
A favorite pattern of mine for this case is interface delegates. You make one “god interface” which extends a bunch of other interfaces. The implementation can inject instances of each sub-interface and delegate all methods to it. Then all behaviors are accessible from a single object, but concerns are still properly separated out into individual classes. Again, since you’re trying to capture behavior, not state, it’s better-suited to be set up with an interface
👍 1
Here’s an example of me doing this (in Java, but I plan on eventually migrating it to actual Kotlin class delegation): “God interface” - https://github.com/JavaEden/Orchid/blob/dev/OrchidCore/src/main/java/com/eden/orchid/api/OrchidContext.java implementation - https://github.com/JavaEden/Orchid/blob/dev/OrchidCore/src/main/java/com/eden/orchid/api/OrchidContextImpl.java
👍 1