[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

quality of error messages

Joachim Wuttke

10/6/2004 1:49:00 PM

25 Answers

Brian Candler

10/6/2004 2:15:00 PM

0

On Wed, Oct 06, 2004 at 10:48:49PM +0900, Joachim Wuttke wrote:
> Example 1: missing "end" in <last-line-of-code>
> -> I forget to close a "class" or a "do" or a "if" block -
> but which one ? Shouldn't the system be able to name
> possible locations of unclosed block openings ?

I agree with that one. I have often has to do a 'divide and conquer': create
a temporary file, copy in one class or method, run, paste in some more, run
again, until I locate the section of code which contains the error.

I think it's difficult for a parser to know where you might have missed an
'end'. It could show you where it thinks the most recent 'do'/'def' was, but
the error could be much, much higher up.

It seems that Ruby permits nested 'defs', which makes it almost impossible
to detect the error. But since nested defs are not common, perhaps there
could be a way to track them. What about if "ruby -W3" gave a warning for a
nested 'def'? That would allow you to isolate the error to a single method,
which would make life a lot easier.

class Foo
def bar(x)
if x == 3
puts "hello"
end

def baz(y) # <-- could error here?
end
end # <-- actually errors here


> Example 2: NoMethodError: undefined method.
> -> Wrong, I defined the method. I just forgot to
> include it in the attr_reader list. The system
> shouldn't mislead me.

That error is correct - perhaps you can give an example of code where you
think it is misleading.

Remember that
@foo = "hello"

sets an instance variable, but it does NOT create a method. You can do:

def foo
@foo
end
def foo=(x)
@foo=x
end

or you can do

attr_accessor :foo

to define corresponding methods automatically, but instance variables
purposely do not automatically gain accessor methods.

Regards,

Brian.


James Gray

10/6/2004 2:18:00 PM

0

On Oct 6, 2004, at 8:48 AM, Joachim Wuttke wrote:

> Example 2: NoMethodError: undefined method.
> -> Wrong, I defined the method. I just forgot to
> include it in the attr_reader list. The system
> shouldn't mislead me.

Could you please show a short example of code that triggers this
message and your solution for it? I don't think I understood the
description.

James Edward Gray II



Bill Atkins

10/6/2004 2:23:00 PM

0

On Wed, 6 Oct 2004 22:48:49 +0900, Joachim Wuttke
<joachim_wuttke@ph.tum.de> wrote:
> Hi Ruby developers,
>
> after spending some time with Perl and Python, I am
> currently exploring Ruby. While I am quite enthusiastic
> about some of its features, I am increasingly preocuppied
> about the difficulties to localize errors.
>
> Example 1: missing "end" in <last-line-of-code>
> -> I forget to close a "class" or a "do" or a "if" block -
> but which one ? Shouldn't the system be able to name
> possible locations of unclosed block openings ?

From what I understand, it's pretty difficult for Ruby (or any other
compiler) to figure out where the improperly-ended block began. Using
ruby-mode or some other automatic indenting system can help you spot
these errors.

Consider the following C code:

