Skip to content

Invariant and :inspect

Jim Weirich edited this page May 24, 2013 · 2 revisions

Small Step Semantics

In Tom Stuart's book Understanding Computation, he uses expression trees to illustrate the different ways of specifying semantics.

Here are a few some examples of Number and Variable expressions:

number = Number.new(5)  
number.to_s             # => "5"
number.inspect          # => "«5»"

var = Variable.new(:x)
var.to_s                # => "x"
var.inspect             # => "«x»"

Each expression returns a text representation of itself using the :to_s method. Also, the inspect method returns the same string, but with the «guillemets» surrounding the text. This makes it easy to visually identify the results as Expressions and not regular Ruby objects.

Here is a short specification for :to_s and :inspect on various Expression types.

describe "Expressions" do
  describe Number do
    Given(:expr) { Number.new(5) }
    Then { expr.to_s == "5" }
    Then { expr.inspect == "«5»" }
  end

  describe Bool do
    Given(:expr) { Bool.new(true) }
    Then { expr.to_s == "true" }
    Then { expr.inspect == "«true»" }
  end

  describe Variable do
    Given(:expr) { Variable.new(:x) }
    Then { expr.to_s == "x" }
    Then { expr.inspect == "«x»" }
  end
end

This is a good spec (as far as :to_s and :inspect are concerned), but we can make the spec a bit stronger. For every expression, the inspect string will always be the same as the :to_s string, but surrounded with guillemets. Let's make that explicit in the spec.

describe "Expressions" do
  Invariant { expr.inspect == #{self}»" }

  describe Number do
    Given(:expr) { Number.new(5) }
    Then { expr.to_s == "5" }
  end

  describe Bool do
    Given(:expr) { Bool.new(true) }
    Then { expr.to_s == "true" }
  end

  describe Variable do
    Given(:expr) { Variable.new(:x) }
    Then { expr.to_s == "x" }
  end
end

This shortens the spec a bit, but that's not what's important. What is important is that the spec now says something about all expressions. Every expression must have a conforming :inspect method. If we add a new expression type, and forget to say anything about the :inspect method, the invariant will automatically remind us that we need to implement it correctly.

This is the power of invariants, the ability to specify something in a broader context than just the current object.


Go back to Semantic Expression Examples