Forum: Ruby Help with a ruby idiom

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Tim W. (Guest)
on 2006-12-23 18:02
From the O'Reilly Cookbook there is code that keeps call functions in a
hash as a subscriber/listener type pattern.  What I don't understand (or
I don't understand how it works is the line:
(@EventDispatcher_listeners[event] ||= []) << callback


module EventDispatcher
    def setup_listeners
    @EventDispatcher_listeners = {}
  end

  def subscribe(event, &callback)
    (@EventDispatcher_listeners[event] ||= []) << callback
  end

  protected
  def notify(event, *args)
    if @EventDispatcher_listeners[event]
      @EventDispatcher_listeners[event].each do |m|
        m.call(*args) if m.respond_to? :call
      end
    end
    return nil
  end
end
Vincent F. (Guest)
on 2006-12-23 18:09
(Received via mailing list)
Tim W. wrote:
>>From the O'Reilly Cookbook there is code that keeps call functions in a
> hash as a subscriber/listener type pattern.  What I don't understand (or
> I don't understand how it works is the line:
> (@EventDispatcher_listeners[event] ||= []) << callback

  You can split it into two, which will make it more clear:

@EventDispatcher_listeners[event]  ||= [] # makes it an empty array if
it doesn't exist
@EventDispatcher_listeners[event] << callback # and pushes the callback
on top of it

  I agree that this kind of compact notation is very hand but slightly
indecipherable... Cheers,

	Vince
Robert K. (Guest)
on 2006-12-23 18:17
(Received via mailing list)
On 23.12.2006 17:02, Tim W. wrote:
> From the O'Reilly Cookbook there is code that keeps call functions in a
> hash as a subscriber/listener type pattern.  What I don't understand (or
> I don't understand how it works is the line:
> (@EventDispatcher_listeners[event] ||= []) << callback

a ||= b

is equivalent to

a || (a = b)

IOW

a = b unless a

IOW

unless a
   a = b
end

IOW

"eval b and assign the result to a if a is nil or false".

In this case, since a Hash is also involved the lengthy form looks like
this:

unless @EventDispatcher_listeners[event]
   @EventDispatcher_listeners[event] = []
end
@EventDispatcher_listeners[event] << callback

I hope you admit that ||= is much more concise and elegant. :-)

HTH

	robert
unknown (Guest)
on 2006-12-23 18:17
(Received via mailing list)
Tim W. <removed_email_address@domain.invalid> wrote:

> What I don't understand (or
> I don't understand how it works is the line:
> (@EventDispatcher_listeners[event] ||= []) << callback

Here is a verbose a description:

@EventDispatcher_listeners is a hash.

Look up the entry in that hash, the entry named "event".

But perhaps there is no such entry. (The entry is reported as nil.) In
that case, create one, and set it to be an empty array.

Now you have an array - either the array that was already the "event"
entry in the hash, or the empty array that is now the "event" entry in
the hash. Append "callback" as the last item of that array.

m.
Tim W. (Guest)
on 2006-12-23 18:38
Robert K. wrote:
> I hope you admit that ||= is much more concise and elegant. :-)
>
> HTH
>
>   robert

Thanks to all, I think I understand now. And yes, it is QUITE concise!
-tim
unknown (Guest)
on 2006-12-23 20:55
(Received via mailing list)
Hi --

On Sun, 24 Dec 2006, Robert K. wrote:

> a || (a = b)
>
> IOW
>
> "eval b and assign the result to a if a is nil or false".

It is indeed functionally equivalent to those, though all of them
would blow up :-)  I believe the reason a ||= b doesn't blow up is
that it's expanded to:

   a = a || b

and when Ruby sees "a =" it allocates a local variable called a -- so
that means that the rhs will not raise an error, which it otherwise
would.

This doesn't add anything to what the idiom does, but I think it's an
interesting semantic detail.


David
Devin M. (Guest)
on 2006-12-23 21:03
(Received via mailing list)
removed_email_address@domain.invalid wrote:
> It is indeed functionally equivalent to those, though all of them
> would blow up :-)
Not all of them.
   a = b unless a
works, for the same reason you described
   a = a || b
working. Here, the "a =" is parsed before the "unless a" is evaluated.

But yes, a ||= b maps more closely to a = a || b, just like a += b maps
to a = a + b.

Devin
(Though, I tend to use the ||= idiom most often with instance/class
variables, who don't raise NameError like locals do.)
unknown (Guest)
on 2006-12-23 21:05
(Received via mailing list)
Hi --

On Sun, 24 Dec 2006, Devin M. wrote:

> removed_email_address@domain.invalid wrote:
>> It is indeed functionally equivalent to those, though all of them
>> would blow up :-)
> Not all of them.
>  a = b unless a
> works, for the same reason you described
>  a = a || b
> working. Here, the "a =" is parsed before the "unless a" is evaluated.

Whoops, right; thanks.


David
M. Edward (Ed) Borasky (Guest)
on 2006-12-23 21:31
(Received via mailing list)
removed_email_address@domain.invalid wrote:
>>  a = a || b
>> working. Here, the "a =" is parsed before the "unless a" is evaluated.
>
> Whoops, right; thanks.
>
>
> David
>
Might I be a curmudgeon on this Christmas eve eve? I say that any idiom
that's confusing enough that its semantics isn't *instantly*
recognizable to an old FORTRAN programmer like my curmudgeonly self
probably doesn't contribute to code readability. :) So I would write
this out in "longhand" and not let the parser have an opportunity to
confuse me. So my "idiom" would be

if (!a) then
  a = b
end

Or, since my curmudgeonly self has managed to learn Perl, :)

a = b if !a



--
M. Edward (Ed) Borasky, FBG, AB, PTA, PGS, MS, MNLP, NST, ACMC(P)
http://borasky-research.blogspot.com/

