I am the senior IT manager at the Macau Productivity and Technology Transfer Center. I've written popular books on agile and web technologies and created an open source testing library for Wicket. kent is a DZone MVB and is not an employee of DZone and has posted 7 posts at DZone. You can read more from them at their website. View Full User Profile

Applying Scala to solving real world problems: Making delegation super easy

06.15.2010
| 7260 views |
  • submit to reddit
In Java it is very common to write boring code like below to perform logging:
public class Foo {
private static Logger logger = LoggerFactory.getLogger(Foo.class);

public void m1() {
logger.debug("...");
...
logger.debug("...");
}
public void m2() {
logger.debug("...");
...
logger.debug("...");
}
}
As you keep typing the delegation call logger.debug(…) repeatedly, you’ll wonder if there is an easy way to do that. For example, you can create your own debug() method, then you can just call debug() instead of logger.debug():
public class Foo {
private static Logger logger = LoggerFactory.getLogger(Foo.class);

public void debug(String msg) {
logger.debug(msg);
}
public void m1() {
debug("...");
...
debug("...");
}
public void m2() {
debug("...");
...
debug("...");
}
}
The problem is that,you’ll need to create other similar methods like info(), warn() and error(). In addition, when you work on another class Bar, you will need to create those  methods in Bar again! To solve these problems, you may extract this code into a common base class to be reused:
public class DelegatingLogger {
protected static Logger logger;

public void debug(String msg) {
logger.debug(msg);
}
public void info(String msg) {
logger.info(msg);
}
...
}

public class Foo extends DelegatingLogger {
static {
logger = LoggerFactory.getLogger(Foo.class);
}
public void m1() {
debug("...");
...
debug("...");
}
}
However, because Java only support single inheritance, if Foo needs to inherit a real base class, then this approach won’t work. To solve this problem in Scala, we can make the DelegatingLogger class a “trait” which is an auxiliary base class (any class can be a trait as long as its constructor takes no argument):
trait DelegatingLogger {
val logger: Logger = LoggerFactory.getLogger(getClass());

def debug(msg: String) {
logger.debug(msg)
}
def info(msg: String) {
logger.info(msg)
}
}

class Foo extends SomeParent with DelegatingLogger {
def m1 {
debug("...")
...
debug("...")
}
}

What the trait mechanism does here is essentially allowing us to easily turn the Foo class from a logger user into a logger itself, that is, turning a “use” relationship into an “is” relationship.

If you’re careful, you may notice that now the logger is an instance variable, not a static variable. If you’re concerned about it, you can let a singleton object (which is also named Foo here but could be anything else) inherit DelegatingLogger, then use a static import to make the static methods available in the Foo class:

object Foo extends DelegatingLogger {

}

import Foo._

class Foo extends SomeParent {
def m1 {
debug("...")
}
}
References
Published at DZone with permission of kent tong, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags:

Comments

Cristian Vasile... replied on Tue, 2010/06/15 - 3:32pm

Having a new toy (Scala/traits) is no excuse to throw good OO design principles out the window! In particular, a Foo is never a DelegatingLogger, no matter how hard you want it to be. A Foo uses a DelegatingLogger, which is something else entirely. It makes no sense to use inheritance if you don't take advantage of polymorphism.

It's because of this type of misuse of inheritance that Sun introduced static imports in Java. Some people used to declare constants in an interface and implement that interface, in order to type less...

I wouldn't break good OO design principiples in order to type less.

It seems that people advocating these new languages repetedly fail to understand that reading and understanding a program is much more important than the ability to quickly write it. I would never use arcane symbols and constructs if they make the program faster to write at the expense of making it harder to read and understand. This is because in a normal application - one that you have to think of maintainability - you have to read existing code many times more than it takes to write it initially. An optimistic percentage would be 80% read / 20% write, but it's probably more.

A nice quote come to mind here: "Code as if the next guy to maintain your code is a homicidal maniac who knows where you live".

Java is verbose, yes. But we should think of ways to remove verbosity without making the code harder to understand.

J Szy replied on Tue, 2010/06/15 - 3:37pm

Why on earth should anyone ever do such a thing? I mean really, introducing multiple inheritance, or, worse, static methods to avoid explicit delegation? I'd rather introduce explicit delegation to avoid multiple, or any, inheritance, not the other way around. And even singleton? WTF?

 

Cay Horstmann replied on Tue, 2010/06/15 - 5:52pm

Cristian and Jacek--aren't you a bit narrowminded here? Java isn't the pinnacle of OO purity. There is nothing intrinsically evil about multiple inheritance. Java rejected MI because it feared the complexities that C++ introduced in its implementation. Scala, as well as other languages, provide reasonable MI implementations and show that the Java designers were perhaps overreacting in their zeal to avoid all C++ ugliness.

The "reading and understanding" argument cuts both ways. A program that is littered with boilerplate is hard to read because of its sheer length, and because you always need to make sure that the programmer applied the boilerplate correctly.  

