Gangmax Blog

Scala Duck Typing

This post records a sample how I use Scala duck typing(structural types). The posts “here“, “here“ and “here“ are referred.


Let’s say we have the following Scala code which runs properly without any issue.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Duck {
def getName(): String = {
return "Duck"
}
}

class Eagle {
def getName(): String = {
return "Eagle"
}
}

class Walrus {
def getName(): String = {
return "Walrus"
}
}

def greetingToDuck(someone: Duck): Unit = {
println(s"Hello, ${someone.getName()}!")
}

def greetingToEagle(someone: Eagle): Unit = {
println(s"Hello, ${someone.getName()}!")
}

greetingToDuck(new Duck())
greetingToEagle(new Eagle())
greetingToWalrus(new Walrus())

The problem happens when I want to refact the code by combining the 3 greeting functions into one:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
scala> def greeting(someone: Object): Unit = {
| println(s"Hello, ${someone.getName()}!")
| }
-- [E008] Not Found Error: -----------------------------------------------------
2 | println(s"Hello, ${someone.getName()}!")
| ^^^^^^^^^^^^^^^
| value getName is not a member of Object
1 error found

scala> def greeting(someone: Unit): Unit = {
| println(s"Hello, ${someone.getName()}!")
| }
-- [E008] Not Found Error: -----------------------------------------------------
2 | println(s"Hello, ${someone.getName()}!")
| ^^^^^^^^^^^^^^^
| value getName is not a member of Unit
1 error found

Scala compiler expects the method “getName()” to be found in the declared type of the given “someone” argument. However the types “Duck/Eagle/Walrus” have no common parent class or interface where the “getName()” method is defined at. In dynamic type languages like “Python/Ruby/JavaScript” this is not an issue since there’s no type checking at compiling time. In static type languages like Java, the “getName()” must be declared at some common parent class or interface which the 3 classes extend or implement. So it seems Scala is one of the static type languages, right? no?

Fortunately, we can do something like below in Scala which doesn’t need to modify the definition of the classes(to add common parent class or interface).

1
2
3
4
def greeting(someone: Object): Unit = {
val name = someone.asInstanceOf[{def getName: String}]
println(s"Hello, ${name.getName}!")
}

Note the “{def getName: String}” part which plays the trick here. It casts the given instance from the “Object” type to one which has the “getName()” method defined. To me it seems like a placebo to comfort the compiler. Anyway, by doing so the code works as expected. This feature needs “import reflect.Selectable.reflectiveSelectable”. The full code looks like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import reflect.Selectable.reflectiveSelectable

class Duck {
def getName(): String = {
return "Duck"
}
}

class Eagle {
def getName(): String = {
return "Eagle"
}
}

class Walrus {
def getName(): String = {
return "Walrus"
}
}

def greeting(someone: Object): Unit = {
val name = someone.asInstanceOf[{def getName: String}]
println(s"Hello, ${name.getName}!")
}

greeting(new Duck())
greeting(new Eagle())
greeting(new Walrus())

Unlike traditional “static typing” languages(like “Java”) or “dynamic typing” languages(like “Python/Ruby/JavaScript”), Scala wants to take advantages from both of them. However, this makes it more complicated than both of them in many scenarios. I think that’s one of the reasons why it’s not very popular nowadays.

Comments