Ruby Gotchas presentation slides

I recently made available the slides for a presentation I did
recently, on Ruby Gotchas, at:

https://docs.google.com/presentation/d/1cqdp89_kolr4q1YAQaB-6i5GXip8MHyve8MvQ_1r6_s

Other than the title, intro, and wrapup, there are 20 slides of
gotchas, from beginner (string interpolation requires double quotes)
to advanced (throw/catch vs. raise/rescue). I’m thinking of turning
it into a series of very brief screencasts. Check it out, let me know
what you think… and if you have any more gotchas you’d like me to
cover.

Thanks,
Dave

Nice presentation

On Sat, Mar 30, 2013 at 6:55 PM, Dave A.

On 31/03/2013, at 10:55 AM, Dave A. [email protected]
wrote:

cover.

Thanks,
Dave

This bothers me a little bit, because quite a few of your “gotchas” are
about how ruby is ruby. For example, puts ‘hi’ if 0 is unexpected if
you’re a C programmer., but not if you’re a smalltalker! But it’s Ruby,
not C or smalltalk!

Also, your slide 20 is about a closure, not a loop. This isn’t a loop.
An Enumerator/Iterator construction is not a loop! You can think of
them as loops if you like, but an Enumerator is a class that can execute
a closure/block many times, passing in different arguments sometimes.
Point in case:

(1…4).map
=> #<Enumerator: 1…4:map>

e = _
=> #<Enumerator: 1…4:map>

e.next
=> 1

e.next
=> 2

e.next
=> 3

The Enumerator doesn’t “close over” any local variables in the scope of
its block… that would make no sense. If that were the case, it
wouldn’t be a closure anymore, it’d just be code in the main body. If
you need variables that stick around, set the variable outside of the
lexical scope of the closure, then it’ll stick around.

Variables aren’t “re-un-defined”! (what a verbal construction!), they
merely fall out of scope when the closure finishes execution each time,
so they don’t exist anymore. If you’re going to do some educating, it’d
be good if you made sure the NEW information you are propagating is as
correct as possible.

l = lambda{|val| val + 5}
=> #<Proc:[email protected](irb):1 (lambda)>

(1…4).map(&l)
=> [6, 7, 8, 9]

It seems you know all this, but it’d be nice if you put it into your
slides :slight_smile:

Otherwise, nice work!

Julian

On 31/03/2013, at 5:36 PM, Josh C. [email protected] wrote:

Might also add floating point number imprecision.
$ ruby -e ‘p 7.01 - 7’
0.009999999999999787

Really? That’s got nothing to do with Ruby! That’s computers! :slight_smile:

Julian.

On Sat, Mar 30, 2013 at 6:55 PM, Dave A.
<[email protected]

wrote:

what you think… and if you have any more gotchas you’d like me to
cover.

Thanks,
Dave

The double vs single quotes doesn’t seem like a gotcha to me.

The constants one is good.

The freezing one is good, but should be separated from the constants, as
it’s really just about variables. You can update the variable, but not
modify the object, so you have to know which you’re doing. Might also
mention that it is for just that one object, so freezing an array
doesn’t
freeze the elements in the array.

the and vs && / or vs || are good

