Bug in ruby?

Well, I’ve spent the last hour or so debugging one of the stupidest
errors I have encountered with Ruby.

Let’s see my code first:

def parse(string, starting, ending) istart = string.index(starting) + starting.length iend = string.index(ending, istart) return string.slice(istart, iend - istart) end

This function is called about 13 times in my entire script. It breaks on
the last one with this error:

undefined method `+’ for nil:NilClass

Now, I have debugged the living hell out of this application. It’s
breaking on the first line, stating that starting.length is a nil object
and that it can’t perform a + operator in a nil object. The string
that’s getting passed into starting is:

buy_item.phtml?

I debugged the application and put a mark on the first line to examine
it in the following code:

def parse(string, starting, ending) length = starting.length istart = string.index(starting) + length iend = string.index(ending, istart) return string.slice(istart, iend - istart) end

And the debugger said that length was an int with the value of 15. Guess
what still happened? Got the exact same error with the + operator on a
nil object. Except that completely contradicts the fact that it’s not
nil but it’s an int with the value of 15.

I have spent the last hour trying hundreds of different forms of this
code and am getting the same exact error every time. I’ve come to the
conclusion that this must be some kind of bug in Ruby, I can not pull on
piece of logical evidence out of this.

So my last resort is you guru’s here, what am I doing wrong? Is there
some kind of magical law I broke? This application needs to get done
tonight, and I really can’t afford anymore time on this tiny little bug.
Thanks in advanced.

~ Alias

On 11/20/06, AliasX Neo [email protected] wrote:

This function is called about 13 times in my entire script. It breaks on
the last one with this error:

undefined method `+’ for nil:NilClass

Now, I have debugged the living hell out of this application. It’s
breaking on the first line, stating that starting.length is a nil object
and that it can’t perform a + operator in a nil object. The string
that’s getting passed into starting is:

Wouldn’t it be string.index() that is Nil here:

string.index(starting).+(starting.length)

starting.length is a parameter to the ‘+’ method being called on the
result of index().

AliasX Neo wrote:

Well, I’ve spent the last hour or so debugging one of the stupidest
errors I have encountered with Ruby.

> And the debugger said that length was an int with the value of 15. Guess > what still happened? Got the exact same error with the + operator on a > nil object. Except that completely contradicts the fact that it's not > nil but it's an int with the value of 15. >
  • is being called on string.index(starting) not length. I’d check to
    make sure you aren’t getting nil from that:

def parse(string, starting, ending)
p string.index(starting)
istart = string.index(starting) + length
iend = string.index(ending, istart)
return string.slice(istart, iend - istart)
end

Hope that helps.

-Justin

This is a subject line that’s mildly infuriating. I wonder if I can
recall more than three threads of that name that actually were a bug in
Ruby after all in the past year, and the one that’s in living memory was
from Ara, and (unsurprisingly) a very subtle issue where it took me
three reads to find out why it’s wrong behaviour in the first place, not
a “method not working at all” issue.

If you’re not a syntax lawyer, and / or haven’t checked the
documentation for what you’re using a code snippet in the first place,
I’d say odds are good it’s a bug in your code due to some (maybe not
really) gotcha you overlooked. And in that case it would be better to
present a problem as such, and providing a more informative subject line
to boot.

Also:

def parse(string, start, ending)
string.match(/#{Regexp.escape(start)}.*(?=#{Regexp.escape(ending)}/)[0]
end

David V.

On 11/21/06, Justin C. [email protected] wrote:

[code]def parse(string, starting, ending)

  • is being called on string.index(starting) not length. I’d check to
    make sure you aren’t getting nil from that:

which is expected behavior
http://www.ruby-doc.org/core/classes/String.html#M000805
cheers
Robert

def parse(string, starting, ending)


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

David V. wrote:

really) gotcha you overlooked. And in that case it would be better to

There have been many that I thought were “bugs in Ruby”, though mainly
in the error message produced rather than that the code should have done
what the person objecting thought it should have done.

I’ll grant that good error messages are a hard problem, but I frequently
find them totally exasperating. E.g., if a loop isn’t properly closed,
the error message should point to where it started rather than several
lines after the end of the program. (Well, perhaps this one’s been
fixed. I don’t remember encountering it recently. But if it hasn’t
been, I consider it a bug in Ruby.)

In this case the bug was in the message not stating which variable had a
nil value. You may not think of it as serious, but he reports spending
several hours on it, and I’d call that a bug.

