Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.ruby > #3515 > unrolled thread

Setting a 'reference' inside the method body

Started byPeter Szinek <peter.szinek@gmail.com>
First post2011-04-26 09:55 -0500
Last post2011-04-27 01:04 -0500
Articles 5 — 5 participants

Back to article view | Back to comp.lang.ruby


Contents

  Setting a 'reference' inside the method body Peter Szinek <peter.szinek@gmail.com> - 2011-04-26 09:55 -0500
    Re: Setting a 'reference' inside the method body Xavier Noria <fxn@hashref.com> - 2011-04-26 10:04 -0500
      Re: Setting a 'reference' inside the method body Brian Candler <b.candler@pobox.com> - 2011-04-26 10:28 -0500
        Re: Setting a 'reference' inside the method body Charles Oliver Nutter <headius@headius.com> - 2011-04-27 00:46 -0500
          Re: Setting a 'reference' inside the method body Robert Dober <robert.dober@gmail.com> - 2011-04-27 01:04 -0500

#3515 — Setting a 'reference' inside the method body

FromPeter Szinek <peter.szinek@gmail.com>
Date2011-04-26 09:55 -0500
SubjectSetting a 'reference' inside the method body
Message-ID<ce11d8adf31eab2c2a5b15b2b4337a74@ruby-forum.com>
Hey guys,

Can Ruby do this in some way:

def foo(bar)
  #DO SOMETHING with bar here resulting in baz being set to {}
end

baz = {:fluff => :ork}
foo(baz)
#baz should be {} now

I'd like to use it in a code which calls a callback, (the foo method in
this case) but the callback is called from multiple places, and only
inside foo() we know whether we want to empty the array or not... it
would be complicated to return something from foo() with the current
architecture (based on which we could empty the hash or not).


My Ruby version is JRuby 1.6 if that makes any difference.

Cheers,
Peter

-- 
Posted via http://www.ruby-forum.com/.

[toc] | [next] | [standalone]


#3516

FromXavier Noria <fxn@hashref.com>
Date2011-04-26 10:04 -0500
Message-ID<BANLkTim+1PkCGMWBqTk30M2QAtE-=wgVAA@mail.gmail.com>
In reply to#3515
On Tue, Apr 26, 2011 at 4:55 PM, Peter Szinek <peter.szinek@gmail.com> wrote:

> def foo(bar)
>  #DO SOMETHING with bar here resulting in baz being set to {}
> end
>
> baz = {:fluff => :ork}
> foo(baz)
> #baz should be {} now
>
> I'd like to use it in a code which calls a callback, (the foo method in
> this case) but the callback is called from multiple places, and only
> inside foo() we know whether we want to empty the array or not... it
> would be complicated to return something from foo() with the current
> architecture (based on which we could empty the hash or not).

You cannot change the reference stored in the caller's baz, because
Ruby has pass by value semantics. But hashes are mutable, in
particular

    baz.clear

wipes the hash, so the caller will see it empty as well.

[toc] | [prev] | [next] | [standalone]


#3517

FromBrian Candler <b.candler@pobox.com>
Date2011-04-26 10:28 -0500
Message-ID<c8ea4e436f3d64ee1cc6891975d8e04c@ruby-forum.com>
In reply to#3516
Xavier Noria wrote in post #995127:
> On Tue, Apr 26, 2011 at 4:55 PM, Peter Szinek <peter.szinek@gmail.com>
> wrote:
>
>> inside foo() we know whether we want to empty the array or not... it
>> would be complicated to return something from foo() with the current
>> architecture (based on which we could empty the hash or not).
>
> You cannot change the reference stored in the caller's baz, because
> Ruby has pass by value semantics. But hashes are mutable, in
> particular
>
>     baz.clear
>
> wipes the hash, so the caller will see it empty as well.

(bar.clear that is). Using bar.replace({}) is another option. Both of 
these mutate the Hash that was passed in.

In Ruby:

- all values are object references
- all method calls are pass-by-value
- a local variable is *not* itself an object
- you cannot take a "reference" to a local variable

Almost certainly you want to mutate the Hash being passed in, not 
attempt to modify the caller's local variable which holds the reference 
to that Hash.

That said, there is one nasty way to achieve specifically what you 
asked:

def bar(b)
  eval "baz='whoopee'", b
end

baz = {:fluff => :ork}
bar(binding)
p baz

It involves either passing a Binding (as shown), or passing a block, 
which also carries a Binding, and then evaluating code in the context of 
that Binding. Unless you're writing a debugger or something like that, 
you almost certainly don't want to do this.

-- 
Posted via http://www.ruby-forum.com/.

[toc] | [prev] | [next] | [standalone]


#3546

FromCharles Oliver Nutter <headius@headius.com>
Date2011-04-27 00:46 -0500
Message-ID<BANLkTinMn_VQGmjsbQ_nvQ7G3LRzMbne3w@mail.gmail.com>
In reply to#3517
On Tue, Apr 26, 2011 at 10:28 AM, Brian Candler <b.candler@pobox.com> wrote:
> It involves either passing a Binding (as shown), or passing a block,
> which also carries a Binding, and then evaluating code in the context of
> that Binding. Unless you're writing a debugger or something like that,
> you almost certainly don't want to do this.

FWIW, I always discourage people from using blocks as bindings,
because it defeats a number of potential optimizations. Specifically,
if blocks can be used as bindings:

* All variables in the containing scope must be made accessible
in-memory somewhere, so you can't eliminate or optimize them away.
* All bodies containing blocks must have a full Ruby execution
environment (frame, scope, etc), so you can't do frame elimination
when blocks are present.
* There's also potential for really nasty threading effects, if the
block binding is passed to another thread that mutates variables in
the containing scope.

Without this feature, I know for a fact that JRuby could optimize
blocks a lot more than it does right now, potentially making them as
fast or faster than methods. We could also reduce the overhead of
methods that contain closures, since right now we have to deoptimize
to handle the block-as-binding case.

I also believe it's a code security/visibility issue, since any method
you pass a block to can read all your local variable state. For
example...

def secure_login(password)
  with_transaction do
    .... do login ....
  end
end

..and in some transaction library that has been compromised:

def with_transaction(&block)
  stolen_password = eval "defined?(password) ? password : nil"
  email_password_to_hacker(stolen_password) if stolen_password
  ... normal transaction logic...
end

With the potential for any code to monkey-patch any other code, this
seems like a very real threat. I don't believe library code should be
able to access the calling method's state unless I make that state
available to it.

It definitely works, but I have lobbied (and continue to lobby) to remove it.

- Charlie

[toc] | [prev] | [next] | [standalone]


#3548

FromRobert Dober <robert.dober@gmail.com>
Date2011-04-27 01:04 -0500
Message-ID<BANLkTik1teEojUQU5y8EtS+64w58YALECQ@mail.gmail.com>
In reply to#3546
> <headius@headius.com> wrote:
> <snip>
>>  stolen_password = eval "defined?(password) ? password : nil"
> I guess you meant - and I corrected this for newbies,
>
>                                      eval( "defined?(password) ?
> password : nil", block.binding)
>
> but for the rest, although not of much help to you, I feel your pain.
>
> Cheers
> Robert

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.ruby


csiph-web