Welcome to Web-News
A Web-based News Reader
Subject A lightweight module for class extensions in D
From Gregor Richards <Richards@codu.org>
Date Fri, 05 Dec 2008 11:37:57 -0500
Newsgroups digitalmars.D
Attachment(s) extensions.d

I ran into a situation where I needed (essentially) the visitor pattern, but the visitor pattern sucks, so I wanted to make something like class extensions instead (that is, methods added to a class outside of the class definition).

Of course, it's not possible to do this particularly cleanly, but I made a system that works (albeit using gross string mixins). Essentially, if you have a class A, class B : A, class C : B, you could do something like this:

mixin(extensions("A", "void", "doFoo", "", ""));

mixin(extend("A", "doFoo"));
void A_doFoo(A pthis) {
    /* method for A */
}

mixin(extend("B", "doFoo"));
void B_doFoo(B pthis) {
    /* method for B */
}

Then if you call doFoo(new A()) the call will become A_doFoo(new A()), if you call doFoo(new B()) the call will become B_doFoo(new B()), if you call doFoo(new C()) the call will become B_doFoo(new C()).

If anybody has some improvements, that'd be cool. Maybe you can get rid of the dependence on string mixins ... but I don't think templates quite cut it.

- Gregor Richards



/** * A lightweight system for class extensions in D. * * Copyright (C) Gregor Richards, 2008 * * License: *  Permission is hereby granted, free of charge, to any person obtaining a copy *  of this software and associated documentation files (the "Software"), to deal *  in the Software without restriction, including without limitation the rights *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell *  copies of the Software, and to permit persons to whom the Software is *  furnished to do so, subject to the following conditions: *   *  The above copyright notice and this permission notice shall be included in *  all copies or substantial portions of the Software. *   *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN *  THE SOFTWARE. */ /* Use: * To make a function int foo(int a, int b) which extends the class A: * mixin(extension("A", "int", "foo", "int a, int b", "a, b")); * * Then to declare a function as an extension for A or a subclass: * int A_foo(A pthis, int a, int b) { ... } * mixin(extend("A", "foo")); * * To call the function, use the object as the first argument: * return foo(a, 1, 2); */ module extensions; /// Maximum extension number currently int extensionCount = 0; /// Basic generator for extensions char[] extension(char[] cl, char[] rtype, char[] fun, char[] args, char[] sargs) {     if (args != "") args = ", " ~ args;     if (sargs != "") sargs = ", " ~ sargs;     char[] ret = `void*[ClassInfo] __ext_` ~ fun ~ `;     ` ~ rtype ~ ` ` ~ fun ~ `(` ~ cl ~ ` pthis` ~ args ~ `) {         // go through super-classes until we lose or find the extension         ClassInfo ci = pthis.classinfo;         while (ci !is null) {             void** ext = ci in __ext_` ~ fun ~ `;             if (ext !is null) {                 void* f = *ext;                 /* found it! */`;                 if (rtype != "void") ret ~= "return ";                 ret ~= `(cast(` ~ rtype ~ ` function(` ~ cl ~ args ~ `)) f)(pthis` ~ sargs ~ `);`;                 if (rtype == "void") ret ~= "return;";                 ret ~= `             }             ci = ci.base;         }         throw new ExtensionLookupFailure();     }`;     return ret; } /// To make a specific extension char[] extend(char[] cl, char[] fun) {     return `class __ext_` ~ cl ~ `_` ~ fun ~ `_staticthis {         static this() {             __ext_` ~ fun ~ `[` ~ cl ~ `.classinfo] = cast(void*) &` ~ cl ~ `_` ~ fun ~ `;         }     }`; } class ExtensionLookupFailure : Exception {     this() {         super("ExtensionLookupFailure");     } }
Recent messages in this thread
 
-# A lightweight module for class extensions in D (Current message) Gregor Richards 05-Dec-2008 11:37 am
.-# Re: A lightweight module for class extensions in D Robert Fraser 05-Dec-2008 07:37 pm
.|-# Re: A lightweight module for class extensions in D Gregor Richards 05-Dec-2008 07:52 pm
.|.-# Re: A lightweight module for class extensions in D Robert Fraser 05-Dec-2008 08:02 pm
.|..-# Re: A lightweight module for class extensions in D Nick Sabalausky 06-Dec-2008 11:43 pm
.|...|# Re: A lightweight module for class extensions in D Robert Fraser 07-Dec-2008 12:55 am
.|...-# Re: A lightweight module for class extensions in D Christopher Wright 07-Dec-2008 08:21 am
.|....\# Re: A lightweight module for class extensions in D Nick Sabalausky 07-Dec-2008 05:20 pm
.|# Re: A lightweight module for class extensions in D Christopher Wright 05-Dec-2008 10:33 pm
.|# Re: A lightweight module for class extensions in D Nick Sabalausky 06-Dec-2008 06:24 pm
.|# Re: A lightweight module for class extensions in D Janderson 06-Dec-2008 09:05 pm
.-# Re: A lightweight module for class extensions in D Christian Kamm 07-Dec-2008 04:10 am
..\# Re: A lightweight module for class extensions in D Gregor Richards 07-Dec-2008 10:48 am