tags:

views:

324

answers:

8

I'm wondering about an idea in my head. I want to ask if you know of any library or article related to this. Or you can just tell me this is a dumb idea and why.

I have a class, and I want to dynamically add methods/properties to it at runtime. I'm well aware of the techniques of using composite/command design pattern and using embedded scripting language to accomplish what I'm talking about. I'm just exploring the idea. Not necessary saying that it is a good idea.

class Dynamic
{
public:
    typedef std::map<std::string, boost::function<void (Dynamic&)> > FuncMap;

    void addMethod(const std::string& name, boost::function<void (Dynamic&)> func) {
     funcMap_[name] = func;
    }

    void operator[](const std::string& name) {
     FuncMap::iterator funcItr = funcMap_.find(name);
     if (funcItr != funcMap_.end()) {
      funcItr->second(*this);
     }
    }

private:
    FuncMap funcMap_;
};

void f(Dynamic& self) {
    doStuffWithDynamic(self);
}

int main()
{
    Dynamic dyn;
    dyn.addMethod("f", boost::bind(&f, _1));
    dyn["f"]; // invoke f
}

The idea is that I can rebind the name "f" to any function at runtime. I'm aware of the performance problem in string lookup and boost::function vs. raw function pointer. With some hard work and non-portable hack I think I can make the performance problem less painful.

With the same kind of technique, I can do "runtime inheritance" by having a "v-table" for name lookup and dispatch function calls base on dynamic runtime properties.

If just want to tell me to use smalltalk or Objective-C, I can respect that but I love my C++ and I'm sticking with it.

A: 

I don't think there's a library for this exact thing.

Of course, you have to have these functions pre-written somehow, so it seems there would be an easier way to do what you want. For example you could have just one method to execute arbitrary code from your favorite scripting language. That seems like an easier way to do what you want.

rlbond
The idea is that the class Dymanic doesn't change and new function f() can be implemented after Dymanic has been deployed. Without restarting the process, I can change the behavior of Dymanic.
Shing Yip
+2  A: 

I don't think it would be a good idea to change C++ enough to make this work. I'd suggest working in another language, such as Lisp or Perl or another language that's basically dynamic, or imbedding a dynamic language and using it.

David Thornley
Actually the programming language Lua works very well for this kind of stuff. But that's not the point. I'm exploring the idea of dynamic runtime binding in C++ not "should I use dynamic language to solve my problem".
Shing Yip
Well, perhaps you *should* be exploring the idea of "should I use a dynamic language to solve my problem" ;)
jalf
Dynamic languages are nice, but what I'm saying is that C++ looks really, really unpromising to me as a dynamic language. If you're really interested, by all means look into it. My track record of identifying promising and unpromising approaches is by no means perfect (I thought the web was unlikely to get popular, for example). However, it's going to take some work just to get a coherent proposal with enough detail to understand.
David Thornley
+9  A: 

What you want is to change C++ into something very different. One of the (many) goals of C++ was efficient implementation. Doing string lookup for function calls (no matter how well you implement it), just isn't going to be very efficient compared to the normal call mechanisms.

Basically, I think you're trying to shoehorn in functionality of a different language. You CAN make it work, to some degree, but you're creating C++ code that no one else is going to be able (or willing) to try to understand.

If you really want to write in a language that can change it's objects on the fly, then go find such a language (there are many choices, I'm sure). Trying to shoehorn that functionality into C++ is just going to cause you problems down the road.

Please note that I'm no stranger to bringing in non-C++ concepts into C++. I once spent a considerable amount of time removing another engineer's attempt at bringing a based-object system into a C++ project (he liked the idea of containers of 'Object *', so he made every class in the system descend from his very own 'Object' class).

Bringing in foreign language concepts almost always ends badly in two ways: The concept runs up against other C++ concepts, and can't work as well as it did in the source language, AND the concept tends to break something else in C++. You end up losing a lot of time trying to implement something that just isn't going to work out.

The only way I could see something like this working at all well, is if you implemented a new language on top of C++, with a cfront-style pre-compiler. That way, you could put some decent syntax onto the thing, and eliminate some of your problems.

Michael Kohne
You're right. He might as well use Python or the like.
Seth Johnson
I didn't like the idea for the exact same reasons. I just want to see if someone has spent more time on similar ideas.
Shing Yip
A: 

