Published 2014-08-04.
Last modified 2016-10-25.
Time to read: 3 minutes.
Structural types provide a typesafe way to use reflection. With structural types, you trade off execution speed for extra flexibility when using inheritance.
The sample code for this lecture can be found in
courseNotes/
.
Structural types are sometimes called
duck types.
This is because if something acts like a duck, then it can be considered as a duck for practical purposes.
Similarly, if an object has one or more methods with specific signatures, or properties with specific names and types
then the object can be considered to be a given type.
In Scala, a structural type is defined {
by writing one or more method signatures and/or properties within curly braces }
.
object Ducks1 extends App { case class Mallard(age: Double) { def quack(count: Int): Unit = println("Quack! " * count) } case class FrenchDuck(weight: Double) { def quack(count: Int): Unit = println("Le quack ! " * count) } val mallard: { def quack(count: Int): Unit } = Mallard(4) val frenchDuck: { def quack(count: Int): Unit } = FrenchDuck(5) mallard.quack(2) frenchDuck.quack(3) }
You can run this code by typing.
$ sbt "runMain Ducks1" Quack! Quack! Le quack ! Le quack ! Le quack !
Using Type Aliases
Structural types are easier to work with when defined as type aliases. We could rewrite the above using a type alias as follows.
object Ducks2 extends App { type Duck = { def quack(count: Int): Unit }
case class Mallard(age: Double) { def quack(count: Int): Unit = println("Quack! " * count) }
case class FrenchDuck(weight: Double) { def quack(count: Int): Unit = println("Le quack ! " * count) }
val mallard: Duck = Mallard(4) val frenchDuck: Duck = FrenchDuck(5)
mallard.quack(2) frenchDuck.quack(3) }
You can run this code by typing:
$ sbt "runMain Ducks2"
Output is the same as before.
Structural Types With Properties
Structural types can also be defined by their properties.
Type aliases make this code much more readable.
Duck3
shows how structural type Duck
requires that candidate objects possess a method
called quack
and a String
property called color
.
object Ducks3 extends App { type Duck = { def quack(count: Int): Unit
val color: String }
case class Mallard(age: Double) { def quack(count: Int): Unit = println(s"Mallard has $color feathers: " + "Quack! " * count)
val color = "yellow" }
case class FrenchDuck(weight: Double) { def quack(count: Int): Unit = println(s"Le canard français a des plumes $color : " + "Le quack ! " * count)
val color = "blue" }
val mallard: Duck = Mallard(4) val frenchDuck: Duck = FrenchDuck(5)
mallard.quack(2) frenchDuck.quack(3) }
You can run this example by typing:
$ sbt "runMain Ducks3" Mallard has yellow feathers: Quack! Quack! Le canard français a des plume blue: Le quack ! Le quack ! Le quack !
Structural Types and Reflection

Structural types are syntactic sugar around reflection. It is not possible to extends a structural type or inherit from it, and not possible to override structural type methods. This means the following will not compile.
class BadDuck extends { def quack(Int) } {
def waddle() = println("Waddling...")
}
Here are two ways of accomplishing this legally, first using a trait, second using an abstract class:
object GoodDuck extends App { trait DuckLike { def quack(count: Int): Unit }
class DuckExtendsTrait extends DuckLike { def quack(count: Int) = println("DuckExtendsTrait: " + "Quack! " * count)
def waddle() = println("DuckExtendsTrait Waddling...") }
abstract class AbstractDuck { def quack(count: Int): Unit }
class DuckConcrete extends AbstractDuck { def quack(count: Int) = println("DuckConcrete: " + "Quack! " * count)
def waddle() = println("DuckConcrete: Waddling...") }
val duck1 = new DuckExtendsTrait duck1.quack(3) duck1.waddle()
val duck2 = new DuckConcrete duck2.quack(3) duck2.waddle() }
You can run this by typing:
$ sbt "runMain GoodDuck" DuckExtendsTrait: Quack! Quack! Quack! DuckExtendsTrait Waddling... DuckConcrete: Quack! Quack! Quack! DuckConcrete: Waddling...
Structural Types With Parametrics
This example extends the With pattern first introduced in the
More Fun With Functions lecture of the
Introduction to Scala course, which was made parametric in the
’With’ Pattern Revisited section of the
Parametric Types lecture of this course, and further explored in the
Parametric ’With’ Pattern Revisited section of the
Partial Functions lecture.
We will now use the With pattern to define a using
method that is an example of a best practice:
employing a mechanism that automatically closes resources, even when an exception is thrown.
Structural types are often used in conjunction with parametric types.
Here is a useful example that shows how the structural type Closeable
defines an upper bound for A
; in other words, A
must be a subclass of Closeable
.
For a structural type, that means A
must implement Closeable
.
Note that ByteArrayInputStream
has a close
method,
so it conforms to the Closeable
structural type signature.
object Structural extends App { type Closeable = { def close(): Unit }
def using[A <: Closeable, B](closeable: A)(f: A => B): B = { try { f(closeable) } finally { try { closeable.close() } catch { case _: Throwable => () } } }
val byteStream = new java.io.ByteArrayInputStream("hello world".getBytes) using(byteStream){ in => val str = io.Source.fromInputStream(in).mkString println(s"’$str’ has ${str.length} characters") } }
You can run this code by typing:
$ sbt "runMain Structural" ’hello world’ has 11 characters
BTW, we can improve this program by using call by name for the closeable
parameter.
The reasons for doing that were explored in the Call By Name / Lazy Evaluation of a Parameter section of the
More Fun With Functions lecture of the
Introduction to Scala course.
object Structural2 extends App { type Closeable = { def close(): Unit } def using[A <: Closeable, B](closeable: => A)(f: A => B): B = { val closeableRef = closeable // only reference closeable once try { f(closeableRef) } finally { try { closeableRef.close() } catch { case _: Throwable => () } } } val byteStream = new java.io.ByteArrayInputStream("hello world".getBytes) using(byteStream){ in => val str = io.Source.fromInputStream(in).mkString println(s"’$str’ has ${str.length} characters") } }
You can run this code by typing:
$ sbt "runMain Structural2" ’hello world’ has 11 characters

Self Traits and Structural Types
Self types can extend structural types.
type Openable = { def open(): Unit } type Closeable = { def close(): Unit }
trait Door { self: Openable with Closeable => def doSomething(f: () => Unit): Unit = try { open() f() } finally { close() } }
class FrontDoor extends Door { def open(): Unit = println("Door is open")
def walkThrough(): Unit = doSomething { () => println("Walking through door") }
def close(): Unit = println("Door is closed") }
BTW, we could equally well have defined a type alias that specifies both the open
and close
methods:
type OpenAndCloseable = { def open(): Unit def close(): Unit }
... and then the self trait would have looked like this.
trait Door { self: OpenAndCloseable =>
Let’s play with this in the REPL:
scala> val frontDoor = new FrontDoor frontDoor: FrontDoor = FrontDoor@595b5d6b
scala> frontDoor.walkThrough() Door is open Walking through door Door is closed
You can also run this code by typing:
$ sbt "runMain SelfStructural"
This trait assumes that the object which it extends, referred to as self
,
has methods called open()
and close()
.
This allows for safe mixins for duck typing.
Remember that structural types are somewhat inefficient because they use reflection,
so don’t write this type of code in a loop that gets called a lot.
© Copyright 1994-2024 Michael Slinn. All rights reserved.
If you would like to request to use this copyright-protected work in any manner,
please send an email.
This website was made using Jekyll and Mike Slinn’s Jekyll Plugins.