The method args are good (I see people tripped up on that moderately
frequently.

Balanced whitespace is good (better example would be one -1)

Naked variable is IMO, the most relevant, as it still bites me when I’m
not
paying attention. Though I’m never intending to set the ivar, I always
meant to invoke the setter. I’m pretty sure that’s the real case where
this
bites you.

Class variables are also a good one, I just flat out don’t use them.

The parent initialize one doesn’t seem legitimate to me, that’s how
inheritance works, why would you expect anything else?.

The example for local var in the block seems too contrived. It’s only
ever
hit me when I tried to do something like .each{ |i| sum ||= 0; sum += i }
in the loop, in which case it always gets set to zero.

The idea credit seems out of place, the hash block setting the value has
been a common pattern for a long time. Frankly, I dislike it because it
(a)
sets keys on access, regardless of whether or not they will be used
(e.g.
you could be carrying around thousands of empty arrays), and (b) changes
behaviour of hash such that you must use #.has_key? to see if the key is
set, because otherwise, the key is always set. You can’t reliably use
things like #size. It just seems too clever to me. Really, though, I
think
the Array version of this is a better example, because it’s reasonable
to
want to construct an array of objects with something like Array.new(10, []) and not have a good enough understanding of the object model to see
why this can’t work.

I’d maybe add lambda vs proc:
lambda { }.call(1)
Proc.new {}.call(1)
lambda { return 1 }.call
Proc.new { return 1 }.call

Might also add method_missing, which is evil (I don’t think eval is
evil,
but using method_missing on code that anyone else uses is sadistic)

Might also add floating point number imprecision.
$ ruby -e ‘p 7.01 - 7’
0.009999999999999787

Might also mention when a block gets instance evaled, but you’re calling
methods on your local context (e.g. a dsl you call from rspec can’t call
a
let).

Might also add nonprinting characters, I’ve had numerous times where I
copied code (e.g. Textmate output) and the whitespace came in as
nonprinting characters (probably nonbreaking space), and messed up the
file, but I couldn’t see it. One cool thing about github is they
highlight
these.

I’d also put the most relevant ones earlier, when people will be paying
the
most attention.

On Sun, Mar 31, 2013 at 2:14 AM, Julian L.
[email protected]wrote:

It’s IEEE floating point math.

It does have to do with Ruby, Ruby could have implemented literal
numbers
with decimal points using Rational or BigDecimal instead of Float. Both
are
in the stdlib (plus, there are gems like flt)

require ‘bigdecimal’
require ‘bigdecimal/util’
(‘7.01’.to_f - ‘7.00’.to_f) # => 0.009999999999999787
(‘7.01’.to_r - ‘7.00’.to_r) # => (1/100)
(‘7.01’.to_d - ‘7.00’.to_d).to_digits # => “0.01”

On Sat, Mar 30, 2013 at 10:37 PM, Julian L.
[email protected] wrote:

quite a few of your “gotchas” are about how ruby is ruby.

Er, well, yeah, that was kinda the point!

For example, puts ‘hi’ if 0 is unexpected if you’re a
C programmer., but not if you’re a smalltalker!

Eh? I didn’t bother with the “conditional after statement” stuff.
That’s common enough in other scripting languages, and it’s just a
syntax variation, not a gotcha per se. The capability may be
surprising, but it’s not something that you might expect to work a
completely different way, or something that looks perfectly valid but
isn’t, due to parser quirks.

Also, your slide 20 is about a closure, not a loop.

Sort of. It looks like a loop, it quacks like a loop… but the
second you turn your back, it will nibble you to death with quirks
like that. :slight_smile: I suppose I could make the difference, and the root
cause, clearer without being TOO verbose. How’s this grab you:

Variables declared in /blocks passed to iterators/ (e.g., times or

each) are undefined at the top of /each/ iteration!

/Built-in looping constructs/ (e.g., while or for) are OK.

/Iterators/ call the block repeatedly, so vars are out of scope

again after each call.

I’ve made the code skinnier (meaning the error message takes more
lines), so I could extend the explanation into more lines.

If you’re going to do some educating, it’d be good if you made sure
the NEW information you are propagating is as correct as possible.

It’s as correct as could be squeezed into the space and time
available. (I was trying to keep the whole thing under an hour.) I’m
considering making this into a series of screencasts, and then perhaps
I can explain more.

Thanks,
Dave

On Sun, Mar 31, 2013 at 2:36 AM, Josh C. [email protected]
wrote:

The double vs single quotes doesn’t seem like a gotcha to me.

I was debating that one. The rule is the same in most languages that
HAVE string interpolation, so yeah, it shouldn’t be terribly
surprising. But in most languages I’ve used, one or the other (single
vs. double) is just plain invalid (for a multi-char string), or
they’re both equally valid, so there being a difference at all is a
bit of a gotcha.

The freezing one is good, but should be separated from the constants, as
it’s really just about variables. You can update the variable, but not
modify the object, so you have to know which you’re doing. Might also
mention that it is for just that one object, so freezing an array doesn’t
freeze the elements in the array.

Ah, yes, I had originally intended to do something about modding the
references vs. the object it points to. Forgot to split that out.
Array slots are of course simply a special case of that. I’ll split
'em out and work on it before the next time I present it.

Balanced whitespace is good (better example would be one -1)

Oooh, good one!

The parent initialize one doesn’t seem legitimate to me, that’s how
inheritance works, why would you expect anything else?.

IIRC, in some languages, they do automagically run parental initters
for you by default. It’s been so long since I’ve done much OO other
than Ruby, especially with inheritance, that I forget which does what.

The example for local var in the block seems too contrived. It’s only ever
hit me when I tried to do something like .each{ |i| sum ||= 0; sum += i }
in the loop, in which case it always gets set to zero.

Well, yeah, they’re all rather contrived! I didn’t put a high
priority on thinking up a realistic example, so I’ll just swipe yours.
:slight_smile:

The idea credit seems out of place, the hash block setting the value has
been a common pattern for a long time.

I figured, better to give credit too much and take up extra space,
than to slight someone by stealing something. But to make you happy,
I won’t credit your loop/closure var-value-losing example. :slight_smile:

Frankly, I dislike it because it (a)
sets keys on access, regardless of whether or not they will be used (e.g.
you could be carrying around thousands of empty arrays),

Good point, I’ll add a caveat.

and (b) changes
behaviour of hash such that you must use #.has_key? to see if the key is
set, because otherwise, the key is always set.

True, but if you’re using it for a specific purpose, there’s probably
a more domain-relevant test. In the case I showed, someone wanting to
know if someone knows any computer languages might ask if
langs[employee].any?.

I think the
Array version of this is a better example,

Also useful… but I think it’s still worth pointing out this gotcha
with hashes too. I’ll make them separate slides, with Arrays first
since creating them all up front is clearer.

I’d maybe add lambda vs proc:

Yeah, I thought about delving into that, but it was a bit more
advanced than I wanted to inflict at that point. I was trying to keep
the whole talk under an hour, including Q&A, and the audience has a
wide range of skill levels. Maybe I’ll just save it for last, and
skip it if we’re running short of time, or their eyes are glazing
over…

Might also add method_missing, which is evil (I don’t think eval is evil,
but using method_missing on code that anyone else uses is sadistic)

Eh… if used judiciously, and correctly (including a super-call if
not figured out), it can be OK. And if someone is messing about with
method_missing, I think they’re probably experienced enough not to
need this presentation. :slight_smile: But now that you mention it, the need to
ALSO adjust responds_to_missing, is quite a gotcha.

Might also add floating point number imprecision.

That’s in pretty much any language, so I don’t really count that as
a Ruby gotcha per se.

Might also mention when a block gets instance evaled, but you’re calling
methods on your local context (e.g. a dsl you call from rspec can’t call a
let).

Now you’re just making my head hurt! :wink: I think I read something on
that a few weeks ago, that I might be able to TL;DR-ify… or maybe it
was in the context of JavaScript, where issues of defining “this” are
critical AND common…

Might also add nonprinting characters,

Not Ruby-specific enough.

I’d also put the most relevant ones earlier, when people will be paying the
most attention.

Ordering is a bit of a tough question. I was initially trying to put
the easiest stuff first, so the Ruby-newbies could get some value out
of it before their eyes glazed over. :slight_smile:

Thanks,
Dave

Please keep this discussion going! I’m getting tons of value out of
lurking
this thread.
On Apr 1, 2013 4:50 PM, “Dave A.” [email protected]

Sorry about that reply. I was responding off my cell phone and it seems
to
do something weird when it sends, that makes it look like email does
when
its been quoted. Again, apologies for the weird looking reply.

On Mon, Apr 1, 2013 at 6:00 PM, D. Deryl D.
[email protected]wrote:

HAVE string interpolation, so yeah, it shouldn’t be terribly

freeze the elements in the array.
The parent initialize one doesn’t seem legitimate to me, that’s how
in the loop, in which case it always gets set to zero.
I won’t credit your loop/closure var-value-losing example. :slight_smile:
set, because otherwise, the key is always set.
with hashes too. I’ll make them separate slides, with Arrays first

Might also add floating point number imprecision.
that a few weeks ago, that I might be able to TL;DR-ify… or maybe it

taking contracts in or near NoVa or remote.
See information at http://www.Codosaur.us/.


[image: Your Logo]D. Deryl Downey,

*T: * *M: * *E: *

On Mon, Apr 1, 2013 at 7:04 PM, Matthew K. [email protected]
wrote:

It could be handy to have some gotchas explicitly listed under “gotchas
for C programmers” (or Java or PHP or whatever language to which you’re
accustomed) for all the ways in which Ruby can differ subtlely (or not
so subtlely in some cases.) However that doesn’t really fit the layout
of your current slides.

Right, that’s one of the reasons I was considering breaking them up,
be it into blog posts (my blog has been horribly inactive of late, see
http://blog.codosaur.us for details) or screencasts or whatever. Then
I could tag.

Otherwise, all round, cool presentation.

Thanks!

BTW, I’ve made numerous additions and clarifications today, based on
assorted feedback received here.

-Dave

On Sun, Mar 31, 2013 at 1:36 AM, Josh C. [email protected]
wrote:

The example for local var in the block seems too contrived. It’s only ever
hit me when I tried to do something like .each{ |i| sum ||= 0; sum += i }
in the loop, in which case it always gets set to zero.

There’s also the opposite side of this, which is that a var in a for
loop
doesn’t open a new scope on each invocation, which can be confusing
because
all iterations are using the same variable.

blocks = []
1.upto(5) { |i| blocks << lambda { i } }
blocks.map &:call # => [1, 2, 3, 4, 5]

blocks = []
for i in 1…5; blocks << lambda { i } end
blocks.map &:call # => [5, 5, 5, 5, 5]

Or could cause you to override a variable you meant to shadow

var = 100

1.upto(10) { |var| }
var # => 100

for var in 1…10; end
var # => 10

Might be too nuanced, but if you don’t understand the object model, it
might be unclear why include doesn’t override your instance methods.

module A
def meth
‘A#meth’
end
end

class B
def meth
‘B#meth’
end

include A
end

B.new.meth # => “B#meth”

Dave A. wrote in post #1104005:

On Sun, Mar 31, 2013 at 2:36 AM, Josh C. [email protected]
wrote:

The double vs single quotes doesn’t seem like a gotcha to me.

I was debating that one.

It could be handy to have some gotchas explicitly listed under “gotchas
for C programmers” (or Java or PHP or whatever language to which you’re
accustomed) for all the ways in which Ruby can differ subtlely (or not
so subtlely in some cases.) However that doesn’t really fit the layout
of your current slides.

If they were categorised that way, I’d list single- vs double-quotes
under C-style gotchas (they’re bog standard in perl and bash, but ‘ab’
is a 16-bit integer in C).

Otherwise, all round, cool presentation.

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs