August 09, 2005

Quantum Software Design

Guido von Rossum is considering adding interfaces to Python.  In this article, he explains that the power of interfaces has forced a few major Python projects to implement their own version of interfaces, which is probably a sign that such a feature is needed in Python itself.

Mix-ins are strikingly absent from Guido's discussion and I really wonder why.  Mix-ins don't exactly address the same need as interfaces but they are a better fit for scripting languages where concrete and granular software contracts are more important then schemas.

I actually happen to think that mix-ins would be a very welcome addition to Java as well and I can think of many times when I have needed the functionality provided by a set of methods and I was forced to use one of the following three workarounds:

  • Move these methods in a separate class and make them static.
  • Extend the class they belong to (an approach that is wrong on many counts).
  • Use delegation.

Here is a concrete example of this problem.

Imagine that some of your classes need to expose the properties "shortName" and "longName" with getters and setters.  While interfaces let you specify this contract easily (an interface with four methods), you still need to find a way to capture this implementation in a separate class.

Let's start with the obvious:

public class Nameable {
  private String m_shortName;
  private String m_longName;

  public String getShortName() {
    return m_shortName;
  }

  public void setShortName(String s) {
    m_shortName = s;
  }

  public String getLongName() {
    return m_longName;
  }

  public void setLongName(String s) {
    m_longName = s;
  }
}

At this point, Java forces you to use one of the three techniques described above, but imagine we could do the following:

public class Employee {
  import com.beust.Nameable;  // illegal Java
  // ...
}

Importing the class inside your own class is equivalent to doing a copy/paste of the content of the imported class, so that the following becomes valid:

Employee e = new Employee();
e.setShortName("Cedric");
e.setLongName("Cedric Beust");

There are a lot of things to like about this approach:

  • Your Employee class is much less verbose.  Getters and setters are notoriously verbose in Java and while the Ruby equivalent of Nameable would fit on one line, reading through the Java code adds a lot of noise around what should be a simple concept.
     
  • You are not perverting your type system by extending a class you have no clear "is-a" relationship with.
     
  • Changes to the imported class are automatically imported into your class, so you don't need to keep up with them (as you would with delegation since need to implement new forwarding methods if new methods are added to the delegate).

One might argue that the methods imported are not obvious in your class, but this is no different from regular inheritance, and IDE's can show the imported methods just as easily.

Once the concept of mix-ins is made available to you, you start looking at your code in very different ways and just when you thought you had done a pretty good job at creating small modular classes that interact nicely with each other and isolate the responsibilities in clear ways, you start realizing that you could decompose your architecture much further.  Interfaces allowed you to create a nice abstract schema of your code and mix-ins give you the power to create a nice concrete decomposition as well.  It's code reuse at its best.

If you take this concept far enough, you end up with "Quantum Software Design", software that is made of a lot of very tiny pieces that you can mix and match at your leisure without compromising your architecture.

I already used the term "Quantum AOP" a couple of years ago to describe software made of tiny aspects that get woven together to create the final product.  This is a very similar concept except that instead of using AOP as the glue, we use a simple, albeit hypothetical as of today, feature of the Java language:  internal class imports.

Interestingly, Quantum Software Design is also a technique that I started identifying recently in my Java code, but this time tied to a totally different framework.  I'll keep the name of this framework secret for now so I can dedicate an entire entry to it very soon.

Posted by cedric at August 9, 2005 11:23 AM
Comments

"Quantum Software Design" for an idea that's completely unrelated to quantum computing or quantum physics ?

Sorry, I just can't resist a bogus analogy... you make me do it... I claim the idea as MINE!

Posted by: Martin Fowlbot at August 9, 2005 12:23 PM

It's related to quanta... The smallest unit that your code can be broken into.

Maybe we should call then "swanta"... Software Quanta :-)

--
Cedric

Posted by: Cedric at August 9, 2005 12:26 PM

Oh, it warms my physicist's heart to see the term Quantum in use here! :) The mix-ins in Java would really help ensuring the Single Responsibility Principle.

Posted by: Kai Virkki at August 9, 2005 12:32 PM