If God had meant for carrots to be eaten cooked, He would have given
rabbits fire.
unknown (Guest)
on 2006-12-23 22:23
(Received via mailing list)
Hi --

On Sun, 24 Dec 2006, M. Edward (Ed) Borasky wrote:

> Might I be a curmudgeon on this Christmas eve eve? I say that any idiom
> that's confusing enough that its semantics isn't *instantly* recognizable to
> an old FORTRAN programmer like my curmudgeonly self probably doesn't
> contribute to code readability. :) So I would write this out in "longhand"
> and not let the parser have an opportunity to confuse me. So my "idiom" would
> be
>
> if (!a) then
> a = b
> end

That won't work though:

ruby -e 'if (!a) then a = b end'
-e:1: undefined local variable or method `a' for main:Object
(NameError)

because of the forward reference to a.

> Or, since my curmudgeonly self has managed to learn Perl, :)
>
> a = b if !a

||= is used a lot in Perl, too :-)  I guess I'm just used to it; my
eye takes it in pretty readily.


David
William J. (Guest)
on 2006-12-23 22:35
(Received via mailing list)
M. Edward (Ed) Borasky wrote:
> >> works, for the same reason you described
> recognizable to an old FORTRAN programmer like my curmudgeonly self
> a = b if !a
a = b  unless a
M. Edward (Ed) Borasky (Guest)
on 2006-12-23 23:03
(Received via mailing list)
removed_email_address@domain.invalid wrote:
>>
> because of the forward reference to a.
>
Does this Perl-ism work?

if (!defined(a)) then
  a = b
end



--
M. Edward (Ed) Borasky, FBG, AB, PTA, PGS, MS, MNLP, NST, ACMC(P)
http://borasky-research.blogspot.com/

If God had meant for carrots to be eaten cooked, He would have given
rabbits fire.
unknown (Guest)
on 2006-12-23 23:19
(Received via mailing list)
Hi --

On Sun, 24 Dec 2006, M. Edward (Ed) Borasky wrote:

>>> would be
>>
>> David
>>
> Does this Perl-ism work?
>
> if (!defined(a)) then
> a = b
> end

Yes, but in Ruby it's defined? rather than defined.


David
unknown (Guest)
on 2006-12-24 04:54
(Received via mailing list)
On Dec 23, 2006, at 3:35 PM, William J. wrote:
>> Might I be a curmudgeon on this Christmas eve eve? I say that any
>> idiom
>> that's confusing enough that its semantics isn't *instantly*
>> recognizable to an old FORTRAN programmer like my curmudgeonly self
>> probably doesn't contribute to code readability. :)

Isn't an idiom by definition somewhat unique to its cultural/language
context? If an expression is instantly recognizable by non-native
speakers of the language then it isn't an idiom at all.

Gary W.
unknown (Guest)
on 2006-12-24 05:56
(Received via mailing list)
Quoting removed_email_address@domain.invalid:

> speakers of the language then it isn't an idiom at all.
>
> Gary W.

Uh ... OK ... I'll be the curmudgeon and you can be the pedant. :)

Seriously though, you're right. As David Black pointed out, it's more or
less
inherited from Perl, as is "unless". I find "unless" difficult to read
in many
circumstances, although it does seem natural in this one:

a = b unless defined?(a)

the missing word "already" gets filled in by my mind.

a ||= b

on the other hand, doesn't read as easily to me.
Robert K. (Guest)
on 2006-12-24 12:01
(Received via mailing list)
On 23.12.2006 19:55, removed_email_address@domain.invalid wrote:
>> a ||= b
>>
> that it's expanded to:
>
>   a = a || b
>
> and when Ruby sees "a =" it allocates a local variable called a -- so
> that means that the rhs will not raise an error, which it otherwise
> would.
>
> This doesn't add anything to what the idiom does, but I think it's an
> interesting semantic detail.

Absolutely!  I had this slightly nagging feeling that I had the first
variant wrong, and indeed

$ ruby -e 'a || (a=1); p a'
-e:1: undefined local variable or method `a' for main:Object (NameError)

Thanks for the correction!

	robert
David V. (Guest)
on 2006-12-25 18:57
(Received via mailing list)
removed_email_address@domain.invalid wrote:
>> Or, since my curmudgeonly self has managed to learn Perl, :)
>>
>> a = b if !a
>
> ||= is used a lot in Perl, too :-)  I guess I'm just used to it; my
> eye takes it in pretty readily.
>

With no Perl background whatsoever, and a chronic dislike of things
terse / golfy, I'll admit to using and liking ||=. Mostly because it
maps to a single simple concept - I don't even begin to read it as
"assign b to a *if* a doesn't exist", I mentally parse it as "the lazy
initialisation operator" as a unit.

David V.
Wayne V. (Guest)
on 2006-12-25 19:58
(Received via mailing list)
Hi Devin,

On 12/23/06, Devin M. <removed_email_address@domain.invalid> wrote:
> (Though, I tend to use the ||= idiom most often with instance/class
> variables, who don't raise NameError like locals do.)

Not to be picky, but class variables do raise NameError:

C:\>ruby -e "puts @@a"
-e:1: uninitialized class variable @@a in Object (NameError)

C:\>ruby -v
ruby 1.8.2 (2004-12-25) [i386-mswin32]

Personally, the way I remember this is that if there's an even
number of prefix characters before the variable name
(like a or @@a) it raises NameError, but if there's an odd
number (like @a or $a), it doesn't.

Merry Christmas!

Wayne

---

Wayne V.
No Bugs Software
Ruby, C# and Erlang Agile Contract Programming in Silicon Valley
This topic is locked and can not be replied to.