On Wednesday 05 October 2005 18:41, waterbowl / gmail.com wrote:
> Is it possible to write a method in Ruby that acts like pop does in
> Lisp? Array#shift is an obvious candidate but there's a difference. For
> example:
>
> Ruby:
>
> irb(main):001:0> x = [[:a, :b], :c]
> => [[:a, :b], :c]
> irb(main):002:0> y = x.first
> => [:a, :b]
> irb(main):003:0> y.shift
> => :a
> irb(main):004:0> y
> => [:b]
> irb(main):005:0> x
> => [[:b], :c]
> irb(main):006:0>
>
> Lisp:
>
> [2]> (setq x '((a b) c))
> ((A B) C)
> [3]> (setq y (car x))
> (A B)
> [4]> (pop y)
> A
> [5]> y
> (B)
> [6]> x
> ((A B) C)
>
> y.shift causes x to be modified whereas Lisp's (pop y) does not modify
> x.

You could force a deep copy:

y = Marshal.load(Marshal.dump(x.first))

> If Ruby had macros we could use them to define pop. Given that it does
> not, is there some other way to define a method to do this?

It's getting modified because both are just references to the original. 
(shallow copy)

irb(main):001:0> x = [[:a, :b], :c]
=> [[:a, :b], :c]
irb(main):002:0> y = Marshal.load(Marshal.dump(x.first))
=> [:a, :b]
irb(main):003:0> y.shift
=> :a
irb(main):004:0> y
=> [:b]
irb(main):005:0> x
=> [[:a, :b], :c]