Steffen
Posts: 4
Nickname: steffen
Registered: Aug, 2005
|
|
Re: Interfaces or Abstract Base Classes?
|
Posted: Aug 18, 2005 5:33 PM
|
|
I quite agree that 'ad hoc polymorphism' (aka 'overloading') is 'richer' (or more powerful) when combined with a 'richer' (or more extensive) method/operator/function signature. By combining strong typing and interfaces, you get two additional dimensions of functionality. This multiplies ones options. It is more 'flexible'. It is can be considered more 'expressive'. Yet either new dimension of functionality can be supported either in isolation or in combination.
I rush to agree that without sufficient programming language 'flexibility'/'expressiveness', one could end up forced to hand code run-time type checks on untyped arguments. As far as I can tell, you illustrate the necessary work arounds perfectly.
Still, it seems like a non-sequitur to conclude that strong typing (e.g. typed method/function arguments) are always 'better' for any programming languge. Python, for example, has abstained from the complexities of strong typing for a number of very specific reasons.
There is a price to pay for Python's 'simplicity'. The performance price is well understood (and often discussed). The lack of strong typing also affects the 'flexibility' of any 'ad hoc polymorphism' (aka 'overloading'). This might be yet another price to pay for the sake of simplicity. Perhaps the aggregate price of Python's simplicity (via weak typing) is starting to add up. As new features come into the Python language, weak typing might be more and more onerous. Perhaps the price of weak typing simplicity is getting too high? Perhaps not?
Should we always seek to add more and more features to Python? Must Python become as 'expressive' (and/or baroque) as C++? Is more always better?
Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Antoine de Saint-Exupery
By the way, I figure that you are also quite correct about the potential software engineering benefits of type checking. Strong typing adds signficant value - from earlier 'type checking' feedback. A type checker automaton can be darn diligent about reliably catching whole classes of errors and omissions ...
This software engineering benefit *is* very similar to the benefits of an 'interface' contract. Yet Python's simplicity is at stake.
The more-is-better argument is a slippery slope. Sometimes, languages optimized for different purposes are better than one language that tries to be all things for all purposes. While we're talking about programming langauges, this point is perhaps even clearer with respect to domain specific langauges (DSLs) -- if anyone happens to follow these.
Permit me to try an analogy. I own a cross-bike. A cross-bike is a blend of a mountian bike and a road bike. It is great for puttering around with small children (on paved surfaces). It isn't great for a road race. It isn't great for single track trails (up/down mountains). The cross-bike is a nasty compromise - but it'll get you everywhere. All the same, the better solution is to have *both* a mountain bike and a road bike. With *two* different bikes, I get the best of all worlds. I always have the choice of a bike optimized for what I want to do. Now that I've got two such bikes, I realize that the cross-bike is really not very good for anything in particular. Dare I say that cross-bikes should be considered harmful?
If you'll permit me to spin a weak metaphor from this lame analogy, I'm hoping that Python does not become a cross-bike.
Personally, I quite like Python as my quick-n-easy, RAD/agile language. I sort like the way Python pairs up with C++ (and/or interfaces to C++). Take performance conerns. Careful C++ code can be really fast. Good luck trying to get a cross-bike-style language (like Java) to match C++ performance. I know, this is a long-standing flame war. A whole lot of folks wish that Java was faster than C++ for every application ... but it isn't. A lot of folks wish that RAM/disk footprints of JAVA programs (and J2EE/JVM support environments) were just as small as statically linked C++ programs - but they aren't. Reality sucks. A cross-bike is a cross-bike.
The Python/C/C++ language bundle is probably better than *any* single language could *ever* be. I'd hate to see Python become yet another Java/C#/C++ equivalent. What's the point?
I quite agree with the 'interface' semantic you seem to illustrate. Lets say that there is a graphical object class hierarchy. Lines, shapes and dots (pixels?) might be specializations. Shapes might specialize into regular/geometric/vector shapes and irregular/raster shapes. All geometric shapes might have properties/methods/accessors like these:
name (an enum like "triangle", "square", "rhombus" ...) center_point, locus (or locii[] ...) edge_color_depth, edge_red_value, edge_green_value, edge_blue_value, fill_color_depth, fill_red_value, fill_green_value, fill_blue_value, edge_luminosity, edge_width, fill_luminosity, edge_color_transparency, fill_color_transparency, edge_texture_name, edge_texture_transparency, fill_texture_name, fill_texture_transparency, texture_light_source_x_offset (from center point) texture_light_source_y_offset (from center point) : : : :
Now there might also be a interface hierarchy for 'color'. The root 'color' interface might require only a bunch of fill_* color property/accessors. This can be specialized into a 'Edged_Color' interface when a bunch of 'edge_*' properties/accessors are available.
There might also be a interface hierarchy for 'Texture'. The root 'texture' interface might simply require some property/accessor named 'fill_texture_name'. A variety of more specialized texture interfaces might refine the vague concept of 'Texture' in various ways (e.g. the Shaded/3D texture 'interface', the gradient/2D texture 'interface', etc.).
My point is simply that strong typing is *NOT* required. I've made no use of strong types in this elaborate Shape/Color/Texture example. If anything, I've hinted at user-defined type extensions like enumerations - and other such base/machine-type (object/property/argument) 'constraints'.
I'm also trying to illustrate the 'alternate abstraction' (i.e. perspective) 'interface' semantic. It seems we agee on this purpose for the 'interface' concept.
I'm suggesting that all of the 'implementation' logic/code for the shape classes be organized into Shape class hiearchy. Such 'interfaces' would be assert/express commonalities/hierachies from other possible 'perspectives'.
As I mentioned, I'd avoid scattering 'implementation' code/logic into any of the alternate 'interfaces' hierarchies. This would lead to either some form of 'aspect oriented programming' (and code weaving) or to multiple inheritance (from multiple, concurrent type hiearchies). Neither of these results is very 'simple'. I'm all for keeping Python as simple as possible ;-)
At the end of the day, I'd try to solve 80% of the common/typical needs with something 20% as complicated. It is the last 20% of the needs - the corner cases - that usually requires 80% of the complexity. In other words, I'd suggest
* Weak typing (continue w/duck typing) - This seems best as a separate debate/discussion * Alternate abstraction 'interfaces' only - Various 'perspectives' on the class hierarchy - limited! No core/class implementation logic/code. No property additions via interface decl. No multiple inheritance. No implementation weaving. * Adaptation - accept constraint logic/code in interfaces > match to constraints applied to class decls (e.g. support optional enums?) - accept mapping/glue logic via interface decl > when possible, such mapping/glue logic conforms a given set of class instances to a desired 'interface'. > class specific 'wrapper'logic within the 'interface' decl.
|
|