views:

116

answers:

3

Recently I started noticing a repetition in some of my code. Of course, once you notice a repetition, it becomes grating. Which is why I'm asking this question.

The idea is this: sometimes you write different versions of the same class: a raw version, a locked version, a read-only facade version, etc. These are common things to do to a class, but the translations are highly mechanical. Surround all the methods with lock acquires/releases, etc. In a dynamic language, you could write a function which did this to an instance of a class (eg. iterate over all the functions, replacing them with a version which acquires/releases a lock.).

I think a good term for what I mean is 'reflected class'. You create a transformation which takes a class, and returns a modified-in-a-desired-way class. Synchronization is the easiest case, but there are others: make a class immutable [wrap methods so they clone, mutate the clone, and include it in the result], make a class readonly [assuming you can identify mutating methods], make a class appear to work with type A instead of type B, etc.

The important part is that, in theory, these transformations make sense at compile-time. Even though an ActorModel<T> has methods which change depending on T, they depend on T in a specific way knowable at compile-time (ActorModel<T> methods would return a future of the original result type).

I'm just wondering if this has been implemented in a language, and what it's called.

+1  A: 

Aspect oriented programming

ergosys
It certainly sounds similar, and covers some of the cases. But, using aspects, can I take a class and have the methods return futures instead of normal values?
Strilanc
You can typically not change the return type with AOP, a bit of the point is that code that uses it is unaware of the aspects.
Lasse V. Karlsen
A: 

Couldn't you do this with templates? It would be slightly hackish, but something like:

#define LOCKED = true;
#define UNLOCKED = false;

template<bool lock>
void doStuff(){
    if(lock){
        // get lock
    }
    // other code
    if(lock){
        // release lock
    }
}
Brendan Long
I don't know. I've never really explored the limits of C++ templates. Can they create a class whose methods are based on a sub-class' methods?
Strilanc
You could create an instance of your subclass as a member variable and then use its methods? Or if they're static functions, you can use them as `SubclassName::functionName()`
Brendan Long
+2  A: 

If I understand well, you would like to be able to generate new class/type through a transformation of an existing type. Something like

class Synchronized<T> {
    Object invocation( Object ... args ) {
        synchronize( this ) {
            return original.invocation( args );
        } 
    }
}
...
Foo f;
Synchronized<Foo> f2;
f.bar();
f2.bar(); // would be valid for the type-system

, where invocation and original would be keywords for this novel abstraction.

The new type can be seen as a proxy / wrapper / adapter around the original type. Whether the new type still represent a subtype of the original or not is then another question. How far the abstraction would support changing the return type is also another question.

While byte code instrumentation, AOP or custom class loader could achieve part of this, I would say that in spirit the closest match is a dynamic proxy. The code of a dynamic proxy looks indeed terrible similar to what I wrote above. Here, here and here are situations I solved with dynamic proxies. Of course dynamic proxies are not static but as the name says, dynamic.

I fear that the general problem that you describe -- how to create variations of existing types -- is too broad. Proposition of type system extension have been made for specific situations, e.g. how to create an adapter from interface X to Y so that all concrete implementation of X can also be seen as implementation of Y.

Maybe have a look at these papers (I haven't read them all yet, but I plan to):

For the last one, the abstract says:

We discuss the precise benefits and costs of our extension in terms of the criteria introduced, and illustrate the usefulness of uniformly available proxies by implementing future method invocations both safely and transparently.

, which was one of your question.

Cool question btw, I wish a general solution to your problem exist. I don't pretend to be an expert in the subject, so there might even be one, but I'm not aware of.

ewernli