The Artima Developer Community
Sponsored Link

Weblogs Forum
Attempting to Define Interface Oriented Programming Languages

52 replies on 4 pages. Most recent reply: Feb 10, 2006 3:38 PM by D. Charles Lee

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 52 replies on 4 pages [ « | 1 2 3 4 | » ]
James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: Attempting to Define Interface Oriented Programming Languages Posted: Dec 29, 2005 10:10 AM
Reply to this message Reply
Advertisement
> > If I understand the difference would be like the
> > difference between how static methods and object
> methods
> > are treated in Java.
>
> I am not sure I follow, but I wouldn't make that
> comparison. I am trying to say that in an IOPL, the only
> method of dynamic dispatching would be through interface
> references, thus eliminating the need for virtual and
> abstract functions.

I understand what you are getting at now. But the comparison holds. static methods do not require dynamic dispatching in Java. Non-static methods do.

An interesting idea to be sure. I think it might have one drawback, however. If I implement an interface and add a few methods to it, no one can extend my new class effectively if a new interface is not defined. It's not insurmountable but could cause problems for the unprepared.

James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: How C++ programmers think Posted: Dec 29, 2005 10:23 AM
Reply to this message Reply
> There exists different opinions on this matter. :) (Java
> makes you make the same choice - final or not final, but
> the default is the opposite of C++)

Again, this is not correct. Making a method final doesn't make in non-virtual. It makes it possible for the runtime to inline it but this is side-effect of it's true purpose: disallowing overriding. If I'm not mistaken, you can extend a class in C++ and define the same method on that extended class whether it is virtual or not. The only truly non-virtual (compile-time-bound) methods in Java are static methods.

> It would be nice if we
> didn't have to - in advance - specify something as virtual
> or non-virtual, and instead have the compiler figure it
> out, but the problem is that the full knowledge for doing
> this is only available at link time, and many environments
> allow dynamical linking at run-time.

In a way this is what the JVM does. With the new escape-analsys coming in 1.6 (which allows for stack-based allocation) this could can become more effective.

> Whether something is a feature or a flaw, should be
> determined based on the design goals of the language (then
> one may instead judge _them_, based on what they aim at,
> or what one wants), and based on C++'s design goals -
> which included not paying for what you don't use, as well
> as compatibility with C, I think it may be argued that a
> non-virtual default is a reasonable choice, and not a
> flaw, considering the goals.

Sure, but I feel that from the development perspective, it's a flaw. Or at least for my purposes it is. The cost of the lookup is small compared to potential cost of refactoring the code.

Christopher Diggins

Posts: 1215
Nickname: cdiggins
Registered: Feb, 2004

Re: Attempting to Define Interface Oriented Programming Languages Posted: Dec 29, 2005 10:30 AM
Reply to this message Reply
> I understand what you are getting at now. But the
> comparison holds. static methods do not require dynamic
> dispatching in Java. Non-static methods do.

Only virtual functions (in some circumstances), or calls to an interface method require dynamic dispatching. Dynamic dispatching means the function address is not known until runtime. Non virtual methods addresses can be resolved at compile-time.

> An interesting idea to be sure. I think it might have one
> drawback, however. If I implement an interface and add a
> few methods to it, no one can extend my new class
> effectively if a new interface is not defined. It's not
> insurmountable but could cause problems for the unprepared.

Heron doesn't have the limitation.

I should mention that Heron doesn't require interfaces to be explicitly implemented, but rather a duck-typing mechanism is used. I am unsure of whether or not that feature should be part of the criteria used to define an IOPL.

Keith Gaughan

Posts: 17
Nickname: kgaughan
Registered: Feb, 2003

