1

I often wanted to be able to decorate java-classes properly, that is add behaviour to them. I know mixins from ruby, and i know that they can get terribly confusing.

I came up with the theoretical idea of having a language-construct like this:

package org.test.decorator;

public decorator ListPatch<E> extends List<E> {
    public E last() {
        return this.get(this.size() - 1);
    }
}

this would give access to public members of List and the Decorator itself.

Then in a class i could use:

package org.test.decorator;

decoration org.test.decorator.ListPatch;

public MyClass {
    public void foo() {
        List<String> list = Lists.newArrayList();
        list.add("test");
        System.out.println(list.last());
    }
}

I don't have that much knowledge about compilers, so I wondered if something like that was possible. Also if it actually would be an improvement.

Fabian Zeindl
  • 5,860
  • 8
  • 54
  • 78
  • Well, here's an article from 2000: http://csis.pace.edu/~bergin/patterns/multipleinheritance.html – Hamish Jul 29 '12 at 21:57
  • Your first task would be to come up with a rigorous non-ambiguous definition that covered all the cases and didn't break anything else in the language. I think you would find that part of the task daunting enough in itself. – user207421 Jul 30 '12 at 01:12

3 Answers3

2

Sure, it's possible.

The fact that Scala compiles to bytecode (and has a fairly straight forward mapping from Scala classes to bytecode classes) and supports mixins proves this.

Here's how your sample code looks in Scala syntax:

class ListTest {

    // ...

}

trait ListPatch {
    def last {
        // ...
    }
}

object Main {
    def main(args: Array[String]) {
        val list = new ListTest() with ListPatch;
        list.add("test")
        println(list.last)
    }
}

Scala compiles this by adding an axillary class Main$$anon$1 which composes ListTest and ListPatch.

The motto for the Java developers have always been (and will probably always be) "If in doubt, leave it out." though.

Related questions:

Community
  • 1
  • 1
aioobe
  • 413,195
  • 112
  • 811
  • 826
1

Not really an Answer to your question but you can solve this problem with inversion of control/dependency injection (just like you did in your code)

basically: don't use "new ArrayList()" but instead some factory like "injector.new(ArrayList.class)". This injector can now override the wanted class and return an Object which extends ArrayList decorated with your methods.

Absurd-Mind
  • 7,884
  • 5
  • 35
  • 47
1

Your idea sounds much like Extension methods in C#.

Extension methods enable you to "add" methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type.

In C# you would write your example as:

public static class ListExtensions
{
    public E Last(this List<E> list)
    {
        return list[list.Count - 1];
    }
}

Using it like this:

List<String> list = new List<String>();
list.Add("test");
Console.WriteLine(list.Last());

So, from a design perspective it can certainly be designed and added. However, there are other considerations that come into play when adding something to an existing language, such as syntax conflicts, backwards compatibility, edge cases, and cost of designing and coding it versus the benefits it provides.

Eric Lippert has a great blog about Extension Properties (a natural extension of Extension Methods) in C#, and in the second part he highlights some of the aspects that affect why doesn't product X have feature Y?, which I'm sure also applies to Java and its development.

Daniel A.A. Pelsmaeker
  • 47,471
  • 20
  • 111
  • 157