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

actually, the scala version is also "pretty verbose" compared to the java version too, so I may have failed in terms of making it appear more expressive (although I'm not conviced expressiveness is correlated with verbosity, but that's another story). However, my scala style could probably be improved, so please don't let this put you off!

@timcowlishaw
Copy link

....also I got the view bound syntax wrong. Try this, which actually compiles:

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

  trait Speaker[A] {
    def speak : Unit;
  }

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

  implicit def standupCanSpeak(standup : StandupComedian) : Speaker[StandupComedian] = {
    return new Speaker[StandupComedian] {
      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

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