From: E S Date: 2005-02-09T15:39:53+09:00 Subject: Re: Method arguments > L�hett�j�: Nash Kabbara > Aihe: 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. It depends on what you expect :) def foo(hsh) hsh[:a] = 'b' end h = {:a => 'a'} foo(h) h[:a] # => 'b' > 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 > > > > > > > > E