Yep, it's just late binding.
If you want that in the JVM, you can use Groovy, which does just that.
If you want that in the JVM, you can use Groovy, which does just that.
class Fire{}
class Water {}
class Grass {}
class Ice {}
def eff(Fire f, Grass g) { 'burn' }
def eff(Fire f, Ice ice) { 'melt' }
def eff(Water w, Grass g) { 'grow' }
def eff(Water w, Ice ice) { 'freeze' }
def eff(a, b) { 'undefined' }
println eff(new Fire(), new Grass())
println eff(new Fire(), new Ice())
println eff(new Water(), new Grass())
println eff(new Water(), new Ice())
println eff(new Ice(), new Water())
Prints:burn melt grow freeze undefined
EDIT: to make it even more obvious there's no difference:
class Fire{}
class Water {}
class Grass {}
class Ice {}
def eff(Fire f, Grass g) { 'burn' }
def eff(Fire f, Ice ice) { 'melt' }
def eff(Water w, Grass g) { 'grow' }
def eff(Water w, Ice ice) { 'freeze' }
def eff(a, b) { 'undefined' }
// hide compile-time types
Object fire = new Fire()
Object grass = new Grass()
Object ice = new Ice()
Object water = new Water()
println eff(fire, grass)
println eff(fire, ice)
println eff(water, grass)
println eff(water, ice)
println eff(ice, water)
Prints: burn
melt
grow
freeze
undefined