Another interesting, albeit slightly different, approach is the "category" concept in Objective-C.
With categories, you don't explicitely import a mixin into a class, but define a category on an existing class, and implement new methods (but no new ivars). Not unlike partial classes in C#, but you can apply that on any class without restriction. Of course, it's quite easy to do in Objective-C as the runtime is very Smalltalkish.

An interesting use is often to add new methods to existing classes from a standard libraries, for adhoc methods adding new behavior to a string class (i.e. 'getMD5Hash') and subclasses. Non-verbose and quite elegant when using it as a regular method. The drawback is of course that the added behavior is not explicit on the extended class.

In actual code, it's more often fine-grain extension than fine-grain decomposition for an new implementation, but it could probably related to the 'quantum software design school of thought' :)

Posted by: Olivier Gutknecht at August 9, 2005 12:57 PM

I'm not sure I understand all this, but how is this better then multiple inheritance? Python has multiple inheritance so you can mix via that. Ex.: are there name clashes in mixins?
And I would say this is still is-a so you can't stop someone from using parent class methods not nedded wile with delegation you can.

Posted by: at August 9, 2005 01:28 PM

I like the idea of adding the mixin at the target class instead of in a separate aspect class definition.

I agree, I think this compositional style of OO programming is very powerful and may be a selling point for AOP -- for java at least -- instead of just "cross cutting of concerns" decomposition.

Posted by: Frank Bolander at August 9, 2005 02:01 PM

The feature described by Cedric seems to be equivalent to multiple inheritence and quite different to mixins as implemented in Ruby.

I think that language support for delegation in Java might be worth considering.
Something like:

public class Employee {
com.beust.Nameable name;
expose name.setShortname, name.setLongName;
// ...
}

This would be equivalent to defining setShortname and setLongName in Employee to delegate to the name instance variable.

Posted by: Peter McK at August 9, 2005 02:12 PM

maybe :)
public class Employee imports Nameable, Payable {
}

Smells of multiple inheritence - even if you boil it down to just an under the hood copy/paste.

The 1st & 3rd benefits are available with mulitple inheritence. The 2nd benefit - is that really a benefit ? If you have imported the whole implementation - haven't you got an is-a relationship ?

I miss Multiple Inheritence...as well. Complexity and misuse are no excuse to exclude it.

Posted by: Sony Mathew at August 9, 2005 03:14 PM

Peter, I was think it was multiple inheritence as well... but it's not.

Why? Because Employee is _not_ a Nameable.

Inheritence is the inheritance of _type_, with the optional inheritance of _behaviour_. Mixins is the "inheritance" of behaviour, without type. This is the second benefit pointed out by Cedric. Largely because they _don't_ bring in type, mixins avoid a number of problems associated with multiple inheritance. For one thing, mixins have a clear order of import. The "last" method definition always wins (with class-level methods coming "last") in most mixin-based languages.

However, I thought mixins didn't bring in attributes... the m_shortName and m_longName attributes should actually be on the Employee class, I think.

Also, Python already has a well-known mixin technique: http://c2.com/cgi/wiki?MixinsForPython

Mixins would be a good addition to Java. Oh, and mixins are more like the atomic building blocks; the quanta of programming would really be the method. :)

Posted by: Robert Watkins at August 9, 2005 03:59 PM

Mixins would be a blessing for any language. I also like how many Rubyians use mixins to organize more complex classes into shorter parts.

Posted by: Henning Koch at August 9, 2005 05:14 PM

I've thought about this before. Basically I want an alternative to cut/paste and inheritance just as you described.

Posted by: Sam Pullara at August 9, 2005 08:44 PM

This sounds similar to BUG ID 4191243 on the Java Bug Parade. I think this would be a valuable addition to Java.

Posted by: Eric M. Burke at August 10, 2005 04:26 AM

Delphi has had this capability for quite a long time now using the 'implements' keyword. This and a few other features like properties and pascal style enumerators are things I really miss from Object Pascal when working in Java.

Posted by: Gerald at August 10, 2005 06:29 AM

I don't think it is a good idea. This would pollute Java. Your idea is some sort of MACRO function. The compiler does not enforce the code checks of “imports staffed” class.

The nice thing about "extends" and "implements" is that compiler can check at compile time the contract in the inheritance and implementation.

With "imports staffing" you'd we on your own!

Bad idea indeed.

