Polymorphism in Scala, Introduction to Graphs
Polymorphism in Scala
In Python we explored the concept of polymorphism. We can implement the same method in different classes, then call that method without worrying about which implementation we’re calling.
What would happen if we tried to do something like this in Scala? We can define another class for DJ-ing–maybe one used at a different radio station, with different policies on prizes and song requests:
class AlternativeDJData { private var queue: List[String] = List() def request(caller: String, song: String): String = { queue = song :: queue "Great, we'll play it next" } def play(): String = { val song = queue.head queue = queue.tail song } }
Now let’s say we want to write a method that can use either of these classes. We
should be able to do this: after all, they both implement the request
and
play
methods! We might write something like this:
object Caller extends App { def callIn(djd: TYPE): Unit = { println(djd.request("Doug", "Stairway to Heaven")) println(djd.play()) } callIn(new RockDJData("Alex")) callIn(new AlternativeDJData()) }
What should we fill in as the type of djd
? If we put RockDJData
, we
won’t be able to use the method with AlternativeDJData
. If we put
AlternativeDJData
we won’t be able to use it with RockDJData
. And if
we write another class–maybe JazzDJData
–we’ll have more problems.
We want to be able to put something as the type of djd
that tells Scala:
anything we pass as the argument to this method will implement the request
and
play
methods. We can do this:
trait DJData { def request(caller: String, song: String): String def play(): String } // edit class definitions class RockDJData extends DJData class AlternativeDJData extends DJData
Then we can edit our definition of callIn
:
object Caller extends App { def callIn(djd: DJData): Unit = { println(djd.request("Doug", "Stairway to Heaven")) println(djd.play()) } callIn(new RockDJData("Alex")) callIn(new AlternativeDJData()) }
Introduction to graphs
Here are a few scenarios, each specifying data we might want to track and access in a computer program. The scenarios are all related, though it may be difficult to see this at first!
- A social networking application tracks friendships between people.
- A railroad company tracks which of its stations are connected, and what the distances between them are
- A gossip blog tracks which musical artists have recorded diss tracks targeting which other individuals.
As an exercise, try drawing diagrams representing each of these scenarios. What do your diagrams have in common? What are the differences?
Each of these situations can be represented by a graph. A graph consists of:
- nodes
- a node represents a single piece of data, for instance a person (in the case of the social network or the gossip blog) or a railroad station. You will sometimes see nodes referred to as “vertices” (the plural of “vertex”).
- edges
- edges connect pairs of nodes. For instance, in the social network an edge is a friendship.
Nodes almost always store data. Edges can also store data–for instance, the distance between two railroad stations, or maybe the title of a diss track.
Graphs can be either undirected or directed. In an undirected graph, edges simply connect pairs of nodes. Edges in undirected graphs are usually drawn as lines. In a directed graph, each edge connects a source node and a destination node; in other words, edges have a direction. Edges in directed graphs are usually drawn as arrows between the source and the destination.
The social network and the railroad are probably undirected graphs (although not all social networks are undirected–what about Twitter?). The gossip blog needs a directed graph–an artist might have recorded a diss track targeting someone who hasn’t recorded a diss track of their own!