From: Nash Kabbara Date: 2005-02-09T14:15:08+09:00 Subject: Re: Method arguments Hmmm. Is it safe to pass a Hash and modify it in a function then use it? for example: a = Hash.new modify(a) do_something_useful(a) after reading the response below, it's making me think how hashs behave and whether it's safe to do the above. Thanks Mikael Brockman wrote: > "Tookelso" writes: > > >>Hello, >> >>Sorry for asking this basic question, but I couldn't find it in the >>PickAxe book. >> >>When you pass an argument to a method, is it passed by reference, or by >>value? > > > By value. But remember that the value of a variable is always a > reference! (That's not *technically* true for Fixnums, but since > Fixnums are entirely immutable, the abstraction holds up.) > > >>Or, does it depend on the object's type? >> >>For example, in the simple script below, the program outputs "0". >>#----------------------------------- >>def test(c_count) >>c_count = c_count + 1 >>end >># begin program >>c_count = 0 >>test(c_count) >>puts c_count >>#----------------------------------- >>I realize that for simple things, it's better to return a value from >>the method, but I would like to know *why* it's not modifying my >>"c_count" value. > > > (In this explanation, I'm ignoring the fact that Fixnums are special -- > that fact is a pure implementation detail. Just an optimization.) > > When you initialize c_count, the 0 is evaluated first. Ruby will > allocate space for a Fixnum. Let's say it allocates some bytes over at > the memory location 0xCAFEBABE. It copies 0x0000, or whatever the > machine representation of 0 is, to 0xCAFEBABE. > > Then it creates a new instance variable. Sets its value to 0xCAFEBABE. > > When you call ``test'', c_count is passed by value, as always. The > value passed is 0xCAFEBABE. > > Now, what happens when you receive an argument is this: a new instance > variable is created. This c_count has nothing in common with the other > c_count -- except that they happen to share values. Of course, you > could name the test parameter ``snuggly_taco'', and the program would > work the same. > > When you assign to snuggly_taco, the only thing that happens is that the > value of snuggly_taco is changed, to the address of that new number > you're making. This affects neither 0xCAFEBABE nor c_count. > > If you really want to change the value of an instance variable from > another function -- bad luck. You can't. > > Actually, I lied. You can do it. If you use Florian Gro�'s > binding_of_caller and eval. > > But that's an extremely obscure hack. Avoid it! The clean solution is, > as always, adding another layer of indirection. Make it so that by > setting something you actually can change -- like an instance variable > -- you change the effective value. > > | class Box > | attr_accessor :value > | > | def initialize value=nil > | @value = value > | end > | end > | > | def test c_count > | c_count.value = c_count.value + 1 > | end > | > | c_count = Box.new 0 > | test c_count > | puts c_count > > This box is perfectly analogous with a C pointer (except, of course, > that you can't do pointer arithmetic). Instead of ``*foo'', we write > ``foo.value''. > > (By the way, is there a class like this in the stdlib?) > > mikael > > > >