Posted by: Ruslan Zenin at August 10, 2005 06:52 AM

If you are too retarded to handle multiple-inheritance than you surely won't be able to handle mixins. That is why Java will never include mixins. I mean, duh!

Posted by: at August 10, 2005 09:50 AM

Mixins make me uncomfortable. I think they're a bludgeon to solve for repetitive boilerplate, when a little more analysis of the code duplication and of the reason it exists are in order.

For example, I'd rather solve your problem with a 'has-a'. I think 'Nameable' is confusing the discussion since 'able' screams interface/mix-in.

How about:


public class Name() {
private String shortName;
private String longName;
}

public class Employee {
private Name name;
public Name getName() { return name; }
}

public class Pet {
private Name name;
public Name getName() { return name; }
}

.....

return employee().getName().getLongName();


Yes? No?


Here's where I know my model is weak. Suppose I want to customize the name behavior just for a particular type. Since I've explicitly delegated the name behavior to the Name type in my contract for the Employee class, I've lost some control of it. I have to honor the existence of the Name type and still get my custom functionality in there. For example:


public class Employee {

public Employee(Name name) {
this.name = new EmployeeName(name);
}
...
private boolean isContractor;
...
class EmployeeName extends Name() {
public String getLongName() {
if (isContractor) {
return super.getLongName() + " - CON";
} else {
return super.getLongName();
}
}
}


How would this be accomplished with mixins? Any better?

Posted by: sidereal at August 10, 2005 03:15 PM

This approach has a critical weakness in my opinion: Obfuscation.

I much prefer to write employee.getShortName() then employee.getName().getShortName()

Delegation has its uses, but keep in mind what I'm trying to do: reuse an existing implementation made of a few classes so I can expose it *directly* on my class and which I won't have to maintain (if new methods are added, my class will automatically expose these methods as well).

--
Cedric

Posted by: Cedric at August 10, 2005 03:28 PM

You're right. The more I thought about it after commenting the more glaring the problem became. And in fact got me started on a whole chain of thinking about the weakness of types that delegate portions of their contracts to code outside of their control. Of course, the quick solution is just to wrap the calls to Name, which is back to your 3rd existing Java solution.

I think mixins are a heavy solution for that particular problem, since they cut through so many aspects of Java type interaction. For example, what if the mixin and the importing class have member variables of the same name? What if one is static and one not? One final and one not? Etc.

As long as you're changing the language, how about a system to essentially promote the methods of member variables? Something like this:

private Name name;

promote Name.setLongName();
promote Name.getLongName();
promote Name.setShortName();
promote Name.getShortName();

Obviously a compile-time rather than run-time directive. It would push those methods up to be available from the promoting type, though the internal Name would be the object the method is actually called on.

Posted by: sidereal at August 10, 2005 04:37 PM

Dude, that is exacty what I suggested with my 'export' keyword in an earlier comment. Btw, I think you actually want to say:

promote name.setLongName()

because you might have more than one instance variable of type Name. As long as we're off in language feature creation land, maybe the feature could be extended to handle multiple instance variables of the same type? I.e.

private Person mother;
private Person father;

promote mother.getName() as getMothersName;
promote father.getName() as getFathersName;

Its all just syntactic sugar of course. But then so is ++ and who'd be without that?

Posted by: Peter McK at August 10, 2005 09:02 PM

Then it is not Java anymore...

Why not to build a new language and fight the world with its adoption!


Posted by: Ruslan Zenin at August 11, 2005 06:59 AM

You could go off and invent cool new ways to hack mix-ins into a language with single inheritance. Or you could go and read about traits: http://www.iam.unibe.ch/~scg/Research/Traits/

If you examine the paper where they refactor the smalltalk collections API: http://www.iam.unibe.ch/~scg/cgi-bin/oobib.cgi?query=nathanael+applying+traits+to+the+collection+hierarchy+oopsla you'll see that they've given this idea rather a lot of thought.

Posted by: anon at August 12, 2005 05:03 AM

for Mixins in Java using Annotations

See https://rapt.dev.java.net/nonav/docs/api/index.html?net/java/dev/rapt/exploratory/mixin/package-summary.html

Posted by: Bruce Chapman at August 23, 2005 06:21 PM
Post a comment






Remember personal info?