Applying Scala to solving real world problems: Making delegation super easy
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("...")
}
}
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)






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
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
J Szy replied on Wed, 2010/06/16 - 6:56am
in response to:
Cay Horstmann
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 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.
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.
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
Examples above suggest otherwise.
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
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
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
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"