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.
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.
Aspect oriented programming
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With