Help convert a Perl user to the Ruby Way

Hi all.

I've been working on some Ruby projects using the Rails framework

and getting on well, however recently I’ve started on some projects
using Ruby alone and have run into some issues as the task gets a
little more complicated.

One particular script is giving me trouble and I suspect it is due

to my Perly ways. Below is a pastebin of the code. As some I’m sure
can tell, it is an rbot plugin that right now doesn’t do a whole lot.

http://pastebin.com/822611

The highlighted line is flagging up the error:

TypeError: no implicit conversion from nil to integer

on line 18 (highlighted).

Now this is looking to me like a variable instantiation issue which

brings us back to Perl. In Perl that line would be perfectly legal
(though some would debate its elegance) and hashes and arrays would
be created as and when required.

I'm willing to accept that this may not be the best way to do things

in Ruby, thus I come to you to ask for a quick rundown on best
practices in these situations.

I've played around with default procs and the like in the

initialisation routine to no avail. There is an implicit dump
somewhere which causes problems. What would be the best way to deal
with this type of thing?

Many thanks,
Seb

Sebastian Reid wrote:

(though some would debate its elegance) and hashes and arrays would be
created as and when required.

In Ruby, only instance variables are autovivified to nil, and that by
itself is a behaviour that gets on my nerves (typo-prone).

From the code it looks @registry should be an object (maybe use a
Struct) instead of a Hash, and you should preinitialise its contents to
empty arrays and whatnot in its initialize method.

I'm willing to accept that this may not be the best way to do things

in Ruby, thus I come to you to ask for a quick rundown on best practices
in these situations.

I've played around with default procs and the like in the

initialisation routine to no avail.

Using blocks to initialize hashes / arrays is fine when not nested,
otherwise things get messy. Clean up your data structure initialisation
to be explicit?

David V.

On Nov 12, 2006, at 11:18 AM, David V. wrote:

In Ruby, only instance variables are autovivified to nil, and that by
itself is a behaviour that gets on my nerves (typo-prone).

This shouldn’t be an issue, if you turn on warnings:

$ ruby warning.rb
warning.rb:4: warning: instance variable @brand_new not initialized
nil
$ cat warning.rb
#!/usr/bin/env ruby -w

use an unassigned instance variable

p @brand_new

END

James Edward G. II

@registry unfortunately is not within my command, though yes I did
consider using objects for its contents. I’d rather use simpler
(though nested) structures first if I can.

The problem with being explicit when initialising the nested
structures is that they’re going to be pretty dynamic throughout, not
to mention the structure itself being changed as I go along.

That said, how would I go about initialising a hash in a hash value
that doesn’t exist yet and won’t until runtime? Unfortunately this
is something I’ve gotten well used to not needing to know these days.

Hi –

On Mon, 13 Nov 2006, Sebastian Reid wrote:

some would debate its elegance) and hashes and arrays would be created as and
when required.

In Ruby that won’t work (as you’ve seen), specifically because [] is a
method. When you do:

x[“y”]

you’re really doing:

x.

Arrays and hashes have a [] method, but so can any object; so the
presence of [] doesn’t narrow down the field.

I’m willing to accept that this may not be the best way to do things
in Ruby, thus I come to you to ask for a quick rundown on best practices in
these situations.

I’ve played around with default procs and the like in the
initialisation routine to no avail. There is an implicit dump somewhere
which causes problems. What would be the best way to deal with this type of
thing?

You’d probably be likely to see @registry initialized in the
initialize method, and then its elements initialized conditionally
along the way:

(@registry[“content”] ||= []).push(m.message)

You can certainly economize on this if you do:

@registry = Hash.new {|h,k| h[k] = [] }

though this approach might be less slick as you get into deeper
nesting.

You might want to encapsulate the behavior in a class or module, and
even perhaps have a class representing @registry[“context”].

David

On 11/12/06, David V. [email protected] wrote:

to my Perly ways. Below is a pastebin of the code. As some I’m sure
Now this is looking to me like a variable instantiation issue which
brings us back to Perl. In Perl that line would be perfectly legal
(though some would debate its elegance) and hashes and arrays would be
created as and when required.

In Ruby, only instance variables are autovivified to nil, and that by
itself is a behaviour that gets on my nerves (typo-prone).

agreed but see JEGII remark about warnings

From the code it looks @registry should be an object (maybe use a

Struct) instead of a Hash, and you should preinitialise its contents to
empty arrays and whatnot in its initialize method.

