One big difference between Perl and Ruby is that Ruby has no lexical variables. This confuses me when programming Ruby, because I’m used to thinking ifwill create a new scope. It doesn’t. Variables defined inside if will be available outside, because they belong to the method scope.

For example, in Ruby you can do this:

def foo
  if true
    x = 2
  end
  puts x
end

foo

This prints 2.

However, in Perl:

sub foo {
  if (1) {
    my $x = 2;
  }
  print $x;
}
foo();

You get the warning Use of uninitialized value $x in print at lexical_test.pl line 5..

This is OK. If anything, the Ruby version looks more convenient. But I prefer my variables to have as small a scope as possible, because it avoids mistakes like this:

def foo
  x = 1
  if true
    x = 2
  end
  puts x
end

foo # prints 2. what have you done to my x?

In Perl, we’d write it like this:

sub foo {
  my $x = 1;
  if (1) {
    my $x = 2;
  }
  print $x;
}
foo(); # prints 1

So how to avoid it in Ruby? Well, you could create a new method, or you can create a new block (eg. with a lambda or proc). This feels a bit weird though. Maybe a more Rubyish way is to use Object#tap, like so:

def foo
  x = 1
  2.tap do |x|
    puts x # 2
  end
  puts x # 1
end

That gets a bit unwieldy if you have multiple variables. But then, if you need more than 1 variable with the same name in your method, then it’s probably a sign that you should write a new method…

Variable scope in Ruby

Post navigation


Leave a Reply

Your email address will not be published. Required fields are marked *