Remember, Ruby is being recommended to total neophytes as a good
language to start with. That means that good diagnostic error messages
are essential!

On 11/21/06, Charles D Hixson [email protected] wrote:

I’d say odds are good it’s a bug in your code due to some (maybe not
David V.
fixed. I don’t remember encountering it recently. But if it hasn’t
been, I consider it a bug in Ruby.)

In this case the bug was in the message not stating which variable had a
nil value. You may not think of it as serious, but he reports spending
several hours on it, and I’d call that a bug.

Remember, Ruby is being recommended to total neophytes as a good
language to start with. That means that good diagnostic error messages
are essential!

I have also previously requested that this get fixed in a future Ruby.
It’s very annoying to try and guess which could be the offending
variable in a complex expression, and it wastes a lot of time. It
would surely be very easy for Ruby to say which variable was nil.

In some of my latest scripts I have this:

def preventNil(*args)
args.each_with_index do |arg, i|
raise ArgumentError.new(“argument #{i} cannot be nil”) if arg.nil?
end
end

class StatSaver
def initialize(vehicle, column, dataSet, log)

preventNil(vehicle, column, dataSet, log)

@vehicleID = vehicle.VehicleID
@column = column
@dataSet = dataSet
@log = log

end

…as a kind of firebreak contract to prevent nil’s from failures in
completely unrelated places causing other code to fall over. You don’t
always realise that a certain method might return nil.

I’d be interested to hear if there are nicer solutions to this problem.

Les

Charles D Hixson wrote:

In this case the bug was in the message not stating which variable had a
nil value. You may not think of it as serious, but he reports spending
several hours on it, and I’d call that a bug.

I’m not aware of a programming language that DOES report this. Remember
that a nil value can come out of a fairly complex expression instead of
a single variable, and that nil can have many variables bound to it at a
given moment. The bug was in the OP’s code, plain and simple, it’s not
the responsibility of the programming language to do in-depth diagnosis
of dangling pointer problems.

Also, in the OP, the error message was consistent to Ruby’s semantics -
a NoMethodError on nil usually significates what a NPE in Java,
NullRefError in C#, or segfault in C would be. Since the undefined
method was #+, the culprit was the expression that a method of that name
was called on in that code snippet.

Ruby reported what happened consistently with its computation model
(failed method lookup, nil being a regular object), and where it
happened (with no less detail than any other programming language I’ve
worked with reports on null pointers).

Further diagnostics (why it could have possibly happened) is the role of
a static code analysis tool; since it’s sooner or later guesswork it’s
not the task of the interpreter itself.

Coding defensively and using sanity checks on the return value of #index
and other methods that may return nil would also have helped.

Remember, Ruby is being recommended to total neophytes as a good
language to start with. That means that good diagnostic error messages
are essential!

As is learning the syntax rules and how to read the error messages.

Also, whoever makes that recommendation is a fool, and I’m not
responsible for him making that wrong recommendation. AFAIK, the Ruby
language presumes the programmer is a grownup, and there’s a LOT of
running with scissors involved. The simplicity makes it easy to pickup,
but in my opinion it gets very difficult to hobble along with only basic
knowledge and get something working done as the emergent behaviours
“noone tells you about” bite you if you don’t either delve deeper into
how stuff works to avoid those errors, or get a broader overview of
what’s available to end up writing less code (e.g. replacing futzing
around with substrings with a RE.)

David V.

Leslie V. wrote:

It’s very annoying to try and guess which could be the offending
variable in a complex expression, and it wastes a lot of time. It
would surely be very easy for Ruby to say which variable was nil.

Meet my good friends, local variable, and return value checking. You’ll
get along great once you get to know each other.

Also, see previous post. At any given point in time, there’s several
variables that point to nil in the interpreter, and the culprit is also
usually an expression. Finding the possible expressions that returned a
nil would require tracing back to the literal in the stack frames, and
even then the last one wouldn’t have to be the cause of the problem. I
stand by my point that this is not the job of a core language runtime,
but of manual or automated code review.

David V.

Bill K. wrote:

solution may not generate useful information. See for ex:
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/209336

Regards,

Bill
I admitted it was a hard problem … but, well,…

if functions are defined, and begins/ends balance within them, it
probably happened before or after that. Not guaranteed, as there might
be internal functions, but probable. If it’s an end that is missing
(usual case) start parsing from inner constructs out. Etc.

(FWIW, I normally comment my ends thusly:
end # initialize
for just this reason. With Ruby syntax it is a REALLY hard problem.
When this has occurred a few times I start really agreeing with the
languages that do things like “end if” or “end def”.)

OTOH, it’s also true that by compiling every time I enter a new
definition I can generally handle this error with minimal problems …
but it would be a lot easier to include sufficient context markers to
ensure localization of errors.

From: “Charles D Hixson” [email protected]

I’ll grant that good error messages are a hard problem, but I frequently
find them totally exasperating. E.g., if a loop isn’t properly closed,
the error message should point to where it started rather than several
lines after the end of the program. (Well, perhaps this one’s been
fixed. I don’t remember encountering it recently. But if it hasn’t
been, I consider it a bug in Ruby.)

Have you thought through how this might work? It seems the obvious
solution may not generate useful information. See for ex:
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/209336

Regards,

Bill

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

usually an expression. Finding the possible expressions that returned a
nil would require tracing back to the literal in the stack frames, and
even then the last one wouldn’t have to be the cause of the problem. I
stand by my point that this is not the job of a core language runtime,
but of manual or automated code review.

It just seems like it would be easier than that, since Ruby is an
interpreter. Doesn’t the last sub-expression get stored in a string
somewhere as the expression is parsed?

Anyway, I am just now noticing that 5+nil and nil+5 return different
error messages. As long as an operator is unique in an expression, it
should be easy to figure out which is nil.

Leslie V. wrote:

variables that point to nil in the interpreter, and the culprit is also
Anyway, I am just now noticing that 5+nil and nil+5 return different
error messages. As long as an operator is unique in an expression, it
should be easy to figure out which is nil.

The thing is, Ruby is not returning “nil” error messages, it’s returning
error messages which are consistent across all NoMethodError and
TypeError exceptions (in these cases). More generally, nil is not
getting any kind of special treatment. I think this is kind of nice,
personally.

-Justin

On Wed, 22 Nov 2006, David V. wrote:

Charles D Hixson wrote:

In this case the bug was in the message not stating which variable had a
nil value. You may not think of it as serious, but he reports spending
several hours on it, and I’d call that a bug.

This is one of the things I find irritating as well. Normally Ruby
is rightly praised for not getting in the way of productivity, but
this really does force one to program to meet constraints which are
not actually part of the language as such.

I’m not aware of a programming language that DOES report this. Remember

Some other languages report things differently…
[…]

NullRefError in C#, or segfault in C would be. Since the undefined
method was #+, the culprit was the expression that a method of that name
was called on in that code snippet.

…but in many conventionally constructed arithmetic expressions there
will be more than one plus sign. Some languages use an arrow

    y = (a * x**3) + (b * x * x) + (c * x) + d
                   ^
                   |

-----------------------+

or similar. Evidence? The %p construct in vim errorformats
in compiler files for handling error messages, which uses
the arrow to pick up the column:

/usr/local/share/vim/vim70/compiler/ant.vim: %A\ %#[%.%#]\ %f:%l:\
%m,%-Z\ %#[%.%#]\ %p^,%C\ %#[%.%#]\ %#%m
/usr/local/share/vim/vim70/compiler/bdf.vim: %-Z%p^,
/usr/local/share/vim/vim70/compiler/eruby.vim: %-Z%p^,
/usr/local/share/vim/vim70/compiler/fortran_cv.vim: %-Z%p%^%.%#,
/usr/local/share/vim/vim70/compiler/fortran_elf90.vim: %C%p|,
/usr/local/share/vim/vim70/compiler/fortran_g77.vim: %-C\ \ \
%p%*[0123456789^]%.%#,
/usr/local/share/vim/vim70/compiler/hp_acc.vim: %Z\ \ \ \
%p^%.%#,
/usr/local/share/vim/vim70/compiler/icc.vim:CompilerSet
errorformat=%-Z%p^,%f(%l):\ remark\ #%n:%m,%f(%l)\ :\ (col.\ %c)\
remark:\ %m,%E%f(%l):\ error:\ %m,%E%f(%l):\ error:\ #%n:\ %m,%W%f(%l):\
warning\ #%n:\ %m,%W%f(%l):\ warning:\ %m,%-C%.%#
/usr/local/share/vim/vim70/compiler/intel.vim: %-Z\ \ %p^,
/usr/local/share/vim/vim70/compiler/irix5_c.vim: %-Z\ %p^,
/usr/local/share/vim/vim70/compiler/irix5_cpp.vim: %-Z\ \ %p%^,
/usr/local/share/vim/vim70/compiler/javac.vim:CompilerSet
errorformat=%E%f:%l:\ %m,%-Z%p^,%-C%.%#,%-G%.%#
/usr/local/share/vim/vim70/compiler/mips_c.vim: %-Z\ \ %p^,
/usr/local/share/vim/vim70/compiler/mipspro_c89.vim: %-Z%p%^,
/usr/local/share/vim/vim70/compiler/mipspro_cpp.vim: %-Z\ \ %p^,
/usr/local/share/vim/vim70/compiler/ruby.vim: %-Z%p^,
/usr/local/share/vim/vim70/compiler/xmllint.vim: %-Z%p^,

So it looks like Ruby does this occasionally itself.

    [...]

Further diagnostics (why it could have possibly happened) is the role of
a static code analysis tool; since it’s sooner or later guesswork it’s

Which doesn’t apply in dynamic languages like Ruby where method creation
on the fly is the norm (attr_accessor, method_missing, and more).

not the task of the interpreter itself.

Coding defensively and using sanity checks on the return value of #index
and other methods that may return nil would also have helped.

This doesn’t mean that is is undesirable that Ruby do more. This is
shifting the burden from the developers of ruby to the many users
of it. Not to suggest that the developers have all the time in the
world, but to say that more people are affected by not having this than
are affected by having to implement it.

Now, I would be the first to say that writing parsers is not easy.
I have tried on a number of occasions, and frankly, I am rubbish at
it. Given the constraints imposed by YACC on the future of the
language (see other threads in the past) I suspect that moving to
some other parser may be helpful. But the point of this post is
that there is evidence from other languages that it is possible for
Ruby to be more helpful, there is a desire among its users that it
be more helpful. The next question, which I can’t answer given my
weaknesses in this area, is: how can this be improved? Or,
conversely, can it be shown that improving it would be detrimental
to Ruby in some important way?

We know Ruby is excellent. That’s why we’d like it to be even better.

    Hugh

On 11/21/06, AliasX Neo [email protected] wrote:

    istart = string.index(starting) + starting.length

[…]

undefined method `+’ for nil:NilClass

Other people have said this, but just to put it explicitly:

Ruby has a message-passing object model - every operation consists of
a message sent to an object. Thus, there are no symmetrical operations

  • even binary operations like + translate internally to one object
    being sent to the other as part of a “+” message. Indeed, you could
    even write the above as

istart = string.index.starting.+(starting.length)

to make it explicit that there’s a method call going on under the hood.

One consequence of this is that when an exception or error is thrown,
it is thrown from the context of the receiving object. Thus “undefined
method `+’ for nil:NilClass” means you have attempted to call
nil.+(something), not something.+(nil). That should help greatly in
debugging stuff.

martin

Leslie V. wrote:

interpreter. Doesn’t the last sub-expression get stored in a string
somewhere as the expression is parsed?

Probably not, to my best knowledge, a source file is always tokenized
and parsed into an AST before interpreting. The interpreter would have
to do extra work to reconstruct the last expression, which might not
really be helpful always, or even in most cases. (Someone with more
information on the interpreter’s internals could say this with more
authority.)

David V.

Hugh S. wrote:

not actually part of the language as such.

    y = (a * x**3) + (b * x * x) + (c * x) + d
                   ^
                   |

-----------------------+

or similar. Evidence? The %p construct in vim errorformats
in compiler files for handling error messages, which uses
the arrow to pick up the column:

You might want to look up the definition of evidence, this is stretching
the word way, WAY too far.

I haven’t been able to get either .NET/C# or Java to show me where on a
line a NRE/NRE occured.

The arrows you mention are probably for compile-time errors. Read: while
the source code is being read, is present in it’s textual
representation, and the errors detected are ones that can be determined
from the structure of the source code. A NPE is a runtime error, long
after the textual form of the code is under green pastures.

So it looks like Ruby does this occasionally itself.
[…]

Probably for parse-time errors.

It is completely irrelevant if some languages detect some classes of
errors with precise source code locations, or that Ruby does this sort
of diagnostics at parse-time for other classes of errors than the one at
hand, when you can’t bring a specific, valid counterexample to my
statement, which is that I can’t recall a language that does that for
runtime errors, specifically of the dangling pointer class of errors.

Provide me with an example where a runtime problem in a complex
expression like the one you mentioned gives you exact source code
position, preferrably in a programming language I’ve actually heard of
before (there’s enough of those), and I’ll concede this point.

Further diagnostics (why it could have possibly happened) is the role of
a static code analysis tool; since it’s sooner or later guesswork it’s

Which doesn’t apply in dynamic languages like Ruby where method creation
on the fly is the norm (attr_accessor, method_missing, and more).

That’s a price you pay for using a dynamic language with relatively
little mainstream penetration, those tools are harder to develop, have
to rely on less conclusive heuristics, there’s a smaller market for them
and little chance of someone implementing them without a market because
they’d end up solving problems a lot of people consider a non-issue. If
you want tool support, Java beckons, otherwise wait until Ruby
equivalents emerge. It’s also unrelated to the issue at hand.

Specifically, it doesn’t imply (except in wishful thinking) that it
should be the job of the interpreter to provide possibly (probably)
unrelated “this -might- have gone wrong” type of information. The Ruby
interpreter’s behaviour as it is is in my opinion correct and complete -
it provides the programmer with all the information it has at the time
from the information it needs to run the program. I am strongly opposed
to losing interpreter runtime efficiency (from keeping full program
source code intact in memory, for example) to provide heuristic
diagnostics.

For me, it is undesirable. If it’s a problem that can be solved within
the standard library by providing a set of DbC -ish metaprogramming
features, be it so. Same if it’s a missing feature that can be
implemented without ambiguous output.

And for features that are clearly in the domain of code analysis tools,
I’m clearly against. Yes, such tools are absent in the Ruby domain. This
however doesn’t imply the core interpreter should become one. I don’t
want it to become a full-blown development tool, or any other form of
bloated monstrosity, the core responsibility of the interpreter is to
run Ruby code, and say when it can’t stating the immediate reason why.

Now, I would be the first to say that writing parsers is not easy.
I have tried on a number of occasions, and frankly, I am rubbish at
it. Given the constraints imposed by YACC on the future of the
language (see other threads in the past) I suspect that moving to
some other parser may be helpful. But the point of this post is
that there is evidence from other languages that it is possible for
Ruby to be more helpful, there is a desire among its users that it
be more helpful.

I’ll repeat that I haven’t seen evidence that this class of errors is
diagnosed with the level of detail you’d like in a language with a
computation model similar to Ruby from you.

David V.

On Thu, 23 Nov 2006, David V. wrote:

Hugh S. wrote:

or similar. Evidence? The %p construct in vim errorformats
in compiler files for handling error messages, which uses
the arrow to pick up the column:

You might want to look up the definition of evidence, this is stretching
the word way, WAY too far.

Are we talking evidence for civil or criminal cases here? :slight_smile:
I have provided evidence for diagnostic messages pointing to the point
in the line where the error occurs. I concede that usually this is
for syntax errors. See below.

I haven’t been able to get either .NET/C# or Java to show me where on a
line a NRE/NRE occured.

The arrows you mention are probably for compile-time errors. Read: while

They generally are, I agree. I can’t assert “always”, and no, I
can’t provide a counter example.

the source code is being read, is present in it’s textual
representation, and the errors detected are ones that can be determined
from the structure of the source code. A NPE is a runtime error, long
after the textual form of the code is under green pastures.

There are reasons for not throwing that information away in an
interpreter.

So it looks like Ruby does this occasionally itself.
[…]

It is completely irrelevant if some languages detect some classes of
errors with precise source code locations, or that Ruby does this sort
of diagnostics at parse-time for other classes of errors than the one at
hand, when you can’t bring a specific, valid counterexample to my

I don’t tend to keep things with errors like this in lying around,
and can’t remember off the top of my head.

statement, which is that I can’t recall a language that does that for
runtime errors, specifically of the dangling pointer class of errors.

We are not discussing pointers. We are discussing method calls on
objects that don’t support them, and stating where in the computation
this occurred.

Provide me with an example where a runtime problem in a complex
expression like the one you mentioned gives you exact source code
position, preferrably in a programming language I’ve actually heard of
before (there’s enough of those), and I’ll concede this point.

Just because nobody does it yet, it doesn’t mean it can’t be done.
[…]

Specifically, it doesn’t imply (except in wishful thinking) that it
should be the job of the interpreter to provide possibly (probably)
unrelated “this -might- have gone wrong” type of information. The Ruby

If it has the AST, it shouldn’t have to be probabilistic. I’m
specifically not saying this is easy, I’m saying it is desirable,
and that I accept constraints.

    [...]

to losing interpreter runtime efficiency (from keeping full program
source code intact in memory, for example) to provide heuristic diagnostics.

For heuristic (guesswork), I’d agree. For sufficient exactitude, then
under control of an option (like -w) I’d be in favour.

are affected by having to implement it.

For me, it is undesirable. If it’s a problem that can be solved within
the standard library by providing a set of DbC -ish metaprogramming
features, be it so. Same if it’s a missing feature that can be
implemented without ambiguous output.

I don’t see how one could do that for something internal to the
interpreter.

And for features that are clearly in the domain of code analysis tools,
I’m clearly against. Yes, such tools are absent in the Ruby domain. This
however doesn’t imply the core interpreter should become one. I don’t
want it to become a full-blown development tool, or any other form of
bloated monstrosity, the core responsibility of the interpreter is to
run Ruby code, and say when it can’t stating the immediate reason why.

It’s that ‘statement of the reason why’ I’d like improved.
Obviously there are trade-offs, and it is up to Matz. I’m simply
adding my voice to those that wish for improved diagnostics. If it
is impossible, or not practical at this time, or some other
sufficient constraint to prevent this, then fine. But if it is not
being done because there is no apparent desire for this, then I’d
like to say there is some desire for this. I fully accept that
this may run counter to other desirable attributes, such as speed
of execution, and a decision may not go in favour of better diagnostics
as a result. But to quote an early version of the Ruby Newsgroup FAQ:
http://www.rubycentral.com/faq/ruby_newsgroup_faq.txt
‘You could characterize the Ruby philosophy as “there’s a better way
to do it” (TABWTDI).’

    Hugh

AliasX Neo wrote:

Well, I’ve spent the last hour or so debugging one of the stupidest
errors I have encountered with Ruby.

It is a stupid error, but to say it diplomatically, the responsibility
assignment is flawed.

/ …

I have spent the last hour trying hundreds of different forms of this
code

Except the one shown below.

and am getting the same exact error every time. I’ve come to the
conclusion that this must be some kind of bug in Ruby, I can not pull on
piece of logical evidence out of this.

That is because you are not thinking hard enough.

So my last resort is you guru’s here, what am I doing wrong?

You are not breaking the problem down sufficiently. As others have
commented, there are two operands for “+” and you have only looked at
one
of them.

Do this:

length = starting.length
si = string.index(starting)
if(length != nil && si != nil)
istart = si + length
end

Is there some kind of magical law I broke?

Yes, as a matter of fact, there is. You assumed there was a flaw in the
language before exhausting the more obvious possibility that the error
is
your own.

This application needs to get done
tonight, and I really can’t afford anymore time on this tiny little bug.

Famous last words.

Charles D Hixson wrote:

/ …

I’ll grant that good error messages are a hard problem, but I frequently
find them totally exasperating. E.g., if a loop isn’t properly closed,
the error message should point to where it started rather than several
lines after the end of the program.

But the interpreter cannot do that without reading the programmer’s
mind.
Maybe the programmer intended to complete the loop in some code, not yet
written, that extends beyond the present end of the program. The
evidence
is that the interpreter’s scanner ended up at the end of the file, still
happy with the syntax up to that point.

(Well, perhaps this one’s been
fixed. I don’t remember encountering it recently. But if it hasn’t
been, I consider it a bug in Ruby.)

It is not a bug in Ruby if the incomplete loop could in principle
continue
beyond EOF.

In this case the bug was in the message not stating which variable had a
nil value. You may not think of it as serious, but he reports spending
several hours on it, and I’d call that a bug.

It is not a bug, at least, not in Ruby. At the point at which the error
condition arises, the ‘+’ method doesn’t know the names of the variables
that produced its inputs, it only knows that one of them is nil.
Remember
that this is a runtime error.

And the OP used a debugger but still didn’t realize there was a
possibility
he hadn’t considered. This is not something any finite-sized language
can
possibly deal with.

Also remember: in an interpreted language, every increase in
hand-holding
runtime comprehensiveness decreases execution speed.

Remember, Ruby is being recommended to total neophytes as a good
language to start with. That means that good diagnostic error messages
are essential!

It also means that, as in all computer programming for all time,
neophytes
have to pay attention to details.

The single most difficult part of learning how to program is to fully
grasp
how simple-minded computers actually are. Successful programmers know
exactly how a computer will react to their code. Learning this, reducing
it
to a matter of instinct, takes time.