String > Integer Conversion Problem

Hi --

I disagree that this particular use of an exception would be a no-no in
Java. Inability to parse input is justifiably an "exceptional" case.
And the handling of that exceptional case is also appropriate.

Agreed, I was referring more to the idea of swapping out flow control for exceptions in general. Obviously if the input is an exceptional case, throw an exception. I have just been wondering about a few examples of this I've seen in Ruby code, and just picked this as an 'in' to ask about it :wink:

The big "no-no" about exception usage is true for any language: "Don't
use exceptions for flow control".

The following code is "wrong" for various reasons as well as violating
the "axiom" above:

begin
# display 1 through 10
i = 0
while true
   unless i > 10
     puts i
   else
     raise "End o' the line"
   end
   i += 1
end
rescue
end

Ruby provides enough mechanisms for "controlling the flow" that using
exceptions for "normal" conditions is definitely poor style, if not
worse.

Okay, good. That was my feeling too.

I agree in general, although... there's one case where I can't resist,
at least sometimes, and that's this:

   if obj.respond_to("meth")
     obj.meth
   else
     <something else>
   end

I really dislike the repetition there, and it also technically isn't
thread-safe:

   a = Object.new
   def a.x; end

   Thread.new do
     sleep 1
     class << a; undef_method("x"); end
   end

   if a.respond_to?("x")
     sleep 2
     a.x
   end

   => undefined method `x' for #<Object:0x1cd508> (NoMethodError)

I don't know any way around it, though, except:

   begin
    obj.meth
   rescue NoMethodError
    <something else>
   end

or some variant thereof. (Obviously in true duck-typing cases you
just send the message without this kind of check, but there are cases
where the check makes sense.)

I've toyed with the idea of some kind of special "nack" object that
would be returned on these kinds of method calls, but I don't think it
plays well with method_missing.

David

···

On Thu, 22 Dec 2005, Ross Bamford wrote:

On Thu, 22 Dec 2005 14:07:03 -0000, jwesley <justin.w.smith@gmail.com> wrote:

--
David A. Black
dblack@wobblini.net

"Ruby for Rails", from Manning Publications, coming April 2006!

dblack@wobblini.net wrote:

Hi --

I disagree that this particular use of an exception would be a no-no in
Java. Inability to parse input is justifiably an "exceptional" case.
And the handling of that exceptional case is also appropriate.

Agreed, I was referring more to the idea of swapping out flow control
for exceptions in general. Obviously if the input is an exceptional
case, throw an exception. I have just been wondering about a few
examples of this I've seen in Ruby code, and just picked this as an
'in' to ask about it :wink:

The big "no-no" about exception usage is true for any language: "Don't
use exceptions for flow control".

The following code is "wrong" for various reasons as well as violating
the "axiom" above:

begin
# display 1 through 10
i = 0
while true
   unless i > 10
     puts i
   else
     raise "End o' the line"
   end
   i += 1
end
rescue
end

Ruby provides enough mechanisms for "controlling the flow" that using
exceptions for "normal" conditions is definitely poor style, if not
worse.

Okay, good. That was my feeling too.

I agree in general, although... there's one case where I can't resist,
at least sometimes, and that's this:

  if obj.respond_to("meth")
    obj.meth
  else
    <something else>
  end

I really dislike the repetition there, and it also technically isn't
thread-safe:

  a = Object.new
  def a.x; end

  Thread.new do
    sleep 1
    class << a; undef_method("x"); end
  end

  if a.respond_to?("x")
    sleep 2
    a.x
  end

  => undefined method `x' for #<Object:0x1cd508> (NoMethodError)

I don't know any way around it, though, except:

  begin
   obj.meth
  rescue NoMethodError
   <something else>
  end

This has the unfortunate side effect of conflating NoMethodErrors that
are reported for other method calls besides the original obj.meth but
which occur during that method. What's the best way of handling that?
Compare exception.backtrace depth with the current backtrace depth?

It's not really threadsafe either. By the time <something else> is
executed, #meth could have been defined (though you do know it was
undefined at the time of the method call, which is an improvement over
the #respond_to version).

···

On Thu, 22 Dec 2005, Ross Bamford wrote:

On Thu, 22 Dec 2005 14:07:03 -0000, jwesley <justin.w.smith@gmail.com> >> wrote:

