-
21
AUG
2014Guard Clauses, Rust Style
When I'm programming in Ruby, I will often use guard clauses to prevent undesirable scenarios. For example, let's say I'm building a simple
Stack
:class Stack def initialize @numbers = [ ] end def push(number) @numbers.push(number) end def peek fail "Stack underflow" if @numbers.empty? @numbers.last end end stack = Stack.new ARGV.each do |number| stack.push(number.to_f) end p stack.peek
If I only want to work with numbers everywhere, I add a line like the call to
fail()
above. This prevents anil
from being returned frompeek()
, ruining my expectation that I will have numbers everywhere.When I first started playing with Rust, I wanted to write code the same way:
use std::os; struct Stack { numbers: Vec<f64> } impl Stack { fn new() -> Stack { Stack{numbers: vec![]} } fn push(&mut self, number: f64) { self.numbers.push(number); } fn peek(&self) -> f64 { if self.numbers.is_empty() { fail!("Stack underflow"); } self.numbers.last() } } fn main() { let mut stack = Stack::new(); for number in os::args().tail().iter() { stack.push(from_str(number.as_slice()).expect("Not a number")); } println!("{}", stack.peek()); }
-
26
JUN
2008Summoning Error Classes As Needed
In the past, I've written a lot of code like this:
class SomeThing class SomeError < RuntimeError; end class AnotherError < RuntimeError; end class YetAnotherError < RuntimeError; end # some methods that can raise the above errors... end
I have a new strategy I've been using for code like this and it has really been working out well. Here is how I do the same thing today:
class SmarterThing def self.const_missing(error_name) # :nodoc: if error_name.to_s =~ /Error\z/ const_set(error_name, Class.new(RuntimeError)) else super end end # error raising methods here... end
Let's discuss how this works. The
const_missing()
method is a hook in Ruby, much like the belovedmethod_missing()
. Note thatconst_missing()
is a class method though, instead of an instance method. When a constant is used and Ruby can't find it, a call to the hook will be triggered.In this version, I just check to see if the constant name ends in
Error
. If it does, I summon anException
subclass on the fly. Other calls to this hook are forwarded on to Ruby's default error raising implementation viasuper
.