Cristian Vasile... replied on Tue, 2010/06/15 - 11:48pm

Cay, I wasn't talking about Java at all, but rather about OO design. I was simply talking about using inheritance where it doesn't belong. This is a clear case where delegation and not inheritance should be used, regardless of the language.

Slim Ouertani replied on Wed, 2010/06/16 - 3:18am

Hi,

 

I wonder if this is a start point of logging dsl with scala ;) 

This article can clarify some idea http://jonasboner.com/2008/02/06/aop-style-mixin-composition-stacks-in-scala.html

 

slim ouertani

Alexander Grünewald replied on Wed, 2010/06/16 - 5:52am

Cristian, why would it be better to use delegation here instead of mixin composition?

Mixin composition gives extensibility and flexibility. It makes the code easy readable and testable. And with mixin composition the compiler ensures at compile time that the wiring of the classes and objects is correct. Compare this with delegation where you at runtime face some strange error if you failed to setup your classes and objects correctly.

Michal Huniewicz replied on Wed, 2010/06/16 - 6:16am

Well the inheritance example is evil - it is not the goal of OO to save you some typing. The trait example might be worth thinking of.

J Szy replied on Wed, 2010/06/16 - 6:56am in response to: Cay Horstmann

There is nothing intrinsically evil about multiple inheritance.

 Gee, there is nothing intrinsically evil about anything. It's just people not smart or cautious enough to learn to use that without misusing or abusing. Take goto, global variables, closures, continuations, implementation inheritance...

 Java isn't the pinnacle of OO purity.

 Java isn't the pinnacle of anything, it's just a decent language whose original designers were wise enough to reject a few "features" that weren't evil by themselves, but it just happened that they were bringing more harm than good.

Scala, as well as other languages, provide reasonable MI implementations and show that the Java designers were perhaps overreacting

 I'd rather say that this, as well as many other examples, provide reasonable evidence to show that the Java designers were underreacting and they should get rid of any implementation inheritance altogether.

 hard to read because of its sheer length, and because you always need to make sure that the programmer applied the boilerplate correctly.

We're talking logging here, remember? There isn't much boilerplate in prefixing info() or error() calls with "logger." and it really helps. After all, without it, how should I know that error() would just log and not do something more heavy? Or that info() would not show an infobox to the user?

BTW, most of what is called "boilerplate" in Java is there for a very good reason, and really helps to understand the code. 

J Szy replied on Wed, 2010/06/16 - 7:55am in response to: Alexander Grünewald

It makes the code easy readable and testable.

 Examples above suggest otherwise.

 with mixin composition the compiler ensures at compile time that the wiring of the classes and objects is correct.

 This would be nice, but I'm not entirely convinced that I'd be so eager to spoil my design just to have a few extra compile checks. 

Frank Silbermann replied on Wed, 2010/06/16 - 8:06am

Christian's point is that inheritance implies an "Is a ..." relationship; composition implies a "uses ..." relationship. Foo is not a logging utility; a user of your API would not create an instance of Foo in order to log her errors; logging is not be part of Foo's intended public interface. Therefore, Foo should not inherit from Logger.

Foo _uses_ logging, that is why composition is more appropriate.

If you want to use inheritance to implement methods for internal use only, then you need the concept of private or protected inheritance. I think maybe C++ has this; Java does not. If you want to do this sort of thing, maybe Scala also should have private or protected inheritance.

Leo de Blaauw replied on Wed, 2010/06/16 - 9:38am

Well, Yes i see the author wants to make a point of aplying scala, but with any AOP solution be it spring or any other framework this problem is easier solved and more cleanly so Leo

Endre Varga replied on Wed, 2010/06/16 - 11:26am

Class hierarchies are not ontologies.

This means that inheritance does not necessarily represents "isa" relation

Inheritance itself is a method to extract code duplications to a central and more maintainable place. Good example are configuration mechanisms that allow inheritance to reduce unnecessary configuration. Like maven. Inheritance patterns like Template Method also violate the pure "isa" view.

I found the "isa" notion the most harmful to my students mind. This is why they want to create overcomplicated class hierarchies because they want to represent sets and ontologies -- which inheritance cannot cleanly do.

Gabriel Claramunt replied on Wed, 2010/06/16 - 6:31pm

Maybe the example is not very clear but traits are very useful.
Consider them like "interfaces with behavior" and they can be used in a AOP fashion but without the need of external frameworks or extra configuration.
The problem to solve is not when Foo needs to use Logger, but when Foo needs to provide logging services to its clients. In Java you would implement the logger interface and delegate all the calls to the Logger class. Many lines with the only purpose to delegate the calls. Or just "mixin" the trait. In Scala there's no multiple inheritance problem, theres only one base class to extend and the traits hierarchy is "flattened" depending on the mixing order.
Repeat with me: "traits are not inheritance, traits are not inheritance"

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.