www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Walter: extend existing classes with new methods?

reply Marcio <mqmnews321 sglebs.com> writes:
Walter,

    Do you plan to add the ability of adding methods to an existing 
class, from another module?

    This ties to the issues raised at 
http://www.cs.princeton.edu/~dpw/popl/06/Tim-POPL.ppt and the fact that 
some languages/systems have had this capability for years (Smalltalk, 
for example, and more recently Ruby) with very beneficial results.

    Thanks,

marcio
Aug 27 2006
parent reply Bill Baxter <wbaxter gmail.com> writes:
Marcio wrote:
 Walter,
 
    Do you plan to add the ability of adding methods to an existing 
 class, from another module?
 
    This ties to the issues raised at 
 http://www.cs.princeton.edu/~dpw/popl/06/Tim-POPL.ppt and the fact that 
 some languages/systems have had this capability for years (Smalltalk, 
 for example, and more recently Ruby) with very beneficial results.
 
Smalltalk and Ruby are both dynamically typed languages. D is statically typed -- that is the type of everything must be known at compile-time, and in particular what methods are present must be known. AFIK, in D, like in C++, someobject.foo() either fails to compile, or it successully calls foo() at runtime. There is no runtime check to see if the method exists or not before calling it. What you're asking for is a really big fundamental change to what D is. That said, it might be nice for some aspects of dynamic typing to be built in to the language. From what I gather, that's one of the strengths of Objective-C, and what makes it a good language for writing GUIs. So the first step would be to ask if D is going to gain support for basic dynamic method calling, THEN you can ask the question of whether or not adding dynamic methods to existing classes will be allowed. But I guess if you have dynamic methods, then adding them to classes a la Smalltalk is really not a big deal. Just a matter of putting another pointer in the class's dynamic method dict. --bb
Aug 30 2006
next sibling parent reply Ivan Senji <ivan.senji_REMOVE_ _THIS__gmail.com> writes:
Bill Baxter wrote:
 Marcio wrote:
 Walter,

    Do you plan to add the ability of adding methods to an existing 
 class, from another module?

    This ties to the issues raised at 
 http://www.cs.princeton.edu/~dpw/popl/06/Tim-POPL.ppt and the fact 
 that some languages/systems have had this capability for years 
 (Smalltalk, for example, and more recently Ruby) with very beneficial 
 results.
Smalltalk and Ruby are both dynamically typed languages. D is statically typed -- that is the type of everything must be known at compile-time, and in particular what methods are present must be known. AFIK, in D, like in C++, someobject.foo() either fails to compile, or it successully calls foo() at runtime. There is no runtime check to see if the method exists or not before calling it. What you're asking for is a really big fundamental change to what D is.
Not really. It is possible to extend a type without the need for runtime Here is a little example: static class Program { static void Main(string[] args) { string s = "Hello, world"; s.Print(); } static void Print(this string s) { Console.WriteLine(s); } } There is nothing dynamic about that. Actually D already has a feature to add methods to array types and it is only a natural extension to allow it for other types. The only thing compiler would have to do is for every a.method(b); check if there exists method(a,b); and translate the code to that. This is how it works for arrays and it is one inconsistency just begging to be resolved (and not my removing this feature, but by extending it to other types).
Aug 31 2006
parent reply Bill Baxter <wbaxter gmail.com> writes:
Ivan Senji wrote:
 Bill Baxter wrote:
 
 Marcio wrote:

 Walter,

    Do you plan to add the ability of adding methods to an existing 
 class, from another module?
 compile, or it successully calls foo() at runtime.  There is no 
 runtime check to see if the method exists or not before calling it.  
 What you're asking for is a really big fundamental change to what D is.
Not really. It is possible to extend a type without the need for runtime Here is a little example: static class Program { static void Main(string[] args) { string s = "Hello, world"; s.Print(); } static void Print(this string s) { Console.WriteLine(s); } } There is nothing dynamic about that.
I see. Is that little bit of syntactic sugar all the original poster was asking for? And was that also all Tim Sweeny was asking for in the referenced presentation? That means you can only add non-virtual methods, right? --bb
Aug 31 2006
parent Marcio <mqmnews321 sglebs.com> writes:
Bill Baxter wrote:
[...]
 There is nothing dynamic about that.
