Interfaces in Crystal

# Interfaces are named collections of method signatures.

# Here's a basic interface for geometric shapes.
module Geometry
  abstract def area : Float64
  abstract def perim : Float64
end

# For our example we'll implement this interface on
# `Rect` and `Circle` classes.
class Rect
  include Geometry

  def initialize(@width : Float64, @height : Float64)
  end

  def area : Float64
    @width * @height
  end

  def perim : Float64
    2*@width + 2*@height
  end
end

class Circle
  include Geometry

  def initialize(@radius : Float64)
  end

  def area : Float64
    Math::PI * @radius * @radius
  end

  def perim : Float64
    2 * Math::PI * @radius
  end
end

# If a variable has an interface type, then we can call
# methods that are in the named interface. Here's a
# generic `measure` function taking advantage of this
# to work on any `Geometry`.
def measure(g : Geometry)
  puts g
  puts g.area
  puts g.perim
end

# In the main function, we create instances of `Rect` and `Circle`
r = Rect.new(width: 3, height: 4)
c = Circle.new(radius: 5)

# The `Circle` and `Rect` classes both
# implement the `Geometry` module so we can use
# instances of these classes as arguments to `measure`.
measure(r)
measure(c)

This Crystal code implements the concept of interfaces using modules. Here’s a breakdown of the translation:

  1. We define a Geometry module with abstract methods area and perim. This is equivalent to the geometry interface in the original code.

  2. We create Rect and Circle classes that include the Geometry module and implement its methods.

  3. The measure function takes a parameter of type Geometry, which allows it to work with any object that includes the Geometry module.

  4. In the main part of the program, we create instances of Rect and Circle and pass them to the measure function.

To run this program, you would save it to a file (e.g., interfaces.cr) and then use the Crystal compiler:

$ crystal interfaces.cr
{Rect(@width=3.0, @height=4.0)}
12.0
14.0
{Circle(@radius=5.0)}
78.53981633974483
31.41592653589793

This example demonstrates how Crystal implements interface-like behavior using modules, providing a way to define a set of methods that a class must implement. This allows for polymorphism, where different types can be used interchangeably as long as they implement the required methods.