I'm learning Ruby (2.0) and this just surprised me:
s = "1234"
s =~ /\d+/
$& ==> "1234" # as expected, $& contains the matched string
$&.slice!(-2..-1) # should mutate string
$& ==> "1234" # what?
s.slice(-2..-1)
s ==> "12" # as expected
The slice!
method is supposed to mutate the string. Other mutator methods behave in the same way. My questions: why is this not throwing an error, which is what I expect when a function can't do what it says it will do? Is this documented somewhere? Is there a rationale?
Update
So, I see that $&
is not acting like a global variable. Each reference to it gives a new object, as if it's really a no-arg function:
irb> $foo = "1234"
=> "1234"
irb> $foo.object_id
=> 70205012205980
irb> $foo.object_id
=> 70205012205980 # the same
irb> $&.object_id
=> 70205003531300
irb> $&.object_id
=> 70205011619040 # different object
So... my question becomes: is this simply "magic" from the interpreter, or is $&
actually a no-arg function just as I could define in Ruby using def ... end
? And, how could I tell the difference? In Python I could refer to a function foo
by just using it's name:
>>> foo
<function foo at 0x10d3117d0>
Is there way to do this in Ruby? I could then look at what $& "really" is (if it's not magic).
Global variables should be used sparingly. They are dangerous because they can be written to from anywhere. Overuse of globals can make isolating bugs difficult; it also tends to indicate that the design of a program has not been carefully thought out.
Assignments to global variables can be made from anywhere in the program. Global variables are always prefixed with a dollar sign. It is necessary to define a global variable to have a variable that is available across classes. When a global variable is uninitialized, it has no value by default and its use is nil.
The Ruby C API includes hooked and virtual variables. From README.EXT:
You can defined hooked variables. The accessor functions (getter and setter) are called on access to the hooked variables.
void rb_define_hooked_variable(const char *name, VALUE *var, VALUE (*getter)(), void (*setter)())
If you need to supply either setter or getter, just supply 0 for the hook you don't need. If both hooks are 0, rb_define_hooked_variable() works just like rb_define_variable().
The prototypes of the getter and setter functions are as follows:
VALUE (*getter)(ID id, VALUE *var); void (*setter)(VALUE val, ID id, VALUE *var);
Also you can define a Ruby global variable without a corresponding C variable. The value of the variable will be set/get only by hooks.
void rb_define_virtual_variable(const char *name, VALUE (*getter)(), void (*setter)())
The prototypes of the getter and setter functions are as follows:
VALUE (*getter)(ID id); void (*setter)(VALUE val, ID id);
$&
is an example of a virtual variable, it is defined in re.c
, the corresponding getter is last_match_getter
and there is no assocoated setter.
So $&
is, in a sense, a no-arg function, only it is implemented in C. You can’t (as far as I’m aware) define your own virtual globals like this in pure Ruby (you can if you create your own C extension).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With