I see. Is that little bit of syntactic sugar all the original poster was asking for? And was that also all Tim Sweeny was asking for in the referenced presentation? That means you can only add non-virtual methods, right?
feature itself. I want to be able to add virtual, instance methods, of course. marcio
Sep 03 2006
prev sibling next sibling parent Fredrik Olsson <peylow gmail.com> writes:
Bill Baxter skrev:
 Marcio wrote:
 Walter,

    Do you plan to add the ability of adding methods to an existing 
 class, from another module?

    This ties to the issues raised at 
 http://www.cs.princeton.edu/~dpw/popl/06/Tim-POPL.ppt and the fact 
 that some languages/systems have had this capability for years 
 (Smalltalk, for example, and more recently Ruby) with very beneficial 
 results.
Smalltalk and Ruby are both dynamically typed languages. D is statically typed -- that is the type of everything must be known at compile-time, and in particular what methods are present must be known. AFIK, in D, like in C++, someobject.foo() either fails to compile, or it successully calls foo() at runtime. There is no runtime check to see if the method exists or not before calling it. What you're asking for is a really big fundamental change to what D is. That said, it might be nice for some aspects of dynamic typing to be built in to the language. From what I gather, that's one of the strengths of Objective-C, and what makes it a good language for writing GUIs.
In my humble opinion it rocks for writing GUIs. And key value coding, binding, and much more that reduce code for managing data and UI sync is not only less code, but in most cases no code at all, is as I can see it not practically possible without the dynamix message dispatch of Objective-C. Now taking the whole step to Objective-C's lever would be a major task, but some run-time info, and possibility to at runtime change the virtual methods table would be nice. I dunno how this could work internally, probably linked list of many virtual method tables for each class, allowing "extensions" to add batches of new methods. // Original class class Foo { void doStuff() { writeln("some stuff"); } } // New extension to class, added method will be added to all // subclasses as well, only methods, not instance variables // can be added. class Foo (myextension) { void doOtherStuff(int a) { writeln("some other stuff:", a); } } // And in semi action. Foo foo = new Foo(); if (foo.respondsTo(doOtherStuff(int)) { foo.doOtherStuff(42); } But looking at it, I think it would probably be much easier to just create Objective-D. The Objective part of Objective-C is very small, and could be made as a preprocessor for D to start with, that is exactly what was done for Objective-C once upon a time. The idea of Objective-D intrigues me :). I love Objective-C, but hate the C parts...
 So the first step would be to ask if D is going to gain support for 
 basic dynamic method calling, THEN you can ask the question of whether 
 or not adding dynamic methods to existing classes will be allowed.  But 
 I guess if you have dynamic methods, then adding them to classes a la 
 Smalltalk is really not a big deal.  Just a matter of putting another 
 pointer in the class's dynamic method dict.
 
Unfortunately I do not think it is just that easy, what D, C++, Java, etc call OOP is really just syntactic sugar for having functions pointers in your structs, and then some fluff. It is not really encapsulation, as the caller always needs to know how to call each method, often by knowing the exact offset of a methods function pointer in a table. What smalltalk (And Objective-C) does is taking that responsibility away from the caller, and instead let the called object be responsible for figuring out where the actual implementation is. As methods could be added by from many modules, and in an undetermined order, there is no way to know the exact offset of your added function pointer. And you must take the Smalltalk route and actually look up the method for each call (And cache the lookups for speed). As Objective-C does it this method call: [myObject doSomething:42]; // Think of it as myObject.doSomething(42); Is in reality rewritten as this: objc_msgSend(myObject, "doSomething:", 42); This is not quite true as the C-string "doSomething:" is also guaranteed to only exist once in each running process. But in short that is what it does. The function objc_msgSend() will then look up the correct method implementation for the method specified in argument 2, for the class of the object instance specified in argument 1. If a implementation is found this is called with the rest of the arguments, if not the method for handling unimplemented methods is called, an error raised, or simply do nothing. Hard to describe in text, maybe this one http://tinyurl.com/kojmm does a better job. But in the end it is just a few simple parts, that makes it very flexible and powerful. Claiming you know OOP unless you have seen the Smalltalk school, is like claiming you know of large cities without having seen New York ;). // Fredrik Olsson
Aug 31 2006
prev sibling parent reply Marcio <mqmnews321 sglebs.com> writes:
Bill Baxter wrote:
 Marcio wrote:
 Walter,

    Do you plan to add the ability of adding methods to an existing 
 class, from another module?

    This ties to the issues raised at 
 http://www.cs.princeton.edu/~dpw/popl/06/Tim-POPL.ppt and the fact 
 that some languages/systems have had this capability for years 
 (Smalltalk, for example, and more recently Ruby) with very beneficial 
 results.
