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 if
will 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…