But not much on traits and ADTs(?).
Can you recommend some general learning resources on that?
ADTs are Abstract Data Types[1][2][3]:
> ADT is implementation independent. For example, it only describes what a data type List consists (data) and what are the operations it can perform, but it has no information about how the List is actually implemented.
In the context of Rust it means that the traits, structs and enums are ADTs, while the impls are Data Structures.
Having structs and enums be the way they are in Rust (simplistic and with little extensibility beyond implementing traits) is that pattern matching[4][5] and destructuring is cheap and built in. Pattern matching becomes specially useful when combined with sum types/tagged unions/enums[6][7][8]. On the other corner you have Scala which lets you implement specific interfaces to allow structuring and destructuring for arbitrary types, but that has the same problems as overriding constructors in C++: the performance implications of pattern matching is impl dependent and hidden at the point of calling.
[1]: https://softwareengineering.stackexchange.com/questions/1487...
[2]: https://en.wikipedia.org/wiki/Abstract_data_type
[3]: https://abrickshort.wordpress.com/2005/03/06/abstract-data-t...
[4]: https://en.wikipedia.org/wiki/Pattern_matching
[5]: https://docs.scala-lang.org/tour/pattern-matching.html
[6]: https://www.schoolofhaskell.com/school/to-infinity-and-beyon...
[7]: https://chadaustin.me/2015/07/sum-types/
[8]: https://stackoverflow.com/questions/2502354/what-is-pattern-...
I'm basically looking for a comparison of classes and ADT, I guess.
You said, applying your class-based way of doing things didn't work, so I asked myself how would you do it the ADT way.
The distinction is similar to database design in SQL: the Schema is how the data is laid out and what the relationship between tables is (ADTs) while the queries is the operations performed on them (traits). On the other hand, in OOP there's a higher reliance on encapsulation, making behavior an integral part of what the class is and using inheritance for expansion. When all you have is ADTs, you _can't_ have inheritance, so you end up using composition (which is generally considered better design) and you are more likely to rely on the creation of "new-type" container types for everything. You think of them as a way to describe what the data is, not how you interact with it.
Apologies if this is a bit hand-wavy, I'll try to write a more thoughtful answer at a later time.
[1]: https://medium.com/javascript-scene/the-forgotten-history-of...