Smalltalk and Ruby are both dynamically typed languages. D is statically typed -- that is the type of everything must be known at compile-time, and in particular what methods are present must be known. AFIK, in D, like in C++, someobject.foo() either fails to compile, or it successully calls foo() at runtime. There is no runtime check to see if the method exists or not before calling it. What you're asking for is a really big fundamental change to what D is.
No, I am asking for extending at compile-time. Example: You provide me with a library written in D, with full source, and my app can add methods to some of your classes. Then I compile the full source. This is quite doable, even in D. Adding methods at runtime is an issue if you allow plugins to be loaded from DLLs. If these plugins can add not only classes but also add methods to existing classes, then you need the functionality at runtime. I am being modest in my request. Compile-time extension would be straightforward and very useful. marcio
Sep 03 2006
next sibling parent reply Kirk McDonald <kirklin.mcdonald gmail.com> writes:
Marcio wrote:
 Bill Baxter wrote:
 
 Marcio wrote:

 Walter,

    Do you plan to add the ability of adding methods to an existing 
 class, from another module?

    This ties to the issues raised at 
 http://www.cs.princeton.edu/~dpw/popl/06/Tim-POPL.ppt and the fact 
 that some languages/systems have had this capability for years 
 (Smalltalk, for example, and more recently Ruby) with very beneficial 
 results.