Re: Attempting to Define Interface Oriented Programming Languages Posted: Dec 29, 2005 10:31 AM
Reply to this message Reply
Even after everything that's been said in all the other replies, I don't see the efficacy of an IOPL. Maybe you should read up about traits (http://www.iam.unibe.ch/~scg/Research/Traits/), or take a peek at John Cowan's posts on his weblog: 'OOP without inheritance' (http://recycledknowledge.blogspot.com/2005/06/oop-without-inheritance.html), 'Divided Classes: Having your subclassing and not eating fragility too' (http://recycledknowledge.blogspot.com/2005/04/divided-classes-having-your.html), and 'Celebes Kalossi: Who knows best?' (http://recycledknowledge.blogspot.com/2005/08/celebes-kalossi-who-knows-best.html).

James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: Attempting to Define Interface Oriented Programming Languages Posted: Dec 29, 2005 11:21 AM
Reply to this message Reply
> > I understand what you are getting at now. But the
> > comparison holds. static methods do not require
> dynamic
> > dispatching in Java. Non-static methods do.
>
> Only virtual functions (in some circumstances), or calls
> to an interface method require dynamic dispatching.
> Dynamic dispatching means the function address is not
> known until runtime. Non virtual methods addresses can be
> resolved at compile-time.

Why are you stating what I clearly must know to make the above point? Are you not understanding? Static methods in Java are not virtual. Non-static methods are. Is there something that you do not get about that?

> Heron doesn't have the limitation.
>
> I should mention that Heron doesn't require interfaces to
> be explicitly implemented, but rather a duck-typing
> mechanism is used. I am unsure of whether or not that
> feature should be part of the criteria used to define an
> IOPL.

How is that? If a developer doesn't use an interface and then later another developer realizes that was a mistake, how does Heron eliminate that problem?

Christopher Diggins

Posts: 1215
Nickname: cdiggins
Registered: Feb, 2004

Re: Attempting to Define Interface Oriented Programming Languages Posted: Dec 29, 2005 11:28 AM
Reply to this message Reply
> Why are you stating what I clearly must know to make the
> above point? Are you not understanding? Static methods
> in Java are not virtual. Non-static methods are. Is
> there something that you do not get about that?

Sorry I was hasty and overlooked the fact that you were talking about Java in particular.

> How is that? If a developer doesn't use an interface ...

In what context do you mean? Doesn't use an interface how? Doesn't use it as a function parameter, doesn't explicitly implement an interface, doesn't define an interface?

James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: Attempting to Define Interface Oriented Programming Languages Posted: Dec 29, 2005 11:59 AM
Reply to this message Reply
> In what context do you mean? Doesn't use an interface how?
> Doesn't use it as a function parameter, doesn't explicitly
> implement an interface, doesn't define an interface?

Any or all of the above I suppose.

Max Lybbert

Posts: 314
Nickname: mlybbert
Registered: Apr, 2005

Re: How C++ programmers think Posted: Dec 29, 2005 1:19 PM
Reply to this message Reply
/* [talk about vtables]
As I understand it, Java does essentially the same thing.
*/

I believe so.

/* My understanding was that determining version of the method to call based on the type of the Object was what takes a long time. I'm not convinced 'going through a pointer' is slow. In fact, passing an address to a method is often going to be faster than copying all the data in the Object from one area of memory to another.
*/

Well, in the implementation I described (thanks Terje for the correction!), the pointers are used to determine the correct version of method to call. That is, each object may promise that a pointer to the function that implements the method "make_sound()" is going to be at an address 100 bytes into the object class (this gets a little more confusing with multiple inheritence, but not all that much). Then, when I ask an object to make_sound(), behind the scenes, the computer first determines it has to look 100 bytes into the object to find the pointer, then it follows that pointer to find the correct function to really call, and then calls it.

Without dynamic dispatch, the computer only goes to the correct address for the implementing function, and starts executing the directions there.

You're right that using pointers can be efficient some times. However, pointers-to-functions are generally going to be slower, unless the compiler is able to optimize out the pointer.

/* I've not been following CDs language closely but Heron supports pass-by-value semantics, there will always be a pointer involved.
*/

Yes, but those are pointers to data, not pointers to function. That is where passing pointers can go faster than passing (potentially large) objects. Of course, reading or writing to data through a pointer is going to be slower than access without a pointer. Pointers to functions just create an extra step before calling the function (except when optimized out -- thanks Terje!). But pointers to functions can point to different functions throughout the lifetime of the program, which is why they're useful here.

/* In any event I didn't get the idea that using this technique would change anything about whether the references were pointers, just that the method binding would be done at compile time.
*/

Yeah, that's true. Terje set me straight. There are no pointers, conceptually speaking, just potential speed hits. And as long as the program *behaves* correctly, it doesn't matter whether there are pointers. OTOH, the implementation may well create those pointers, and that creates the speed hit. By moving the dispatch to compile time, you can get a more efficient system. That is what I understand the benefit to be.

Max Lybbert

Posts: 314
Nickname: mlybbert
Registered: Apr, 2005

Re: How C++ programmers think Posted: Dec 29, 2005 1:34 PM
Reply to this message Reply
/* [me] C++ Programmers have to decide to make methods "virtual" in order to allow OOP practices. They know that doing so has a performance penalty

[Terje] Not necessarily. Whether or not a call is resolved at compile-time or run-time is an implementation detail, but if not enough information (for that specific compiler) is available at compile-time to make the decision, then it will be resolved at run-time.
*/

Thanks. That's true.
/* [me] C++ fakes classes by creating a structure that holds all the data, and then defining all methods as functions that take that structure as a hidden argument.

[Terje] could you explain what you mean by this implementation method being used to "fake classes"? In this case, how do you define "real" classes, and can you provide any "authority" as to what should be the proper definition of "class"?
*/

Many beginning programmers believe the methods are actually laid out in memory right next to the data of an object. That could be done, but since the various methods are going to be identical functions, it's much more common to lay out any necessary vtables and the data in the object itself, and make the methods functions that can be found when needed.

That's what I mean by "fake classes." In truth, that's not a Computer Science term. It's just something that comes as a bit of a surprise to beginning programmers.

I'm not aware of any authority for the terms. OTOH, show Java programmers object oriented C code (such as the Linux kernel), they'll almost all say "Oh, I get it -- they're faking OOP!"

/* [me] The sticky problem is making sure enough information is around at compile time to resolve the interface question.

[Terje] Indeed, and you may not even have that information at that time. However, a design that dispatches at compile-time when it can, and at run-time otherwise, and doesn't require inheritance from a common base class or interface, is an interesting idea, and would nicely fuse a mechanism like C++ templates and inheritance-based polymorphism (inclusion polymorphism), giving the "duck typing" of templates at run-time, without requiring dynamically typed variables (as in script languages). As I understood from an earlier posting by Christopher in another thread, Heron either had, or might have such a feature.
*/

It's supposed to go into Heron. While I'm working on Heron right now, I've spent most of that time working on the documentation for the parser (http://www.ootl.org/yard/), so I can't say if this is in there yet.

Max Lybbert

Posts: 314
Nickname: mlybbert
Registered: Apr, 2005

Re: How C++ programmers think Posted: Dec 29, 2005 1:42 PM
Reply to this message Reply
/* If I'm not mistaken, you can extend a class in C++ and define the same method on that extended class whether it is virtual or not. The only truly non-virtual (compile-time-bound) methods in Java are static methods.
*/

You're right about C++. However, if you take a pointer to the pointer to the parent class, and point it at a child, you won't be able to call the extended versions of the methods. In order to do that, you must use virtual.

And thanks for the correction regarding Java, final, and static methods.

Max Lybbert

Posts: 314
Nickname: mlybbert
Registered: Apr, 2005

Re: Attempting to Define Interface Oriented Programming Languages Posted: Dec 29, 2005 2:02 PM
Reply to this message Reply
/* Using the interface oriented system instead, does this mean that there is no inheritance allowed? And that substitutability comes from a class matching the interface only? And so all functions must be reimplemented in new classes? Or only that we may not use abstract (unimplemented functions) in base classes?
*/

The interface system described doesn't try to fix this substitutatbility issue. The system itself could be used with inheritance, if desired (but Heron won't have inheritance if I understand correctly) -- the two ideas are othogonal.