int main() {
if(1) {
// do something

int var = 34;
while(var < 10) {
var--;
}
}

gcc gives a similar message ("syntax error at end of input").
Obviously, the bracket for the if statement was never closed, but it's
difficult for a compiler to tell where it was supposed to end. (For
example, is the bracket closing the while meant to close the if
statement?)


> Example 2: NoMethodError: undefined method.
> -> Wrong, I defined the method. I just forgot to
> include it in the attr_reader list. The system
> shouldn't mislead me.

Hmm, you shouldn't be listing methods you've defined in an attr list.
the attr_* methods define getter and/or setter methods for the names
you pass to them.

Maybe you mean that you haven't declared an attr for some instance
variable and running object.variable gives you a NoMethodError. In
that case, remember that Ruby has no way to know the object.variable
is an attr_reader as opposed to a regular, user-defined method. Just
keep in mind that all accessors are just methods and then the error
message will probably seem more informative.

>
> Developers, do you share my opinion that this would
> be worth working upon ? I would really like to hear that
> error messages will improve in future versions of the
> interpreter.
>
> Once I open a Ruby/Tk session, error messages are
> redirected to an annoying popup window. Can I disable
> this behavior ? I would prefer to see errors in stdout,
> even when I am running a GUI.
>
> Regards, Joachim
>
>


Joachim Wuttke

10/6/2004 2:50:00 PM

0

Gavin Sinclair

10/6/2004 3:01:00 PM

0

On Thursday, October 7, 2004, 12:49:33 AM, Joachim wrote:

> Encouraged by your quick response, I try to explain better
> what I meant in example 2:

> class Foo
> attr_reader ... # here I forgot :pos
> def initialize
> ...
> @pos = ...
> end
> end
> ...
> blabla = someClass.someMethod.link_to_another_class.methods_pos.oof

=>> system complains "no such method"

> Formally, the system is right: I forgot to declare the read
> access method for the variable pos.

It tells you what method is missing from what object/class. This
should be enough for you to work out the problem.

> But:
> (1) the system should tell me which method in the above
> chain causes the problem

See above. Is your error message different from mine? (See IRB
transcript below.)

> (2) as a naive programmer, with a background in other languages,
> I do not think of pos as method. I think of it as variable.

The system is helping you, then, by reminding you it's a method :)
There's no such thing as direct access to instance variables in Ruby.

> Once the system does not find a method, it could check whether
> there is a local variable of same name, and then print out
> an error message like
> "no method 'pos', no read access to local variable 'pos'".

Too much effort. Better to just learn Ruby properly. I'm not
suggesting Ruby couldn't be made more user-friendly, but there's no
need in this area, IMO.

Cheers,
Gavin

P.S. IRB transcript:

$ irb
irb(main):001:0> class A
irb(main):002:1> def foo
irb(main):003:2> b = B.new
irb(main):004:2> b.bar
irb(main):005:2> end
irb(main):006:1> end
=> nil
irb(main):007:0> class B
irb(main):008:1> end
=> nil
irb(main):009:0> A.new.foo
NoMethodError: undefined method `bar' for #<B:0x10272b28>
from (irb):4:in `foo'
from (irb):9
irb(main):010:0>





Joachim Wuttke

10/6/2004 3:03:00 PM

0

James Gray

10/6/2004 3:04:00 PM

0

On Oct 6, 2004, at 9:49 AM, Joachim Wuttke wrote:

> Encouraged by your quick response, I try to explain better
> what I meant in example 2:
>
> class Foo
> attr_reader ... # here I forgot :pos
> def initialize
> ...
> @pos = ...
> end
> end
> ...
> blabla = someClass.someMethod.link_to_another_class.methods_pos.oof
>
> => system complains "no such method"
>
> Formally, the system is right: I forgot to declare the read
> access method for the variable pos.
>
> But:
> (1) the system should tell me which method in the above
> chain causes the problem

I was sure Ruby does this:

james% ruby broken.rb
broken.rb:9: undefined method `value' for #<Broken:0x1ca954 @value=3>
(NoMethodError)
james% cat broken.rb
#!/usr/bin/env ruby

class Broken
def initialize( value )
@value = value
end
end

puts Broken.new(3).value

__END__

Looks right to me. Is that what you're seeing?

> (2) as a naive programmer, with a background in other languages,
> I do not think of pos as method. I think of it as variable.
> Once the system does not find a method, it could check whether
> there is a local variable of same name, and then print out
> an error message like
> "no method 'pos', no read access to local variable 'pos'".

In Ruby all instance variables are private, so there's really no need
for such distinctions. A class defines its interface through its
methods.

I think your misconceptions here are just a few Rubisms that haven't
quite sunk in yet. Hopefully, you'll find the messages making more
sense over time.

And until then, just yell if you need us...

James Edward Gray II



Florian Frank

10/6/2004 3:10:00 PM

0

On 06.10.2004, at 15:48, Joachim Wuttke wrote:
> Example 2: NoMethodError: undefined method.
> -> Wrong, I defined the method. I just forgot to
> include it in the attr_reader list. The system
> shouldn't mislead me.

It doesn't. If you define the method with "def" yourself, you don't
have to call attr_reader at all.

attr_reader :foobar

generates an instance method like

def foobar
@foobar
end

that returns the instance variable @foobar.

You can actually define your own metaprogramming methods:

class Module
def attr_writer_positive(*ids)
ids.each do |id|
define_method("#{id}=") do |value|
raise "not positive" unless value > 0
instance_variable_set("@#{id}", value)
end
end
nil
end
end
# => nil

class Klass

attr_writer_positive :foo

end
# => nil

k = Klass.new
# => #<Klass:0x5de78>
k.foo = 5
# => 5
k.foo = -5
RuntimeError: not positive
from foo.rb:5:in `foo='
from foo.rb:4:in `foo='
from foo.rb:21

Florian Frank



Austin Ziegler

10/6/2004 3:19:00 PM

0

On Wed, 6 Oct 2004 23:49:33 +0900, Joachim Wuttke
<joachim_wuttke@ph.tum.de> wrote:
> => system complains "no such method"
>
> Formally, the system is right: I forgot to declare the read
> access method for the variable pos.
>
> But:
> (1) the system should tell me which method in the above
> chain causes the problem

irb(main):004:0> e = Object.new
=> #<Object:0x28c6f50>
irb(main):005:0> e.pos
NoMethodError: undefined method `pos' for #<Object:0x28c6f50>
from (irb):5

Now, it's impossible to tell which object returned is causing a problem, really:

irb(main):012:0> e = OpenStruct.new
=> <OpenStruct>
irb(main):013:0> e.f = OpenStruct.new
=> <OpenStruct>
irb(main):014:0> e.f.g = OpenStruct.new
=> <OpenStruct>
irb(main):015:0> e.f.g.h = Object.new
=> #<Object:0x28db698>
irb(main):016:0> e.f.g.h.pos
NoMethodError: undefined method `pos' for #<Object:0x28db698>
from (irb):16

But as a smart programmer, you'll note that it's whatever object is
calling "pos" -- because it does tell you which method is missing, and
obviously, the object returned by "h" is the one that doesn't support
pos.

> (2) as a naive programmer, with a background in other languages,
> I do not think of pos as method. I think of it as variable.
> Once the system does not find a method, it could check whether
> there is a local variable of same name, and then print out
> an error message like
> "no method 'pos', no read access to local variable 'pos'".

Absolutely not. Consider:

class FooReader
attr_reader :pos
def initialize(stream)
@stream = stream
end
def open
@stream.open unless @stream.opened?
@pos = @stream.pos
end
def read(size = 1)
raise "Stream must be opened" if @pos.nil?
data = @stream.read(size)
@pos = @stream.pos
data
end
end

@pos is *never* initialized during the initializer; thus, you know the
stream hasn't even been opened until you call Foo#open.

There is no meaningful correspondence between an instance variable and
its accessor methods. The proper answer here is for you to retrain
your thinking.

-austin
--
Austin Ziegler * halostatue@gmail.com
* Alternate: austin@halostatue.ca
: as of this email, I have [ 6 ] Gmail invitations


Florian Frank

10/6/2004 3:29:00 PM

0


On 06.10.2004, at 16:49, Joachim Wuttke wrote:
> But:
> (1) the system should tell me which method in the above
> chain causes the problem

Actually it does.

> (2) as a naive programmer, with a background in other languages,
> I do not think of pos as method. I think of it as variable.
> Once the system does not find a method, it could check whether
> there is a local variable of same name, and then print out
> an error message like
> "no method 'pos', no read access to local variable 'pos'".

You should think of it as a method. That's called the Uniform Access
Principle. It's true that almost all of the so called OOP languages get
it wrong, but that doesn't mean that Ruby should join them. Consider
that you change the implementation of your class and "pos" isn't a
variable (field) anymore but computed instead. In some other languages
you now have to change all the client code that directly accesses the
variable. That's exactly the opposite of data hiding and encapsulation
of state.

Florian Frank