501/2 > ruby -e ‘puts Array.new[nil]’
-e:1:in `[]': no implicit conversion from nil to integer (TypeError)
from -e:1
Given that I rather think that
(a) @registry[“memory”] is referencing an Array object
and
(b) @registry[“context”][1] evaluates to nil

That was the question OP, or was it not?
Now if you really want to shoot yourself into your leg here is the gun:

class GunArray < Array
def [] *args, &block
super(*args,&block) rescue nil end
end
end

you could also monkeypatch Array but I am too lazy to look if its
method_alias or alias_method :wink:

to be explicit?
That is definitely my advice too, but I am less strict :wink:

David V.

Cheers
Robert


The reasonable man adapts himself to the world; the unreasonable one
persists in trying to adapt the world to himself. Therefore all progress
depends on the unreasonable man.

  • George Bernard Shaw

Sebastian Reid wrote:

@registry unfortunately is not within my command, though yes I did
consider using objects for its contents. I’d rather use simpler
(though nested) structures first if I can.

The problem with being explicit when initialising the nested
structures is that they’re going to be pretty dynamic throughout, not
to mention the structure itself being changed as I go along.

That said, how would I go about initialising a hash in a hash value
that doesn’t exist yet and won’t until runtime?

Let’s say we have an instance variable named “hash” that we are not sure
has
been initialized at runtime, and we want to create a new hash where
there
is none, but only then. Add this line:

hash ||= {}

Means “if ‘hash’ is a hash, do nothing, otherwise create a hash”.

On 12 Nov 2006, at 17:37, [email protected] wrote:

x[“y”]

best practices in these situations.
(@registry[“content”] ||= []).push(m.message)

David

I think we actually tried @registry = Hash.new {|h,k| h[k] = [] }

which was where the problem with the dump came in.

Desperately trying not to turn this into a set of classes since it

should be fairly simple otherwise, but I can see it drifting that way.

On Nov 12, 2006, at 2:40 PM, Paul L. wrote:

Let’s say we have an instance variable named “hash” that we are not
sure has
been initialized at runtime, and we want to create a new hash where
there
is none, but only then. Add this line:

hash ||= {}

Means “if ‘hash’ is a hash, do nothing, otherwise create a hash”.

Strictly speaking, doesn’t it mean “if ‘hash’ is nil (or false),
assign to a newly created empty hash”? You’re not testing whether
it’s actually a hash already. Also, maybe it’s worth reminding the
OP that an empty hash is not treated as ‘false’ in a logical
expression in Ruby, as it would be in Perl. So, if you were to
repeatedly evaluate

 hash ||= {}

you’d only create a new Hash the first time. In Perl, on the other
hand, repeatedly evaluating the similar expression

 $hashref ||= {}

would create and assign a new hash repeatedly, until some hash
element was assigned.

Tom

On Nov 12, 2006, at 3:22 PM, Xavier N. wrote:

you’d only create a new Hash the first time. In Perl, on the
$ perl -wle ‘do {$h ||= {}; print $h} for 1…3’
HASH(0x1800e8c)
HASH(0x1800e8c)
HASH(0x1800e8c)

Good point. I confused the ref with the hash. I’ll shut up again,
now…

Tom

Tom P. wrote:

Add this line:

hash ||= {}

Means “if ‘hash’ is a hash, do nothing, otherwise create a hash”.

Strictly speaking, doesn’t it mean “if ‘hash’ is nil (or false),
assign to a newly created empty hash”?

Yes, and a good clarification. I was addressing the intent of the line,
not
its true basis.

On Nov 12, 2006, at 8:58 PM, Tom P. wrote:

hand, repeatedly evaluating the similar expression

$hashref ||= {}

would create and assign a new hash repeatedly, until some hash
element was assigned.

Well, in that case there’s only one assignment indeed, because a
hashref is true in Perl as well:

$ perl -wle ‘do {$h ||= {}; print $h} for 1…3’
HASH(0x1800e8c)
HASH(0x1800e8c)
HASH(0x1800e8c)

– fxn

Paul L. wrote:
[snip]

hash ||= {}

Means “if ‘hash’ is a hash, do nothing, otherwise create a hash”.

To be precise, that is not what that means. It means:
hash = hash || {}

which can be interpreted as:
“If the ‘hash’ variable is nil or false, set it to a new Hash;
otherwise, leave it alone (assigning it to itself).”

In practice it is used to mean what you say (if this variable isn’t
already what I want it to be, set it to that thing), so your comment
largely stands as correct. I just don’t want anyone coming to Ruby to
read that and think it’s some special syntax that involves the object
on the right hand side in the decision of whether or not the assignment
should occur.