-
Notifications
You must be signed in to change notification settings - Fork 61
Invariant and :inspect
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