Hacker News new | ask | show | jobs
by closeparen 2555 days ago
You can change the internal representation while doing transformations in the getter to preserve compatibility.

With collections, you can export contents through an Iterable, or to Array, or any number of other strategies, without coupling the consumer to your internal representation.

1 comments

Of course, but what I am questioning here is how often we really do change internal representations of simple data structures. The theoretical benefit of hiding every representation behind an interface is clear, but any abstraction also has a potential cost if it creates a barrier to doing something useful and/or becomes leaky.

You can still provide standardised interfaces for things like iteration along with a data structure even if you choose to expose the specific representation, so I am not sure how strong an argument your second point makes. Depending on the situation, you may find your consumer is implicitly coupled to the true representation anyway, perhaps because it inadvertently relies on values being iterated in sorted order or insertion order or because it assumes certain performance characteristics even if these things are not strictly part of the documented interface. More than once in programming history, even standard libraries of popular programming languages have been updated to guarantee some behaviour that had been reliable in practice but was never actually part of the original specification.

My perspective is from a heavy Java background.

By using the standardised interfaces for everything you can change the implementation without changing how you work on it.

For example, my service that stores a collection in a database. I could write my service so that it takes in a Collection, rather than an ArrayList, because then anyone using it can pass in a Set (no duplicates), CopyOnWriteArrayList, TreeSet (ordered set).

By hiding internals and using the interface, I can pick the abstraction I need and give more freedom to those using my classes.

Another example. Once Project Valhalla and Value types come in, LinkedList might be changed to use value types for Nodes. Lets say I've tightly coupled my code to the implementation of LinkedList. This could potentially break my code.

And there is nothing wrong with writing generic code like that! Just because you can access the specific representation of the underlying data, that does not mean you have to or would do so routinely. In languages that do tend to expose simple data structures directly, it is still normal to provide standardised tools for accessing and manipulating them, and most of the time that is probably still how you would interact with them.

Regarding your second example, if you are working with an explicit representation then you simply would not make a breaking change like that. Instead you would create a new data structure with the new representation, which other code can then choose to use instead if it wants to. Again, nothing about this prevents both versions from also providing equivalent functions to access them in the same way where that makes sense or writing other code in terms of those functions rather than tied directly to the specific implementation.