There’s a bit of ugliness with object-oriented development which I keep encountering, so I’m wondering if any of the locals out there have a better solution.
Specifically, my problem is that the inheritance relationship seems to be conflating two purposes in at least Java and CSharp. On the one hand, it is defining a one-way interoperability relationship: that is, a class X that inherits from Y means that wherever you could use a Y before, you can now use X, as well. In Java, this kind of relationship can be seen with BigInteger inheriting from Number: wherever a Number is called for, a BigInteger could be used. On the other hand, there is also the implementation work: a class X that inherits from Y means that class X uses the underlying implementatin of Y. This kind of relationship can be seen with Properties inheriting from Hashtable: Properties is simply choosing to inherit from Hashtable because that’s the underlying implementation.
And the conflation of these two very different purposes is complete: there is no way for X to say “I am meeting all the same contract as Y, but I am using my own implementation.” You can perform the inheritance and override all the methods, which works great until the inherited code contract changes, and now (with no compiler warning) you’ve exposed an underlying method which is built off a completely detached implementation. And that’s completely ignoring the fact that you’re still performing a full initialization on Y, even if you’re not ever going to use its faculties! For code that you control, you can always create IY, the Interface implementation of Y, but what do you do about code you don’t control. For a real work example which I have encountered, what if you wanted to implement your own BigInteger implementation (say, based on GMP?).
There’s also no way to say “I want to use all the methods of X in my implementation, but I don’t want to expose its methods to the outside world.” For a Java implementation interpretation, consider the ability to code a class as if you inherited it, but the underlying class methods all behave as private. The reason one would want to do this is because of encapsulation: what if Properties, for instance, wanted to change to get the free sorting provided by a TreeMap? Unfortunately, making the change to now inherit from TreeMap instead of Hashmap could break existing code: it’s been legal for years to work with Properties as though they were a Hashmap, and now you’re making that an illegal cast. This is likely another run-time bug that will be exposed without any help from the compiler, which means that it is a very dangerous change to be making. Yet this change can be made without any adjustment to the the conceptual entity that is “Properties”: what a properties represents is the same, and even the set of method signatures would be the same, but this new implementation could break code. The inheritance from Hashmap is just an implementation detail, yet it has become a key part of the API.
So how do you manage to keep the benefits of inheritance without exposing your underlying implementation? One solution that’s occurred to me is to ALWAYS have an Interface and a Factory for every class, but that’s a lot of noise to sidestep this programming language issue. There’s got to be a better solution — anyone got one?
Related posts:
Pingback: Enfranchised Mind
Pingback: Enfranchised Mind