I keep thinking of the Visitor pattern. That allows you to do a vtable lookup on the visiting object (as well as the visited object, thought that doesn't seem relevant to your question).

And at runtime, you could have some variable which refers to the visitor, and call

Dynamic dynamic;
DynamicVisitor * dv = ...;
dynamic->Accept(dv);
dv = ...; // something else
dynamic->Accept(dv);

The point is, the visitor object has a vtable, which you said you wanted, and you can change its value dynamically, which you said you wanted. Accept is basically the "function to call things I didn't know about at compile time."

Drew Hoskins
Visitor gives you double-dispatch, not dynamic dispatch. It won't work for my case.
Shing Yip
I guess I don't get your scenario, then. You are saying you want to be able to bind "f" to any function at runtime. Practically speaking, in the context of C++, one could instead bind a visitor variable to any visitor object at runtime and that should accomplish the same sets of scenarios. What am I missing?
Drew Hoskins
Visitor allows you can select which function to call based on two types, aka double-dispatch. I need to do dynamic dispatch of a function call, aka virtual dispatch. They're two different concepts. I wasn't clear in my question, but binding "f" to any function is just one of the things I wanted to do. Think Smalltalk or Objective-C, you'll see what I mean.
Shing Yip
+1  A: 

What you are doing is actually a variation of the Visitor pattern.

EDIT: By the way, another approach would be by using Lua, since the language allows you to add functions at runtime. So does Objective-C++.

EDIT 2: You could actually inherit from FuncMap as well:

class Dynamic;

typedef std::map<std::string, boost::function<void (Dynamic&)> > FuncMap;

class Dynamic : public FuncMap
{
public:
};

void f(Dynamic& self) {
    //doStuffWithDynamic(self);
}

int main()
{
    Dynamic dyn;
    dyn["f"] = boost::bind(&f, _1);
    dyn["f"](dyn); // invoke f, however, 'dyn'param is awkward...
    return 0;
}
StackedCrooked
Visitor pattern is a way to do double-dispatch in C++ not the same as dynamic dispatch. I'm aware of Lua and Objective-C++, but I'm not trying to see if I should embed a dynamic language. It is more like a academic question not "how do I do this" kind of question.
Shing Yip
@Shing Yip, I understand, I guess that your current solution is about as far as one can go in C++.
StackedCrooked
A: 

I've considered doing this before as well. Basically, however, you'd be on your way to writing a simple VM or interpreter (look at, say, Lua or Topaz's source to see what I mean -- Topaz is a dead project that pre-dates Parrot).

But if you're going that route it makes sense to just use an existing VM or interpreter.

Max Lybbert
That was my thinking too. I'm just trying to see if I can getaway with pure C++. If I was going to work on a new language I might as well go with seaside/smalltalk. The seaside design fits my ideal runtime system quite nicely.
Shing Yip
Well it's definitely possible. I can't recommend it because you do lose exactly what you expect to lose (typos in the strings can cause runtime errors). OTOH, it's very much like how most regex libraries work. Then again, regex libraries are simple interpreters.
Max Lybbert
+1  A: 

If I understand what you are trying to accomplish correctly, it seems as though dynamic linking (i.e. Dynamically loaded libraries in windows or linux) will do most of what you are trying to accomplish.

That is, you can, at runtime, select the name of the function you want to execute (eg. the name of the DLL), which then gets loaded and executed. Much in the way that COM works. Or you can even use the name of the function exported from that library to select the correct function (C++ name mangling issues aside).

zdan
Dynamic libraries can work. Wrap it with a proxy, using the command and composite design pattern you can make it pretty flexible. But that wasn't my question.
Shing Yip
+3  A: 

If you implemented this, even as a pure library, and then used it extensively, you would in a way be using a new language - one with a hideous syntax, and a curious combination of runtime method resolution and unreliable bounds checking.

As a fan of C/C++ style syntax and apparently a fan of dynamic method dispatch, you may be interested in C# 4.0, which is now in Beta, and has the dynamic keyword to allow exactly this kind of thing to be seamlessly mixed into normal statically typed code.

Daniel Earwicker
C# 4.0? Interesting. Haven't spent much time looking into the whole .net/CLR family since 2005. Maybe I should pay more attention on that side of the world.
Shing Yip
You definitely should, I got into it seriously with C# 3.0/.NET 3.5 and it has blown me away as an incredibly productive environment and language.
Daniel Earwicker