Interface implementations are not just found using factories. You can use compile or link time alterable implementations.
Scott Meyers recently sent me some comments on “Interface-Oriented Design”. He described a few concepts and ideas that the book should have covered in more detail.
One of the points he made regards something that I’ve used in the past, but did not really think about when writing the book. An interface does not have to be represented with an “interface” keyword or equivalent and then implemented by code using “implements” in Java or ":" in C++.
You can establish an interface as a set of methods, along with a test framework that clarifies and enforces the requirements for the methods. You then create different source code modules that provide that same set of methods. At either compile or link time, you specify which module to use for a particular version of the executable. A particular implementation of the interface can be compiled using conditional compilation. Alternatively, a different object module can be linked into the executable.
For example, you might have different types of hard disks that you are using in different versions of an embedded system. You first establish a standard hard disk interface. Using the appropriate source code modules, you implement the hard disk interface for each specific type of hard disk. Now these modules do not use the keyword “implement” or equivalent. They just provide all the methods in the interface.
At link time, you incorporate the module corresponding to the hard disk that you are using on a particular piece of equipment. Using directly linked modules eliminates the overhead of virtual function calls.
In addition, if you are using C++, you include the corresponding module header file in the code that uses the interface. If there were inline functions in that header, you would get a performance benefit.
It's unfortunately not a law - just a really good idea for creating modular, portable code. It is also good for the preprocessor if you only have to include one header to the interface and it's just a list of virtual functions.
When you talk about inlining the function calls, I take it you are not using virtual functions, but are using conditional compilation to select the interface? Only useful when you've only got one implementation in your project (e.g. per platform again).
In Python, Ruby, and some other dynamically checked languages, this is called "duck-typing". A more formal name might be "implicit interfaces". Using this style can enable an extensive and fairly effortless flexibility. Thinking about it from this perspective also leads to the powerful idea of subset interfaces. E.g., in Python, if you supply a file-like object, but you only need to use its readlines() method, then you only have to implement its readlines() method.
It's also a style that can render code somewhat opaque, especially if you're not looking for it. It would be interesting to see a language with type inference, duck typing, and support for explicitly-declarable subset interfaces.
(Haven't read your book yet; so, apologies in advance if all of this is covered in there. But it did seem to me that in the Amazon reviews of the book, every mention of "object oriented programming" should be replaced with "explicitly statically-typed object oriented programming".)
> I do this in C++ all the time. > > It's unfortunately not a law - just a really good idea for > creating modular, portable code. It is also good for the > preprocessor if you only have to include one header to the > interface and it's just a list of virtual functions. > > When you talk about inlining the function calls, I take it > you are not using virtual functions, but are using > conditional compilation to select the interface? Only > useful when you've only got one implementation in your > project (e.g. per platform again).
It is also possible to inline virtual functions if the type of the object is known at compile time. A very simple case: run-time dispatching of virtual functions is only performed for pointers and references.
Also, if you really need to avoid virtual function calls for performance reasons, I would prefer templates to conditional compilation in most cases.
Unfortunately, no language supports this. It's all hacks like #ifdefs or manual library selection. Virtual methods still include code you don't need. It's an old problem that no one has addressed because VM's and all that is supposed to be portable. It doesn't change the fact that different requirements need different solutions. So it comes up again even in those situations. Templates are nice if you can use them, but they can't be used all the time, especially if you use external code.
The D programming language does attempt to support platform dependent code in a slightly better way than #ifdefs and manual library selection - but it is still pretty close to #ifdefs, and I am not sure what advantages it imparts, maybe only better syntax checking? See http://www.digitalmars.com/d/version.html
However, I only know about the D language by reading about it. Does anybody have experience using this feature of D, and whether they like it? It still looks pretty clunky to me.