Skip to content

Instantly share code, notes, and snippets.

@rentalcustard
Created October 31, 2012 10:15
Show Gist options
  • Save rentalcustard/3986263 to your computer and use it in GitHub Desktop.
Save rentalcustard/3986263 to your computer and use it in GitHub Desktop.
My experience of static typing.
class MasterOfCeremonies { //I hate naming in potted examples
public void handle(Dog dog) {
dog.speak();
}
}
class Dog {
public void speak() {
//something
}
}
//And now I want handle to accept anything that can speak...
class MasterOfCeremonies {
public void handle(Speaker speaker) {
speaker.speak();
}
}
interface Speaker {
void speak();
}
class Dog implements Speaker {
public void speak() {
//something
}
}
class StandupComedian implements Speaker {
public void speak() {
//something else
}
}
class MasterOfCeremonies
def handle(speaker)
speaker.speak #no need to define an interface, anything that responds to speak accepted by this method.
end
end
@timcowlishaw
Copy link

Totally don't need the type parameter on Speaker either:

class MasterOfCeremonies {
  def handle[A <% Speaker](speaker : A) : Unit = {
    speaker.speak
  }

  trait Speaker {
    def speak : Unit;
  }

  implicit def dogCanSpeak(dog : Dog) : Speaker = {
    return new Speaker {
       override def speak : Unit = {
          //implement the dog's speak method here
       }
    }
  }

  implicit def standupCanSpeak(standup : StandupComedian) : Speaker = {
    return new Speaker {
      override def speak : Unit = {
        //implement the standup's speaking related functionality here
     }
    }
  }
}

class Dog {
 //dog-specific implementation
}

class StandupComedian {
 //stand-up comedian specific implementation
}

@timcowlishaw
Copy link

Of course, you can also replicate the Ruby-ish duck-typing behaviour, with static checking, using a structural type:

class MasterOfCeremonies {
  def handle(speaker : {def speak : Unit}) : Unit = {
    speaker.speak
  }
}

class Dog {
  def speak : Unit = {
    println("Woof")
  }
}

class StandupComedian {
  def speak : Unit = {
    println("'That Bond villain came in my pub last night. Got drunk and behaved appalingly.' 'Javier Bardem?' 'No, he can come back when he's sober.'")
  }
}

val mc = new MasterOfCeremonies
val dog = new Dog
val standup = new StandupComedian

mc.handle(dog)
mc.handle(standup)

...that way, compilation will fail if handle is not passed an instance of a class that implements speak, but gets around the need to have an actual named interface. However, this still requires you to re-open the classes that you want to implement 'Speak' though, so we still have the same problem as above (I actually just found out there's a name for this).

You could probably have the best of both worlds with an implicit conversion to a structural type, but this doesn't seem to work, sadly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment