Interfaces in Nim

Our first example demonstrates interfaces, which are named collections of method signatures.

import math

# Here's a basic interface for geometric shapes.
type
  Geometry = concept
    proc area(self: Self): float
    proc perim(self: Self): float

# For our example we'll implement this interface on
# `Rect` and `Circle` types.
type
  Rect = object
    width, height: float

  Circle = object
    radius: float

# To implement an interface in Nim, we just need to
# implement all the methods in the interface. Here we
# implement `Geometry` on `Rect`s.
proc area(r: Rect): float =
  r.width * r.height

proc perim(r: Rect): float =
  2*r.width + 2*r.height

# The implementation for `Circle`s.
proc area(c: Circle): float =
  math.PI * c.radius * c.radius

proc perim(c: Circle): float =
  2 * math.PI * c.radius

# 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`.
proc measure(g: Geometry) =
  echo g
  echo g.area()
  echo g.perim()

# Main function
proc main() =
  let r = Rect(width: 3, height: 4)
  let c = Circle(radius: 5)

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

main()

To run the program, save it as interfaces.nim and use the Nim compiler:

$ nim c -r interfaces.nim
{width: 3.0, height: 4.0}
12.0
14.0
{radius: 5.0}
78.53981633974483
31.41592653589793

In this Nim example, we’ve implemented the concept of interfaces using Nim’s concept feature. The Geometry concept defines the required methods for any type that wants to be considered a geometric shape.

We then define Rect and Circle types and implement the required methods for each. The measure function demonstrates how we can use any type that satisfies the Geometry concept.

Nim’s approach to interfaces (concepts) is more flexible than Go’s, as it uses structural typing rather than nominal typing. This means that types don’t need to explicitly declare that they implement an interface; they just need to have the required methods.

To learn more about Nim’s concepts and how they compare to interfaces in other languages, check out the Nim documentation on concepts.