Walter: extend existing classes with new methods?

Don Clugston dac at nospam.com.au
Fri Sep 8 07:48:17 PDT 2006


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.



More information about the Digitalmars-d mailing list