Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Three Examples of Polymorphism under the Reign of Sorbet
# typed: true
require 'sorbet-runtime'
# Example 1: Polymorphism by Classical Inheritance
class Fruit; def eat; puts('ate fruit: ' + self.class.name.to_s); end; end
class Apple < Fruit; def eat; puts 'ate apple'; end; end
class Banana < Fruit; end
class Eater
extend T::Sig
sig { params(fruit: Fruit).void } # it will also accept Apple or Banana
def eat(fruit)
fruit.eat
end
end
eater = Eater.new
[Apple, Banana, Fruit].each { |klass| eater.eat(klass.new) }
# Example 2: Polymorphism by Multiple Inheritance
# A bit less obvious than the above, but Sorbet handles it well.
module PickANumber
extend T::Sig
sig { returns(Integer) }
def pick; 7; end
end
module PickAColor
extend T::Sig
sig { returns(String) }
def pick; 'red'; end
end
class Picker
include PickAColor
include PickANumber
end
should_be_int = Picker.new.pick
T.let(should_be_int, Integer) # try reversing the `include`s above
puts should_be_int
# Example 3: Polymorphism by Duck-typing, with Union-Type signature
# Can we still call it duck-typing, if we have to painstakingly define
# this union type?
class MerganserDuck; def say; 'quack'; end; end
class MallardDuck; def say; 'quack'; end; end
class Carnivore
extend T::Sig
sig { params(duck: T.any(MerganserDuck, MallardDuck)).void }
def eat(duck)
puts format('%s says the %s', duck.say, duck.class.name)
end
end
eater = Carnivore.new
[MerganserDuck, MallardDuck].each { |klass| eater.eat(klass.new) }
# bundle exec srb tc
# No errors! Great job.
# bundle exec ruby lib/sorbet_polymorphism.rb
# ate apple
# ate fruit: Banana
# ate fruit: Fruit
# 7
# quack says the MerganserDuck
# quack says the MallardDuck
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment