Summary
It is commonly assumed that in order to achieve some measure of run-time polymorphism we have to state in a class declaration that it it either implements an interface or it inherits from a base class with virtual functions. Not anymore ...
Advertisement
It is generally assumed that In C++ in order to achieve run-time polymorphic behaviour, we have to inherit from a base class with virtual functions. Java, and other languages also provide us with interfaces, but the classes have to explicitly state their intention to implement the interface.
This is a misconception that a lot of people understandably have when they first hear about the C++ Object Oriented Template Library ( OOTL ). In the September 2004 issue of the C/C++ Users Journal I outline a technique in C++ for implementing interface reference types without requrining changes to existing objects. This technique is used in the upcoming Boost Interfaces Library (BIL) by Jonathan Turkanis. The BIL is not yet ready for a public beta release, but a pre-release version has been included with the OOTL version 0.1.
Given two existing class such as:
class Faz {
public:
int Fu() { return 1; }
void Bar(int x) { printf("faz %d\n", x); }
}
class Baz {
public:
int Fu() { return 2; }
void Bar(int x) { printf("baz %d\n", x); }
}
The BIL can then be used to express an interface after these classes have been defined elsewhere as follows:
You will have to put the blame for the ugly syntax squarely on the shoulders of the C++ design committee, not Jonathan. C++0x will surely enable improved syntax, especially if Jonathan or myself have anything to say about it ( in fact I would like to see interface references gain first class status ). The BOOST_ prefix, is a requirement for consideration in Boost, which clearly is the eventual goal of the BIL.
Once we define this interface, after the fact, we can use it to make Faz and Baz, polymorphic. Consider the following:
int main{
faz f;
baz b;
IFuBar i;
if ((rnd() % 2) == 0) {
i = f;
} else {
i = b;
}
i.Bar(i.Fu());
}
This code snippet prints out either faz 1 or baz 2.
And that's all I have to say about that.
> BOOST_IDL_BEGIN(IFuBar) > BOOST_IDL_FN0(Fu, int) > BOOST_IDL_FN1(Bar, void, (int, x)) > BOOST_IDL_END(IFuBar) > > You will have to put the blame for the ugly syntax > squarely on the shoulders of the C++ design committee, not > Jonathan.
You should probably put the blame on the preprocessor implementors. With a standards compliant preprocessor, it would be possible to do something along the lines of:
Even if it isn't portable, I would like to be able to describe alternatives approaches, so this code would be a valuable contribution to the community.
Just add the macro stuff to your existing library and it should work (on gcc that is). Pretty ugly though.
Here's an alternative version which uses Paul Mensonides' chaos library. It requires a fully compliant C99 preprocessor (for variadics). This allows for a much nicer syntax and a simpler implementation. Although I'm not sure whether I'm using chaos correctly.
There was a series of papers about structural typing in Java in the middle 90s. Laufer's 'Safe Structural Conformance for Java' and Weck's 'Compound Types' papers are good reads.
Chris, you should put some code examples on your site. The implementation-oriented one in your article does a great job of explaining "how it works."
> There was a series of papers about structural typing in > Java in the middle 90s. Laufer's 'Safe Structural > Conformance for Java' and Weck's 'Compound Types' papers > are good reads.
I am not familiar with structural typing, is it the same thing as what I propose?
> Chris, you should put some code examples on your site. > The implementation-oriented one in your article does a > a great job of explaining "how it works."
> It is generally assumed that In C++ in order to achieve > run-time polymorphic behaviour, we have to inherit from a > base class with virtual functions. Java, and other > languages also provide us with interfaces, but the classes > have to explicitly state their intention to implement the > interface.
In C++ and Java - indeed. But most dynamically typed languages, and among statically typed: OCaml, Haskell, Clean and Mercury, already allow to have a common interface for multiple types with no need of declarations at the point of definition of the types. It's not a new idea.
GNU C++ used to have an extension with this property, called signatures. It has been recently removed because people weren't using it, the original author was no longer interested in maintaining it, nobody else wanted to maintain it, and interfered with further development.
Right now, our target platforms are VC7.1, Intel 8.0, GCC 3.4 and Comeau 4.3.3. VC7.1 is the problem child -- not just with respect to the preprocessor.
I haven't had a chance to think about it yet, but being able to use the syntax
may allow me to simpify the implementation considerably, since it will allow the code currently generated by the function declaration macros to dovetail.
Marcin, I would ask if you would please refrain from making any more comments on my blog and discussion group. I have been very patient, but your comments are consistently negative, irrelevant and unwelcome.
> > There was a series of papers about structural typing in > > Java in the middle 90s. Laufer's 'Safe Structural > > Conformance for Java' and Weck's 'Compound Types' > papers > > are good reads. > > I am not familiar with structural typing, is it the same > thing as what I propose?
It is typing based on structural equivalence. class A { int a(); } and class B { int a(); } could both be passed to a context accepting something that needs an a().
A bit different from what you are proposing, but it seems to rely on it. I've long thought it was interesting that structural equivalence typing was considered very bad in the heyday of language development. I think there is even in an admonishment in K&R, but then they were talking about data predominately. Later, templates come along and 'structural equivalence' wins. The rationale is that it is okay because templates always resolve to strongly typed code in the base language, C++.
> > Chris, you should put some code examples on your site. > > The implementation-oriented one in your article does a > > a great job of explaining "how it works." > > Thanks for the suggestion. Is the example such as: > http://www.ootl.org/src/object-test.hpp an example of what > you would be looking for?
Actually, I was thinking of the implementation code. I see you put it up yesterday in the CodeProject? That snippet of code that shows how someone would hand-code an interface. When I first your articles, I kept thinking "okay, he has to be using function pointers. If he's not, there is some way to resolve using templates that I don't know yet." Had to wait until I got home to find your article and understand what the approach was.
> In C++ and Java - indeed. But most dynamically typed > languages, and among statically typed: OCaml, Haskell, > Clean and Mercury, already allow to have a common > interface for multiple types with no need of declarations > at the point of definition of the types. It's not a new > idea.
I've wondered quite a bit how aware many in the C++ template community were of the ML languages. Seems like the key difference is that people in that community seem to always bring things back to a declared type rather than allowing free structural matching like we have with C++ templates. C++ tenplates are sort of compile-time 'duck typing.'
> GNU C++ used to have an extension with this property, > called signatures. It has been recently removed because > people weren't using it, the original author was no longer > interested in maintaining it, nobody else wanted to > maintain it, and interfered with further development.
That looks like what Chris is talking about. Is that it, Chris? It would be neat to see what the author thinks of it now. It is funny. Sometimes the time isn't right or something needs to be championed differently.
> I've wondered quite a bit how aware many in the C++ > template community were of the ML languages. Seems like > the key difference is that people in that community seem > to always bring things back to a declared type rather than > allowing free structural matching like we have with C++ > templates. C++ tenplates are sort of compile-time 'duck > typing.'
The interfaces technique now allows a more explicit and rigorous typing that can't be easily achieved with templates alone.
> > GNU C++ used to have an extension with this property, > > called signatures. It has been recently removed because > > people weren't using it, the original author was no > longer > > interested in maintaining it, nobody else wanted to > > maintain it, and interfered with further development. > > That looks like what Chris is talking about. Is that it, > Chris?
It is pretty much the same thing as far as I know, except I am doing it in compliant C++, not as a language extension. I don't know how the implementation went for the Signatures feature.
> It would be neat to see what the author thinks of > it now. It is funny. Sometimes the time isn't right or > something needs to be championed differently.
That is true. I think the reason the old extension was dropped for several reasons: 1) language extensions are ignored by the majority of software developers in favour of writing portable code 2) people lack the imagination to see how techniques can be used. This is a big reason why the OOTL exists, as a proof of concept of the BIL.
Flat View: This topic has 21 replies
on 2 pages
[
12
|
»
]