or some variant thereof. (Obviously in true duck-typing cases you
just send the message without this kind of check, but there are cases
where the check makes sense.)

I've toyed with the idea of some kind of special "nack" object that
would be returned on these kinds of method calls, but I don't think it
plays well with method_missing.

David

--
      vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Hi --

Ruby provides enough mechanisms for "controlling the flow" that using
exceptions for "normal" conditions is definitely poor style, if not
worse.

Okay, good. That was my feeling too.

I agree in general, although... there's one case where I can't resist,
at least sometimes, and that's this:

   if obj.respond_to("meth")
     obj.meth
   else
     <something else>
   end

I really dislike the repetition there, and it also technically isn't
thread-safe:

   a = Object.new
   def a.x; end

   Thread.new do
     sleep 1
     class << a; undef_method("x"); end
   end

   if a.respond_to?("x")
     sleep 2
     a.x
   end

   => undefined method `x' for #<Object:0x1cd508> (NoMethodError)

I don't know any way around it, though, except:

   begin
    obj.meth
   rescue NoMethodError
    <something else>
   end

or some variant thereof. (Obviously in true duck-typing cases you
just send the message without this kind of check, but there are cases
where the check makes sense.)

Good point. Now you mention that, I think I'd probably end up going for the latter style in that case anyway, despite my comments earlier about exceptions. I guess it's about a balance between being prepared for exceptions and pre-empting them. Mostly in Java (the only language I've really used exceptions with) the choice is made, since you have to deal with (so-called 'checked') exceptions whenever they might be thrown, so I'm still finding my balance there.

I expect that version also makes refactoring easier later on if you decide to move the <something else> further up the chain.

I've toyed with the idea of some kind of special "nack" object that
would be returned on these kinds of method calls, but I don't think it
plays well with method_missing.

As a general way for objects to nack method calls? If so, maybe the default method_missing (or equivalent?) could do that, or you can provide your own method_missing to do whatever...?

The implications of the metaprogramming stuff on thread safety is a subject that, frankly, worries me. When I understand a bit more I'm looking forward to investigating that side of things.

Cheers,

···

On Thu, 22 Dec 2005 14:53:54 -0000, <dblack@wobblini.net> wrote:

On Thu, 22 Dec 2005, Ross Bamford wrote:

On Thu, 22 Dec 2005 14:07:03 -0000, jwesley <justin.w.smith@gmail.com> >> wrote:

--
Ross Bamford - rosco@roscopeco.remove.co.uk

Hi --

  begin
   obj.meth
  rescue NoMethodError
   <something else>
  end

[Did I really indent by only 1? It must have been early in the
morning... :-]

This has the unfortunate side effect of conflating NoMethodErrors that
are reported for other method calls besides the original obj.meth but
which occur during that method. What's the best way of handling that?
Compare exception.backtrace depth with the current backtrace depth?

I guess, but it gets awfully cluttered. I don't know what the best
way is. Too bad exceptions don't have a depth property or
something....

It's not really threadsafe either. By the time <something else> is
executed, #meth could have been defined (though you do know it was
undefined at the time of the method call, which is an improvement over
the #respond_to version).

I guess in a sense anything non-atomic is non-threadsafe, but here at
least you know there won't be a fault-line between knowing whether the
object responds to the message, and asking it to do so. The method
call happens all at once, and then everything else sort of falls away
from that.

David

···

On Fri, 23 Dec 2005, Joel VanderWerf wrote:

dblack@wobblini.net wrote:

--
David A. Black
dblack@wobblini.net

"Ruby for Rails", from Manning Publications, coming April 2006!

How about something like this:

  class Exception
    def self.local
      primary = self
      localized = Class.new
      klass = (class << localized; self; end)
      klass.send(:define_method, :===) do |other|
        primary === other and other.depth == 1
      end
      localized
    end

    def depth
      self.backtrace.length
    end
  end

Usage:

  begin
    bar()
  rescue NoMethodError.local => e
  end

  def bar
    foo()
  end

  begin
    bar()
  rescue NoMethodError.local => e
  end

First rescue catches the undefined bar since it's local, second rescue
doesn't catch the undefined foo since it's not local.

Jacob Fugal

···

On 12/22/05, dblack@wobblini.net <dblack@wobblini.net> wrote:

On Fri, 23 Dec 2005, Joel VanderWerf wrote:
> This has the unfortunate side effect of conflating NoMethodErrors that
> are reported for other method calls besides the original obj.meth but
> which occur during that method. What's the best way of handling that?
> Compare exception.backtrace depth with the current backtrace depth?

I guess, but it gets awfully cluttered. I don't know what the best
way is. Too bad exceptions don't have a depth property or
something....

First, thanks all very much for the lively discussion thus far. It's
proven very useful.

Timothy Hunter wrote:

The Integer() method raises ArgumentError if given an empty,
non-numeric, or otherwise non-well-formed string.

Hmm...apparently not--at least not w/ 1.8.2 on mswin32.

This:

  begin
    one, two = ARGV.map{ |n| Integer(n) }
  rescue ArgumentError
    puts "Usage..."
    exit
  end

  puts one
  puts two

Outputs:

  nil
  nil

When fed no command-line arguments. It does work as intended if any of
the args are non-empty strings, however.

Also:

  raise "Hey, '#{ arg }' needs to be a number" if !arg.match(/^\d*$/)

I'm a regexp neophyte, without skill or clue. Any suggestions on
tutorials?

Thanks,

-Matthew

···

--
Posted via http://www.ruby-forum.com/\.

One I've used:

  Regular Expression Tutorial - Learn How to Use Regular Expressions

It's not specific to any language.

···

On Thu, 22 Dec 2005 18:47:04 -0000, Matthew Feadler <matthew@feadler.com> wrote:

I'm a regexp neophyte, without skill or clue. Any suggestions on
tutorials?

--
Ross Bamford - rosco@roscopeco.remove.co.uk

Matthew Feadler wrote:

First, thanks all very much for the lively discussion thus far. It's proven very useful.

Timothy Hunter wrote:

The Integer() method raises ArgumentError if given an empty,
non-numeric, or otherwise non-well-formed string.

Hmm...apparently not--at least not w/ 1.8.2 on mswin32.

This:

  begin
    one, two = ARGV.map{ |n| Integer(n) }
  rescue ArgumentError
    puts "Usage..."
    exit
  end

  puts one
  puts two

Outputs:

  nil

When fed no command-line arguments. It does work as intended if any of the args are non-empty strings, however.

That would be because Integer is never called. If there are no command-line arguments, ARGV is empty, there's nothing to map.

Dunno about tutorials, but:

the / characters indidicate that whatever is between them is a regular
expression.
^ is the beginning of a line (or string)
\d is a digit (i.e. 0 1 2 3 4 5 6 7 8 or 9)
* means to match 0 or more of the previous thing.
$ is the end of the line.

So, /^\d*$/ means that the entire string from beginning to end is
comprised of zero or more digits. So, a minus sign ('-') or any
non-digit somewhere in the string would fail the check.

···

On 12/22/05, Matthew Feadler <matthew@feadler.com> wrote:

First, thanks all very much for the lively discussion thus far. It's
proven very useful.

Timothy Hunter wrote:
> The Integer() method raises ArgumentError if given an empty,
> non-numeric, or otherwise non-well-formed string.

Hmm...apparently not--at least not w/ 1.8.2 on mswin32.

This:

begin
   one, two = ARGV.map{ |n| Integer(n) }
rescue ArgumentError
   puts "Usage..."
   exit
end

puts one
puts two

Outputs:

nil
nil

When fed no command-line arguments. It does work as intended if any of
the args are non-empty strings, however.

Also:

raise "Hey, '#{ arg }' needs to be a number" if !arg.match(/^\d*$/)

I'm a regexp neophyte, without skill or clue. Any suggestions on
tutorials?

Timothy Hunter wrote:

That would be because Integer is never called. If there are no
command-line arguments, ARGV is empty, there's nothing to map.

That makes perfect sense. Thanks.

So, after some experimentation I've got the code listed below. It
successfully checks for:

1.) an empty ARGV (i.e., no command-line args)
2.) more than 2 arguments
3.) non-numeric arguments
4.) negative arguments
5.) first arg greater than second arg

Which is to say, it does everything I want it to. However, I wonder if
it can be optimized, condensed?

Here be code:

$usage = "Usage"

def print_usage val
  if val=="exit"
    print $usage
    exit
  else
    print $usage
  end
end

if ARGV!= and !(ARGV.length > 2)
  begin
    arg0, arg1 = ARGV.map{ |n| Integer(n) }
    if (arg0 < 0) or (arg1 < 0)
      print_usage("exit")
    elsif arg0>arg1
      print_usage("exit")
    end
  rescue ArgumentError
    print_usage("exit")
  end
else
  print_usage("exit")
end

···

--
Posted via http://www.ruby-forum.com/\.

Matthew Feadler wrote:

Which is to say, it does everything I want it to. However, I wonder if
it can be optimized, condensed?

How 'bout corrected first? Guess my last post is a perfect argument in
favor of my learning how to use test units.

Corrected code be here:

$usage = "Usage:"

def print_usage(val)
  if val=="exit"
    print $usage
    exit
  else
    print $usage
  end
end

if ARGV!= and !(ARGV.length > 2)
  begin
    arg0, arg1 = ARGV.map{ |n| Integer(n) }
    if (arg0 < 0) or (!arg1.nil? and (arg1 < 0))
      print_usage("exit")
    elsif !arg1.nil? and (arg0 > arg1)
      print_usage("exit")
    end
  rescue ArgumentError
    print_usage("exit")
  end
else
  print_usage("exit")
end

···

--
Posted via http://www.ruby-forum.com/\.

def read_arguments
  arg0, arg1 = ARGV.map{ |n| Integer(n) }
  raise ArgumentError if arg0.nil? or arg0 < 0
  raise ArgumentError if arg1.nil? or arg1 < 0
  raise ArgumentError if arg0 > arg1
  return arg0, arg1
rescue ArgumentError
  print <<-USAGE
Usage
USAGE
  exit
end

a, b = read_arguments

# Jacob Fugal

Jacob Fugal wrote:

def read_arguments
  arg0, arg1 = ARGV.map{ |n| Integer(n) }
  raise ArgumentError if arg0.nil? or arg0 < 0
  raise ArgumentError if arg1.nil? or arg1 < 0
  raise ArgumentError if arg0 > arg1
  return arg0, arg1
rescue ArgumentError
  print <<-USAGE
Usage
USAGE
  exit
end

a, b = read_arguments

Very nice. I like this construction. However, I believe the above will
throw the exception when I have only one valid arg, which is not what I
want (1 or 2 args is correct; no more, no less).

So, it should look like this, yes?

def read_arguments
  arg0, arg1 = ARGV.map{ |n| Integer(n) }
  raise ArgumentError if (ARGV.length == 0) or (ARGV.length > 2)
  raise ArgumentError if (arg0 < 0) or (!arg1.nil? and (arg1 < 0))
  raise ArgumentError if !arg1.nil? and (arg0 > arg1)
  return arg0, arg1
rescue ArgumentError
  print <<-USAGE
Usage
USAGE
  exit
end

a, b = read_arguments

···

--
Posted via http://www.ruby-forum.com/\.

Write the damn tests, man! :slight_smile:

If it passes the tests, it should work, unless you have faulty tests,
in which case you need more/better tests.

···

On 12/22/05, Matthew Feadler <matthew@feadler.com> wrote:

Jacob Fugal wrote:
> def read_arguments
> arg0, arg1 = ARGV.map{ |n| Integer(n) }
> raise ArgumentError if arg0.nil? or arg0 < 0
> raise ArgumentError if arg1.nil? or arg1 < 0
> raise ArgumentError if arg0 > arg1
> return arg0, arg1
> rescue ArgumentError
> print <<-USAGE
> Usage
> USAGE
> exit
> end
>
> a, b = read_arguments

Very nice. I like this construction. However, I believe the above will
throw the exception when I have only one valid arg, which is not what I
want (1 or 2 args is correct; no more, no less).

So, it should look like this, yes?

def read_arguments
  arg0, arg1 = ARGV.map{ |n| Integer(n) }
  raise ArgumentError if (ARGV.length == 0) or (ARGV.length > 2)
  raise ArgumentError if (arg0 < 0) or (!arg1.nil? and (arg1 < 0))
  raise ArgumentError if !arg1.nil? and (arg0 > arg1)
  return arg0, arg1
rescue ArgumentError
  print <<-USAGE
Usage
USAGE
  exit
end

a, b = read_arguments