Smalltalk and Ruby are both dynamically typed languages. D is statically typed -- that is the type of everything must be known at compile-time, and in particular what methods are present must be known. AFIK, in D, like in C++, someobject.foo() either fails to compile, or it successully calls foo() at runtime. There is no runtime check to see if the method exists or not before calling it. What you're asking for is a really big fundamental change to what D is.
No, I am asking for extending at compile-time. Example: You provide me with a library written in D, with full source, and my app can add methods to some of your classes. Then I compile the full source. This is quite doable, even in D. Adding methods at runtime is an issue if you allow plugins to be loaded from DLLs. If these plugins can add not only classes but also add methods to existing classes, then you need the functionality at runtime. I am being modest in my request. Compile-time extension would be straightforward and very useful. marcio
There is a problem with this. class Foo { } static if (is(typeof(Foo.bar))) { const bool has_bar = true; } else { const bool has_bar = false; } /+ Add a 'bar' member to Foo somehow +/ Does Foo have a 'bar' member or not? In order for has_bar to be true, the compiler would need to arbitrarily look ahead and see if class Foo is changed later. This may well be impossible. If instead you want has_bar to evaluate to false (because the 'bar' member hasn't been added at the time the static if is evaluated), then this leads to any number of problems. The class is suddenly different at different points in the code. In a statically-typed language, this is wrong, wrong, wrong. -- Kirk McDonald Pyd: Wrapping Python with D http://pyd.dsource.org
Sep 03 2006
parent reply Marcio <mqmnews321 sglebs.com> writes:
    If I understood your argument correctly, you are saying that you 
can't have a compiler compile code for a class if the source is split 
across multiple source files? Because, after all, that's all we're 
talking about here. Class foo has some code in foo.d, some code in bar.d 
(it added methods to foo) and so on.

   Well, if we are going to use that argument, we might as well move 
back in time to the old days of Turbo Pascal 3.0. If you wanted to use a 
procedure Foo, it had to have already appeared in the source. So, for 
cases like recursive descendent parsers or recursive tree traversal you 
had to declare the function, and later have it appear again, with the 
body itself. This allowed you to have mutually recursive procedures. 
This was because the compiler couldn't do any look-ahead or 2-pass. Way 
to go, put the burden on the developer because of a compiler limitation. 
Fina when you have 64KB of RAM like the MSX I guess...

   I think compilers should serve developers, not the other way around.

   By the way, the reason Java source has so many "instanceof" is 
because it doesn't allow this type of extension. If the language allows 
extensions, you can easily code things with polymorphism by adding say 
isFoo to Object (return false) and overriding it in your Foo class 
(return true). No need for instanceof. You want to know if the object 
isFoo? Damn, just ask it. Use OO. This is a very common pattern of 
coding in systems like Smalltalk.

   I honestly believe that people who never used this feature in a 
language can't really grasp what they are missing. That's too bad. Just 
look at http://www.cs.princeton.edu/~dpw/popl/06/Tim-POPL.ppt  when he 
talks about frameworks, the need to extend base classes. To me that's a 
clear example of a problem that can be solved by this mechanism.

marcio


Kirk McDonald wrote:
 No, I am asking for extending at compile-time. Example: You provide me 
 with a library written in D, with full source, and my app can add 
 methods to some of your classes. Then I compile the full source.

 This is quite doable, even in D.

 Adding methods at runtime is an issue if you allow plugins to be 
 loaded from DLLs. If these plugins can add not only classes but also 
 add methods to existing classes, then you need the functionality at 
 runtime.

 I am being modest in my request. Compile-time extension would be 
 straightforward and very useful.

 marcio
There is a problem with this. class Foo { } static if (is(typeof(Foo.bar))) { const bool has_bar = true; } else { const bool has_bar = false; } /+ Add a 'bar' member to Foo somehow +/ Does Foo have a 'bar' member or not? In order for has_bar to be true, the compiler would need to arbitrarily look ahead and see if class Foo is changed later. This may well be impossible. If instead you want has_bar to evaluate to false (because the 'bar' member hasn't been added at the time the static if is evaluated), then this leads to any number of problems. The class is suddenly different at different points in the code. In a statically-typed language, this is wrong, wrong, wrong.
Sep 04 2006
parent Ivan Senji <ivan.senji_REMOVE_ _THIS__gmail.com> writes:
Marcio wrote:
 
    If I understood your argument correctly, you are saying that you 
 can't have a compiler compile code for a class if the source is split 
 across multiple source files? Because, after all, that's all we're 
 talking about here. Class foo has some code in foo.d, some code in bar.d 
 (it added methods to foo) and so on.
 
   Well, if we are going to use that argument, we might as well move back 
 in time to the old days of Turbo Pascal 3.0. If you wanted to use a 
 procedure Foo, it had to have already appeared in the source. So, for 
 cases like recursive descendent parsers or recursive tree traversal you 
 had to declare the function, and later have it appear again, with the 
 body itself. This allowed you to have mutually recursive procedures. 
 This was because the compiler couldn't do any look-ahead or 2-pass. Way 
 to go, put the burden on the developer because of a compiler limitation. 
 Fina when you have 64KB of RAM like the MSX I guess...
 
   I think compilers should serve developers, not the other way around.
 
   By the way, the reason Java source has so many "instanceof" is because 
 it doesn't allow this type of extension. If the language allows 
 extensions, you can easily code things with polymorphism by adding say 
 isFoo to Object (return false) and overriding it in your Foo class 
 (return true). No need for instanceof. You want to know if the object 
 isFoo? Damn, just ask it. Use OO. This is a very common pattern of 
 coding in systems like Smalltalk.
Now I know I misunderstood you. Extension methods I was thinking of are adding a nonstatic method should work. Static extension methods might not be as useful as nonstatic ones but it can be a nice feature.
Sep 04 2006
prev sibling parent reply Ivan Senji <ivan.senji_REMOVE_ _THIS__gmail.com> writes:
Marcio wrote:
 No, I am asking for extending at compile-time. Example: You provide me 
 with a library written in D, with full source, and my app can add 
 methods to some of your classes. Then I compile the full source.
 
 This is quite doable, even in D.
It sure is. The fact that it isn't implemented is just another inconsistency in the language. I would even go so far and say it is a d1.0blocker (as all inconsistencies are).
Sep 03 2006
parent reply Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Ivan Senji wrote:
 Marcio wrote:
 
 No, I am asking for extending at compile-time. Example: You provide me 
 with a library written in D, with full source, and my app can add 
 methods to some of your classes. Then I compile the full source.

 This is quite doable, even in D.
It sure is. The fact that it isn't implemented is just another inconsistency in the language. I would even go so far and say it is a d1.0blocker (as all inconsistencies are).
Okay... maybe I'm missing something here? I was pretty sure we already do have this, in a little OOP concept called inheritance? Given a library defining 'class Foo', if I need custom behavior, I simply define a 'class MyFoo:Foo' and voila! Or is there some deeper concept that I'm overlooking entirely? -- Chris Nicholson-Sauls
Sep 04 2006
parent reply Marcio <mqmnews321 sglebs.com> writes:
Chris Nicholson-Sauls wrote:
 Okay... maybe I'm missing something here?  
Yes, you are.
 I was pretty sure we already 
 do have this, in a little OOP concept called inheritance?  
Nope.
 Given a
 library defining 'class Foo', if I need custom behavior, I simply define 
 a 'class MyFoo:Foo' and voila!
 
 Or is there some deeper concept that I'm overlooking entirely?
 
You want String to have a new method, say asURL. Or findReplace. Or whatever. Not a new String subclass. You want to add functionality to String. You want all objects to understand dumpOn (aStream). Say you are writing a persistent framework. You need to add methods to Object. If you ever used Smalltalk, you'd know what I mean. marcio
Sep 04 2006
next sibling parent reply Don Clugston <dac nospam.com.au> writes:
Marcio wrote:
 Chris Nicholson-Sauls wrote:
 Okay... maybe I'm missing something here?  
Yes, you are.
 I was pretty sure we already do have this, in a little OOP concept 
 called inheritance?  
Nope. > Given a
 library defining 'class Foo', if I need custom behavior, I simply 
 define a 'class MyFoo:Foo' and voila!

 Or is there some deeper concept that I'm overlooking entirely?
You want String to have a new method, say asURL. Or findReplace. Or whatever. Not a new String subclass. You want to add functionality to String. You want all objects to understand dumpOn (aStream). Say you are writing a persistent framework. You need to add methods to Object. If you ever used Smalltalk, you'd know what I mean. marcio
A somewhat related concept is here (very hackish C++, but the concept translates easily to D): http://www.codeproject.com/cpp/retrofitpolymorphism2.asp The idea being that you make a new interface, IDumpableObject, and define how to cast any Object into an IDumpableObject. You never actually add members to Object. Instead, you make everything look as though it derived from IDumpableObject, and then your framework uses IDumpableObject everywhere. I think it would be possible to get most of this behaviour even from D .166, with a bit of hackery.
Sep 06 2006
parent reply Marcio <mqmnews123 sglebs.com> writes:
Don Clugston wrote:
 A somewhat related concept is here (very hackish C++, but the concept 
 translates easily to D):
 
 http://www.codeproject.com/cpp/retrofitpolymorphism2.asp
 
 The idea being that you make a new interface, IDumpableObject,
 and define how to cast any Object into an IDumpableObject.
 
 You never actually add members to Object. Instead, you make everything 
 look as though it derived from IDumpableObject, and then your framework 
 uses IDumpableObject everywhere.
If you don't need to add code to the class, this works well in statically typed languages. You are basically trying to overcome the limitation of static typing where a 3rd-party class already declared the interfaces it implements, so you are stuck. It's a closed module now. If another class declares it uses another interface that looks just the same, the 2 are still incompatible because they implement 2 separate interfaces, even if they are really the same in terms of functionality. This is an issue even more now with web services, and Erik Meijer's talk mentions this issue (it seems that VB will be really flexible here) But note that there are many cases when you need to add code as well. http://www.cs.princeton.edu/~dpw/popl/06/Tim-POPL.ppt gives one example. marcio
Sep 06 2006
parent reply Don Clugston <dac nospam.com.au> writes:
Marcio wrote:
 Don Clugston wrote:
 A somewhat related concept is here (very hackish C++, but the concept 
 translates easily to D):

 http://www.codeproject.com/cpp/retrofitpolymorphism2.asp

 The idea being that you make a new interface, IDumpableObject,
 and define how to cast any Object into an IDumpableObject.

 You never actually add members to Object. Instead, you make everything 
 look as though it derived from IDumpableObject, and then your 
 framework uses IDumpableObject everywhere.
If you don't need to add code to the class, this works well in statically typed languages. You are basically trying to overcome the limitation of static typing where a 3rd-party class already declared the interfaces it implements, so you are stuck.
It's much more than that. It's about extending functionality to a class without polluting the base class. It is not just about renaming interfaces (although in the link I showed, it does) -- it can be used to add code as well (you just need to populate the interface at compile time). IMHO, this kind of interface arises more frequently than interface inheritance does.
It's a closed module now. If
 another class declares it uses another interface that looks just the 
 same, the 2 are still incompatible because they implement 2 separate 
 interfaces, even if they are really the same in terms of functionality. 
 This is an issue even more now with web services, and Erik Meijer's talk 
 mentions this issue (it seems that VB will be really flexible here) 

 
 
     But note that there are many cases when you need to add code as 
 well. http://www.cs.princeton.edu/~dpw/popl/06/Tim-POPL.ppt gives one 
 example.
Yes, but that example would work perfectly well with static typing.
Sep 07 2006
parent reply Marcio <mqmnews123 sglebs.com> writes:
Don Clugston wrote:
 It's much more than that. It's about extending functionality to a class 
 without polluting the base class. It is not just about renaming 
 interfaces (although in the link I showed, it does) -- it can be used to 
 add code as well (you just need to populate the interface at compile 
 time). 
Ah, ok. Interesting. So, do you mind showing me how I can have the scenario where I can have String now understand a new method, say "asURL", which I can use from my new component? It should return a URL object or null if it is invalid. It is a silly scenario, but adding functionality to String is useful. Java 1.5 just added extra API to String, for example. Code that uses this API won't compile in Java 1.4. So, if you wanted to provide a compatibility layer, you could have it adding this API to String. Can that be done with the approach you sent? It wasn't clear to me that it could. But if it can, I am curious... Another scenario I would be interested to see working is how I can have Object return false to "isWidget" but a Widget class return true. This allows you to get rid of instanceof" checks and rely purely on polymorphism. In my mental model you want to add the isWidget method to Object. You say you can add code to the interface. However, Object and Widget would have 2 opposite implementations, so I am not sure how adding code to the 1 interface would help? Please help me understand that C++ hack - I am not a C++ person :-) Thanks, marcio
Sep 07 2006
parent reply Don Clugston <dac nospam.com.au> writes:
Marcio wrote:
 Don Clugston wrote:
 It's much more than that. It's about extending functionality to a 
 class without polluting the base class. It is not just about renaming 
 interfaces (although in the link I showed, it does) -- it can be used 
 to add code as well (you just need to populate the interface at 
 compile time). 
Ah, ok. Interesting. So, do you mind showing me how I can have the scenario where I can have String now understand a new method, say "asURL", which I can use from my new component? It should return a URL object or null if it is invalid. It is a silly scenario, but adding functionality to String is useful.
In C++ I used my "fastdelegate" template (on CodeProject) to hack delegates into C++. This lets you do something vaguely like: -------------- using namespace fastdelegate; class StringWithURL { String &baseClass; // only necessary when you add new functions public: // The normal String functions. Actually they're delegates, but // they behave exactly like functions. FastDelegate<void ()> makeUpper; FastDelegate<String (String)> concatenate; // etc // Constructor, templated. Note that you can specialize it to behave differently for specific classes. template<class T> StringWithURL(T &a) : baseClass(a), toUpper(MakeDelegate(a, &T::toUpper)), // etc {} // implicit conversion to String. String & operator String () { return baseClass; } URL asURL() { if (baseClass[0]!='h') return 0; // must start with "http" else return new URL("www.smurfsRus.com"); } }; Then, you can write void myfunc(StringWithURL s) {} and it will accept anything derived from String. It's unnecessarily inefficient, though -- not as lightweight as it should be. Also things like delete don't work (they don't delete the base class). What we're doing is using delegates to make a fake vtable. Now, with interfaces, gc, delegates, static if, and is() expressions, D could do much better than this. Only problem is, there's no implicit conversion. Java 1.5 just added extra API to
 String, for example. Code that uses this API won't compile in Java 1.4. 
 So, if you wanted to provide a compatibility layer, you could have it 
 adding this API to String. Can that be done with the approach you sent? 
 It wasn't clear to me that it could. But if it can, I am curious...
 
     Another scenario I would be interested to see working is how I can 
 have Object return false to "isWidget" but a Widget class return true.
Yeah, that's very common. Some cases can be done very easily: template (X) void myfunc(X x) { static if ( is( x.isWidget ) ) { ... } } but if you don't know the type at compile time, you're stuck.
 This allows you to get rid of
 instanceof" checks and rely purely on polymorphism. In my mental model 
 you want to add the isWidget method to Object. You say you can add code 
 to the interface. However, Object and Widget would have 2 opposite 
 implementations, so I am not sure how adding code to the 1 interface 
 would help? Please help me understand that C++ hack - I am not a C++ 
 person :-)
It's very imperfect, but might generate ideas.
Sep 08 2006
parent reply Marcio <mqmnews123 sglebs.com> writes:
 In C++ I used my "fastdelegate" template (on CodeProject) to hack 
 delegates into C++. This lets you do something vaguely like:
 
[...]
 Then, you can write
 
 void myfunc(StringWithURL s) {}
 
 and it will accept anything derived from String. 
I want existing String objects, belonging to class String, to be able to understand asURL. Not a new class. Unless I misunderstood your explanation. My understanding is that "derived from String" does not include String.
 It's unnecessarily 
 inefficient, though -- not as lightweight as it should be.
 Also things like delete don't work (they don't delete the base class).
If you could just add methods to the class, these methods would behave the same as the ones defined in the class itself. No speed penalty. The feature request is quite simple actually. Allow a class C to be defined not just in 1 file, but in N files. From many fragments. A class is never a closed module in this case.
     Another scenario I would be interested to see working is how I can 
 have Object return false to "isWidget" but a Widget class return true.
Yeah, that's very common. Some cases can be done very easily: template (X) void myfunc(X x) { static if ( is( x.isWidget ) ) { ... } } but if you don't know the type at compile time, you're stuck.
Yeah, I'd rather just rely on polymorphism. Which can be done if the source of a class can be split across multiple files. These extra methods become regular methods, not second class.
 It's very imperfect, but might generate ideas.
Indeed. But in my mind, a compiler can do lots of interesting things after compiling the full program. These extension methods would not be hard. There are also all sorts of polymorphism optimizations that can be done. SmartEiffel (used to be SmallEiffel) does all sorts of virtual call optimizations because it can do a global analysis of thr code (something Java can't do, for example, because of thr dynamic class loading etc). Sometimes their compiler eliminates 98% of virtual calls. It generates amazingly fast code. Anyway, just to say that if you are compiling a program to generate an EXE, with no fancy dynamic loading etc, it should be possible to do these global analysis and therefore also allow methods to be added from different places. Like extending a framework by adding methods to base classes so that all subclasses now receive the extra behavior. And that includes Object itself. In dynamic languages, it is a no-brainer of course. Anyway, I wish D had this. It's a powerful mechanism to have. But since Walter did not reply at all, I guess he does not like the idea. Oh well... marcio
Sep 08 2006
next sibling parent Lars Ivar Igesund <larsivar igesund.net> writes:
Marcio wrote:

   Anyway, I wish D had this. It's a powerful mechanism to have. But
 since Walter did not reply at all, I guess he does not like the idea. Oh
 well...
That certainly is the wrong conclusion to make based on those facts ... Walter very seldom reply to new suggestions, and especially now as he is concentrating on bug fixes, however good the suggestion might be. -- Lars Ivar Igesund blog at http://larsivi.net DSource & #D: larsivi
Sep 08 2006
prev sibling parent Don Clugston <dac nospam.com.au> writes:
Marcio wrote:
 In C++ I used my "fastdelegate" template (on CodeProject) to hack 
 delegates into C++. This lets you do something vaguely like:
[...]
 Then, you can write

 void myfunc(StringWithURL s) {}

 and it will accept anything derived from String. 
I want existing String objects, belonging to class String, to be able to understand asURL. Not a new class. Unless I misunderstood your explanation. My understanding is that "derived from String" does not include String.
Sorry, my wording was poor. Anything implicitly convertible to String will be implicitly convertible to StringWithURL. This obviously includes String itself.
 It's unnecessarily inefficient, though -- not as lightweight as it 
 should be.
 Also things like delete don't work (they don't delete the base class).
If you could just add methods to the class, these methods would behave the same as the ones defined in the class itself. No speed penalty.
Yes. That was a limitation of C++ templates, I think you could do better in D with the same idea. With my technique it would not be possible to add data members, though.
   The feature request is quite simple actually. Allow a class C to be 
 defined not just in 1 file, but in N files. From many fragments. A class 
 is never a closed module in this case.
Simple to request, complicated to implement I would guess. Something defined in a DLL surely has to be a closed module?
     Another scenario I would be interested to see working is how I 
 can have Object return false to "isWidget" but a Widget class return 
 true.
Yeah, that's very common. Some cases can be done very easily: template (X) void myfunc(X x) { static if ( is( x.isWidget ) ) { ... } } but if you don't know the type at compile time, you're stuck.
Yeah, I'd rather just rely on polymorphism. Which can be done if the source of a class can be split across multiple files. These extra methods become regular methods, not second class.
 It's very imperfect, but might generate ideas.
Indeed. But in my mind, a compiler can do lots of interesting things after compiling the full program. These extension methods would not be hard. There are also all sorts of polymorphism optimizations that can be done. SmartEiffel (used to be SmallEiffel) does all sorts of virtual call optimizations because it can do a global analysis of thr code (something Java can't do, for example, because of thr dynamic class loading etc). Sometimes their compiler eliminates 98% of virtual calls. It generates amazingly fast code.
I believe D is designed to allow those optimisations.
   Anyway, just to say that if you are compiling a program to generate an 
 EXE, with no fancy dynamic loading etc, it should be possible to do 
 these global analysis and therefore also allow methods to be added from 
 different places. Like extending a framework by adding methods to base 
 classes so that all subclasses now receive the extra behavior. And that 
 includes Object itself.
I'd rather do that stuff with templates. If mixins were a little more powerful, you could use them to add the extra functionality to base classes. If you look at the example in the gaming article, it's clear that the designer of the framework *knows* where the extra functionality is going to be required. The problem is that the language doesn't give a nice way of expressing it.
Sep 11 2006
prev sibling parent Bill Baxter <wbaxter gmail.com> writes:
Sorry to drag this up again, but I was out of town for a while.

Marcio wrote:
   You want String to have a new method, say asURL. Or findReplace. Or 
 whatever. Not a new String subclass. You want to add functionality to 
 String.
 
   You want all objects to understand dumpOn (aStream). Say you are 
 writing a persistent framework. You need to add methods to Object.
The thing that I don't get about this is what happens if code A and code B both decide to add an 'asURL' method to String? Or 'dumpOn' to Object? With a function [e.g. asURL(aString), dumpOn(obj,stream)] these things can be disambiguated by using fully qualified names [myModule.asURL, yourModule.asURL], but if you go and make it a method on the base class [String.asURL()], you're effectively putting in the namespace of that class, right? And so you're suceptible to name clashes with anyone who wants to add methods to the same class. Do you make it so that the lookup is done local to the calling module? So that if module B adds a method to String, only module B can see that method? I don't see how that can work implementation-wise, though. How will I know to use that table instead of the default one when handed some arbitrary pointer to an object that may or may not be derived from String? -- without adding a bunch of extra explicit type checks, I mean. It's a very interesting idea. I guess I still just don't see how it can work in a statically typed language where dispatch is done with vtable lookup. --bb
Sep 21 2006