No one: It’s so sad that there are no pointers in Ruby.
Me: Did you know that you can trivially implement pointers, though?
class Obj < Struct.new(:name, :shortcode, keyword_init: true)
def ~
Pointer.new(object_id: object_id)
end
end
class Pointer < Struct.new(:object_id, keyword_init: true)
def +@
ObjectSpace._id2ref(object_id)
end
end
You can then reference and dereference using a relatively simple semantics, using ~x
to create a Pointer from an Obj
, and +y
to dereference a Pointer
.
Here, ~x
(tilde) is similar to C’s &x
, “get the address of x
”.
Meanwhile +y
is similar to C’s *y
, “dereference the pointer stored at y
”.
Usage
irb(main):012> o=Obj.new(name: "A")
=> #<struct Obj name="A", shortcode=nil>
irb(main):013> p = ~o
=> #<struct Pointer object_id=29020>
irb(main):014> +p
=> #<struct Obj name="A", shortcode=nil>
What… is this
Well, they aren’t pointers in the C sense, exactly. But you can happily use the Ruby VM object IDs for the same concept.
You just have to use .object_id
to fetch the Object ID, and ObjectSpace._id2ref to dereference. And overload some unary operators to provide … some kind of semantics.
I wish I could implement this with *
and &
, for visual similarity to the C operators, but Ruby doesn’t support unary *
or &
.
Why???
People say you can’t do pass by reference in Ruby; you have to do “pass by object reference” or “pass reference by value”.
Discussion:
- https://robertheaton.com/2014/07/22/is-ruby-pass-by-reference-or-pass-by-value/
- https://stackoverflow.com/questions/1872110/is-ruby-pass-by-reference-or-by-value
Well, now you can do pass by reference in your Ruby method calls too, if you really want to :)
def welcome(obj_pointer)
puts "Hello, #{(+obj_pointer).name}"
end
o=Obj.new(name: "Ambassador Spock")
welcome(~o)
=> "Hello, Ambassador Spock"
Disclaimer
Please don’t try C-style pointer arithmetic with these pointers.
Not ready for production usage yet.