However Heron does have a contract mechanism, and contracts could be used to sanity-check any class that has the correct interface so that you know more than just the function signature.

/* So: Is the only drawback of the old inheritance mechanism that you have to use virtual function call mechanism?
*/

It's not really the only problem. Another problem is complex inheritance trees. Java tried to solve this with single inheritance, but that leads to worse abominations than multiple inheritance. So Java relaxed the rules to have single inheritance and interfaces. It's become a popular solution among real programmers, so I can't really badmouth it.

However the interface mechanism that CDiggins is referring to would attack that problem in another way.

Imagine you are writing a cross-platform desktop application. You've chosen the gtkmm GUI toolkit (http://www.gtkmm.org/) because it acts more like the STL than Qt does. However, every so often you want to create a new widget. Sometimes that widget exists in Qt, and sometimes you have to create it using whatever native APIs are available (X Windows for Linux, Quartz for Mac, and the Windows API for that other platform). Contrary to popular belief, it's possible for all these toolkits to work together (with caveats -- I wouldn't try putting a Qt button on a gtkmm window, but I would let clicking a gtkmm button bring up a platform-dependent native print dialog).

In the IOP world, you could leverage the fact that many of the widgets available are going to have similar interfaces, even though they have been independently developed. You could design a window that takes any button from any toolkit, so long as that button models the correct interface (and you could create a class to adapt buttons that come close), and then use interfaces to call "clicked()" or "disable()" without needing to keep up with the multiple inheritance graph.

Max Lybbert

Posts: 314
Nickname: mlybbert
Registered: Apr, 2005

rewording some sentences Posted: Dec 29, 2005 2:14 PM
Reply to this message Reply
Original version: That could be done, but since the various methods are going to be identical functions, it's much more common to lay out any necessary vtables and the data in the object itself, and make the methods functions that can be found when needed.

Better version: ... and turn the methods into functions that can be found when needed.

***

Original version: While I'm working on Heron right now, I've spent most of that time working on the documentation for the parser (http://www.ootl.org/yard/), so I can't say if this is in there yet.

Better version: ... I've spent most of that time working on the documentation for the parser (http://www.ootl.org/yard/ -- please note that this page is not what I wrote, what I wrote is currently in a hand-rolled markup language and I'm writing a YARD parser to convert it into Boost DocBook) ...

***

Original version: However, if you take a pointer to the pointer to the parent class, and point it at a child, you won't be able to call the extended versions of the methods.

Better version: ... if you take a pointer to a parent class, and point it at an object of a child class, you'll get the parent's versions of the methods. In order to get the child's version, the computer needs to go through dynamic dispatch, which is what "virtual" is for.

James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: How C++ programmers think Posted: Dec 29, 2005 2:17 PM
Reply to this message Reply
> /* If I'm not mistaken, you can extend a class in C++ and
> define the same method on that extended class whether it
> is virtual or not. The only truly non-virtual
> (compile-time-bound) methods in Java are static methods.
> */
>
> You're right about C++. However, if you take a pointer to
> the pointer to the parent class, and point it at a child,
> you won't be able to call the extended versions of the
> methods. In order to do that, you must use virtual.

Right. But a static method in Java can also be final even though it is never virtual i.e. cannot be overriden. A little odd but the point is that the concept of final in Java is very different from virtual in C++.

> And thanks for the correction regarding Java, final, and
> static methods.

No problem. The wiki entry was wrong too. I updated it. I did double-check this too. The JLS guarantees that removing final from a method or class will not cause binary incompatiblities. Therefore the compiler cannot bind final methods at compile-time. THe JVM can however inline the lookups at runtime for direct references to final methods which is kind of the same thing.

James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: How C++ programmers think Posted: Dec 29, 2005 2:21 PM
Reply to this message Reply
> Well, in the implementation I described (thanks Terje for
> the correction!), the pointers are used to determine the
> correct version of method to call. That is, each object
> may promise that a pointer to the function that implements
> the method "make_sound()" is going to be at an address 100
> bytes into the object class (this gets a little more
> confusing with multiple inheritence, but not all that
> much). Then, when I ask an object to make_sound(), behind
> the scenes, the computer first determines it has to look
> 100 bytes into the object to find the pointer, then it
> follows that pointer to find the correct function to
> really call, and then calls it.

OK, now I am confused. This is very different from a vtable implementation, is it not? I does make sense, I suppose, if methods can be treated as Objects. This would also allow taking an Object and modifying it to replace method implementations. I suppose this is how languages like Ruby work?

Max Lybbert

Posts: 314
Nickname: mlybbert
Registered: Apr, 2005

Re: How C++ programmers think Posted: Dec 30, 2005 2:11 PM
Reply to this message Reply
/* OK, now I am confused. This is very different from a vtable implementation, is it not?
*/

To be honest, I only really looked into this a little while ago. Let me try to write some pseudocode, and perhaps somebody with more knowledge can correct any mistakes.

Hardware simply doesn't have object-oriented features, generally speaking (http://slashdot.org/developers/00/02/25/1034222.shtml question 8). So OOP languages have to use what the hardware does offer in order to implement OOP. Instead of doing that, I'm going to try to implement OOP in C.

A non-virtual method in C++ maps to a function in C. So, if I have a class (say, dog) that has a method (say, bark), C++ is going to implement that with a data element (we'll call that [object]_data), and a function that works on that data.

So:

dog Fido("dalmation");
Fido.bark(3);

Turns into something like:

struct dog_data {char* species, int age_in_years};
struct dog_data Fido_data = dog_ctor("dalmation", 3);
dog_bark(Fido_data, 3);

The type system remembers that Fido is a dog. However, if I try to refer to Fido as an animal instead of a dog, the type system is going to grap the animal_ version of the functions, and is only going to look at the animal_data portion of Fido_data (this is called slicing). If I did not extend those methods or data, then I won't notice a problem. But if I made a change to one or the other, I'll probably get wrong behavior.

A vtable is a table of function pointers that goes in the object's data portion, and those pointers refer to the functions that implement all virtual methods related to that object.

So if dog were derived from animal, and bark were renamed make_noise, and virtual, there would be a vtable somewhere in animal_data, and one of those pointers would refer to the make_noise function of the derived class.

The magic comes from the computer knowing where this table is, and what kind of function each entry points to. By deriving dog from animal, the compiler puts a pointer to dog_make_noise at the right spot in dog_data, so that I can guarantee the correct function gets called on the correct data, even if I'm using a base class instead of the derived class:

struct animal_data {void* animal_vtable[10]};
struct dog_data {animal_data, string species, int age_in_years};

If animal_vtable[0] is a pointer to the correct make_noise function, dog_data.animal_data.animal_vtable[0] will point at dog_make_noise. And since we're talking about single inheritance and C-style structs, that entry will be both dog_data's and animal_data's very first byte. So I can lookt at the first byte data of any class derived from animal_data to get the pointer for the correct make_noise.

The compiler takes care of the details. I'm not going to write the code for actually doing that, because pointer to function syntax is one thing I have to double check everytime I think about using it. In fact, I'm pretty sure void* animal_vtable[10] isn't the correct way to make a table of function pointers.

Multiple inheritance, btw, is implemented by putting a table of pointers to the various vtables at the beginning of the object's data component. So if class dog derives from both animal and graphic (so it can be displayed), there will be a table at the beginning of dog_data, with one pointer to where animal_vtable is and another to where graphic_vtable is within the dog_data structure.

Flat View: This topic has 52 replies on 4 pages [ « | 1  2  3  4 | » ]
Topic: The Joy of Joy Previous Topic   Next Topic Topic: Audio Interview


Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2014 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use - Advertise with Us