Traits and Interfaces
Author |
Message |
wtd
|
Posted: Thu Jan 11, 2007 5:25 am Post subject: Traits and Interfaces |
|
|
Understanding traits, coming from Java interfaces.
At the simplest level, you can roughly equate these two language constructs.
code: | interface EmptyInterface {
}
class EmptyClass implements EmptyInterface {
} |
code: | trait EmptyTrait
class EmptyClass extends EmptyTrait |
We can replicate the functionality of Java interfaces with traits.
code: | interface Foo {
public String bar();
}
class Baz implements Foo {
public String bar() {
return "Qux";
}
} |
code: | trait Foo {
def bar: String
}
class Baz extends Foo {
def bar = "Qux"
} |
Traits can extend other traits, as interfaces can in Java. But the real fun comes from the differences. An interface in Java may contain only specifications for methods, and not actual definitions.
To get a mix, we have to use abstract classes, but we can't use those like interfaces. This gives rise to a pattern.
code: | interface Foo {
public String foo();
}
class FooUtilities {
static void printFoo(Foo f) {
System.out.println(f.foo());
}
}
class Bar implements Foo {
public String foo() {
return "bar";
}
}
public class Test {
public static void main(String[] args) {
Bar b = new Bar();
FooUtilities.printFoo(b);
}
} |
Here we have an interface Foo which defines that any object of type Foo will have a public "foo" method which returns a String. The static method "printFoo" in the FooUtilities class takes advantage of this to act on an object of type Foo.
We can replicate this pattern in Scala easily enough.
code: | trait Foo {
def foo: String
}
object FooUtilities {
def printFoo(f: Foo) = System.out.println(f.foo)
}
class Bar extends Foo {
def bar = "bar"
}
object Test extends Application {
val b = new Bar
FooUtilities.printFoo(b)
} |
This looks a bit cleaner. The thing is, though, we can do better.
In the original Java, we used a class with a static method to abstract out concrete functionality that was solely dependent on the abstract functionality present in any object of type Foo.
As Scala allows traits to include concrete functionality, this pattern is not necessary.
code: | trait Foo {
def foo: String
def printFoo = System.out.println(foo)
}
class Bar extends Foo {
def bar = "bar"
}
object Test extends Application {
val b = new Bar
b.printFoo
} |
Alternatively, we can abstract this concrete functionality out, and only mix it into implementing classes where explicitly desired.
code: | trait Foo {
def foo: String
}
trait ExtendedFoo extends Foo {
def printFoo = System.out.println(foo)
}
class Bar extends Foo with ExtendedFoo {
def bar = "bar"
}
object Test extends Application {
val b = new Bar
b.printFoo
} |
We can even choose to only mix the functionality in ExtendedFoo into specific objects.
code: | trait Foo {
def foo: String
}
trait ExtendedFoo extends Foo {
def printFoo = System.out.println(foo)
}
class Bar extends Foo {
def bar = "bar"
}
object Test extends Application {
val b = new Bar with ExtendedFoo
b.printFoo
} |
Conclusion
Understanding the similarities and differences between traits in Scala and interfaces in Java can lead to some pretty interesting insights about the abstractions present in the two languages, and the patterns that arise to deal with those abstractions. |
|
|
|
|
|
Sponsor Sponsor
|
|
|
|
|