Mixing Java for Fun
While looking at Platypus, a Java mixins framework, I’ve felt that is was a little too complicated inside and not that extensible from the outside. So, behind the “how simple can it be done”, I’ve started the Quacking Java mixins framework. The idea was to keep it simple and have no external dependencies, that is, only use standard Java features. Java does not support mixins so the framework is obviously limited to dynamic proxys.
It’s a bit of a solution for a problem I don’t really have. But it was fun to explore. So the basic idea was:
- We add objects into a mixin object,
- Obtain an interface from the mixin,
- And invoke a method in the interface.
Invoking a method in the interface will invoke a method in one of the objects. Those objects only need the method signature to match, that is, they don’t really need to implement any interface at all.
1 | public interface Stringable { |
1 | Simple toString() redefinition |
The toString()
method is actually a method at the Object
level. Since
Object
is not an interface an Stringable
was defined. But actually any
interface would do, since they all inherit Object
.
The order in which objects are added to the mixin is important to keep the method
redefinition consistent. The first object added will be searched first, the
second will be searched if the first did not have a matching method, and so on.
In the previous example this means that no invocation would reach that second
Object
instance.
But we can change the order and only bring an object to the front for a
particular interface. In the next example, the indexOf(Object)
is actually
provided by the mixed string. The Object
level methods are provided by the
actual list, so you can put the mixin in an hash table and it will behave like
if you had put the list directly.
1 | Mixin mixin = new Mixin(); |
1 | 3*x^2 + 2*y + 1 |
All these samples are academic because, like I said, there was not really a problem to solve. Still a more partical application would be, for example, to mix a behavior to a collection that delays the modification of the collection. You pass the collection to various methods and, instead of making the collection unmodifiable, you save the changes until all methods finish.
1 | public class DelayedAdd { |
1 | [1, 2, 3] |
The mixing also supports renaming of methods and currying. This allows us to
make any method without arguments a Runnable
and methods with at least 1
argument Callable
instances. When currying you cannot supress arguments, just
add more static arguments. You also need to specify the parameter types
explicitly. This is to avoid resolving the method by name immediatly (there
could be several), and to deal better with the possibility of renaming. Still,
it’s an improvement to consider. Even so, the next example shows some serious
adaptation of objects to Runnable
.
1 | ExecutorService pool = Executors.newFixedThreadPool(1); |
1 | java.util.concurrent.Semaphore@16360268[Permits = 1] |
And we haven’t actually used any really mixing of behaviors. To do that we can
implement Mixer
and have objects that go back to the Mixin
and call other
interfaces. It must be all interface-based, off course, but it allows stuff
like the following.
1 | public interface LockingRunnable { |
1 | 10 executed in pool-2-thread-2 |
Well, it’s a little toy library. The performance is very poor when compared with
the creation of several anonymous Runnable
classes, for example. Still, not
having to create those anonymous classes or other adaptor classes just to plug
and play methods is nice and sometimes refreshing.