Scala DuckTyping

Jul - 07 2016 | By

Duck Typing is Defined as

In duck typing, a programmer is only concerned with ensuring that objects behave as demanded of them in a given context, rather than ensuring that they are of a specific class

But its best put

“If it looks like a duck and quacks like a duck, it’s a duck”

Its always a good idea to give an example to show (I’m a visual person in that respect)   Let say we have a Person Case Class and we know that a person can be married

 

trait Marriageable
case class Person(
                   firstName: Option[String] = None,
                   lastName: Option[String] = None,
                   married: Option[Boolean] = None
                 ) extends Marriageable


Now lets create a MarriageStatus case class


case class MarriedStatus(
                          isMarried : Option[Boolean],
                          marriedDate : Option[String]
                        )

How can we apply a married status to a person?
Lets create a generic trait of updatable to which we can wrap MarriedStatus Around
We're T is a Marriageable type


trait Updatable[T >:  Marriageable] {
  def applyMarriage[T](updatedObject: T): T
}



Lets create a Marriage Wrapper than implements the applyMarriage


case class MarriageHelper(val marriage : MarriedStatus) extends Updatable[Marriageable]
{
  override def applyMarriage[T](updatedObject: T): T = updatedObject match
{
    case person: Person =>
      person.copy(
        married = marriage.isMarried
      ).asInstanceOf[T]
  }
}


The results will be apply a marriage object to a Person




Let put it all together

package test.ducktyping

import org.scalatest.{BeforeAndAfterAll, FlatSpec}

class MarriageTest extends FlatSpec with BeforeAndAfterAll {
  
  trait Marriageable
  
  trait Updatable[T >:  Marriageable] {
    def applyMarriage[T](updatedObject: T): T
  }
  
  case class Person(
                     firstName: Option[String] = None,
                     lastName: Option[String] = None,
                     married: Option[Boolean] = None
                   ) extends Marriageable

  
  case class MarriedStatus(
                            isMarried : Option[Boolean],
                            marriedDate : Option[String]
                          )
  
  case class MarriageHelper(val marriage : MarriedStatus) extends Updatable[Marriageable]
  {
    override def applyMarriage[T](updatedObject: T): T = updatedObject match
    {
      case person: Person =>
        person.copy(
          married = marriage.isMarried
        ).asInstanceOf[T]
    }
  }


  behavior of "a marriageable object"
  it should "be able to apply a marriage to it" in {

    var husband = new Person(Some("John"), Some("Doe"), Some(false))
    var wife = new Person(Some("Jane"), Some("Doe"), Some(false))
    val justMarried = new MarriageHelper(new MarriedStatus(Some(true), Some("now")))

    println("Husbands Married status = "+husband.married.get)
    println("Wifes Married status = "+wife.married.get)


    println("Applying Marriage")

    husband = justMarried.applyMarriage(husband)
    wife = justMarried.applyMarriage(wife)

    println("Husbands Married status = "+husband.married.get)
    println("Wifes Married status = "+wife.married.get)
  }
}
and it should output 

Husbands Married status = false
Wifes Married status = false
Applying Marriage
Husbands Married status = true
Wifes Married status = true



So now we can apply a marriage to any object that is marriageable
For eaxmple, we want to marry a dog


case class Dog(
                   name: Option[String] = None,
                   married: Option[Boolean] = None
                 ) extends Marriageable
Then we just update our applyMarriage to tell it how to handle a dog


case dog: Dog =>
  dog.copy(
    married = marriage.isMarried
  ).asInstanceOf[T]




Comments are closed. Please see front page on how to contact me