Static Dispatch

Objectives: Create container accepting items of any type. Categorize items in runtime. Dispatch methods statically.

Python

Following code works well but I'm unable to give good reasons for doing this in practice. Perhaps performance of this code may be compared with dynamic dispatching. This needs more investigation though.

from typing import Any

class Cat:
    def make_sound(self):
        print("miao")
        
class Cow:
    def make_sound(self):
        print("mooo")

animals: list[Any] = []
animals.append( Cat() )
animals.append( Cow() )

cat_make_sound = Cat.make_sound
cow_make_sound = Cow.make_sound

for animal in animals:    
    match animal:
        case Cat():
            cat_make_sound(animal)
        case Cow():
            cow_make_sound(animal)

CPython interpreters older than 3.10 don't support match, thus alternative would be:

for animal in animals:    
    if isinstance(animal, Cat):
        cat_make_sound(animal)
    elif isinstance(animal, Cow):
        cow_make_sound(animal)

Rust

use std::any::Any;

trait CanMakeSound {
    fn make_sound(&self);
}

struct Cat {
}

impl CanMakeSound for Cat {
    fn make_sound(&self) {
        println!("miao")
    }
}
    
struct Cow {
}

impl CanMakeSound for Cow {
    fn make_sound(&self) {
        println!("mooo")
    }
}

fn main() {
    let mut animals: Vec<Box<dyn Any>> = Vec::new();
    animals.push( Box::new(Cat{}) );
    animals.push( Box::new(Cow{}) );

    for animal in animals {
        if let Some(cat) = animal.downcast_ref::<Cat>() {
            cat.make_sound();
        } else if let Some(cow) = animal.downcast_ref::<Cow>() {
            cow.make_sound();
        }
    }
}

Crystal

#![allow(unused)]
fn main() {
class Cat
  def make_sound
    puts "miao"
  end
end

class Cow
  def make_sound
    puts "mooo"
  end
end

alias Animal = Cat | Cow
alias Any = Pointer(Void)

animals = [] of Any

animals << Box(Animal).box(Cat.new)
animals << Box(Animal).box(Cow.new)

animals.each do |animal|
  unboxed = Box(Animal).unbox(animal)
  if cat = unboxed.as?(Cat)
    cat.make_sound
  elsif cow = unboxed.as?(Cow)
    cow.make_sound
  end
end
}