Forward references?

Is there a way to define forward references to functions? Due to my own
personal eccentricities, I like to have the main body of a program
appear at the top of its source file, and the functions it uses at the
end.

By "define forward reference", I mean something analogous to the
following C construct:

  static char* foo(); /* forward reference */
  static char* bar(); /* forward reference */

  main () {
    printf("%s\n", foo());
    printf("%s\n", bar());
    exit(0);
  }

  char* foo() {
    return ("foo");
  }

  char* bar() {
    return ("bar");
  }

If I could make use of forward references in ruby, the above program
could look something like this:

  # somehow, define a forward reference to function foo()

  # somehow, define a forward reference to function bar()

  # program starts here

  x = foo()
  y = bar()
  puts x
  puts y
  exit(0)

  # real function definitions ...

  def foo
    return "foo"
  end

  def bar
    return "bar"
  end

Am I totally out of luck, or is there some kind of ruby trick I can
perform which will give me this capability?

Thanks in advance.

···

--
Lloyd Zusman
ljz@asfast.com
God bless you.

Lloyd Zusman wrote:

Is there a way to define forward references to functions? Due to my own
personal eccentricities, I like to have the main body of a program
appear at the top of its source file, and the functions it uses at the
end.

By "define forward reference", I mean something analogous to the
following C construct:

static char* foo(); /* forward reference */
static char* bar(); /* forward reference */

main () {
   printf("%s\n", foo());
   printf("%s\n", bar());
   exit(0);
}

char* foo() {
   return ("foo");
}

char* bar() {
   return ("bar");
}

If I could make use of forward references in ruby, the above program
could look something like this:

# somehow, define a forward reference to function foo()

# somehow, define a forward reference to function bar()

# program starts here

x = foo()
y = bar()
puts x
puts y
exit(0)

# real function definitions ...

def foo
   return "foo"
end

def bar
   return "bar"
end

Since Ruby doesn't check whether the functions exist until the code that calls them is actually run, one way to do this would be

def main
  puts foo
  puts bar
  exit(0)
end

def foo
  return "foo"
end

def bar
  return "bar"
end

main

···

--
Mark Sparshatt

Lloyd Zusman wrote:

Is there a way to define forward references to functions? Due to my own
personal eccentricities, I like to have the main body of a program
appear at the top of its source file, and the functions it uses at the
end.

By "define forward reference", I mean something analogous to the
following C construct:

  static char* foo(); /* forward reference */
  static char* bar(); /* forward reference */

  main () {
    printf("%s\n", foo());
    printf("%s\n", bar());
    exit(0);
  }

  char* foo() {
    return ("foo");
  }

  char* bar() {
    return ("bar");
  }

If I could make use of forward references in ruby, the above program
could look something like this:

  # somehow, define a forward reference to function foo()

  # somehow, define a forward reference to function bar()

  # program starts here
  x = foo()
  y = bar()
  puts x
  puts y
  exit(0)

Wrap this code into a END block:

END {
   x = foo
   y = bar
   ...
}

Regards,

   Michael

"Lloyd Zusman" <ljz@asfast.com> schrieb im Newsbeitrag
news:d62dd0tu.fsf@asfast.com...

Is there a way to define forward references to functions? Due to my own
personal eccentricities, I like to have the main body of a program
appear at the top of its source file, and the functions it uses at the
end.

By "define forward reference", I mean something analogous to the
following C construct:

  static char* foo(); /* forward reference */
  static char* bar(); /* forward reference */

  main () {
    printf("%s\n", foo());
    printf("%s\n", bar());
    exit(0);
  }

  char* foo() {
    return ("foo");
  }

  char* bar() {
    return ("bar");
  }

If I could make use of forward references in ruby, the above program
could look something like this:

  # somehow, define a forward reference to function foo()

  # somehow, define a forward reference to function bar()

  # program starts here

  x = foo()
  y = bar()
  puts x
  puts y
  exit(0)

  # real function definitions ...

  def foo
    return "foo"
  end

  def bar
    return "bar"
  end

Am I totally out of luck, or is there some kind of ruby trick I can
perform which will give me this capability?

Just define them duplicately, the first time with an empty body:

# "prototypes"
def foo;end
def bar(name)end

# main stuff
x = foo()
y = bar()
puts x
puts y
exit 0

# "functions"
def foo
  # foodoo
end

def bar(name)
  # bardo
end

Regards

    robert

Lloyd Zusman wrote:

Is there a way to define forward references to functions? Due to my own
personal eccentricities, I like to have the main body of a program
appear at the top of its source file, and the functions it uses at the
end.

In ruby, function definitions are code that gets executed, rather than declarations that get found in the source file and put into a table.
So basically, the definitions have to come before the code that uses them (but not before the definition of the methods that use them) in the program flow. Therefore, if you want the main code at the top of the file, put it in an END block or a method as already mentioned, or in a separate file etc.
Defining stubs at the top won't work, because your main code runs before the methods are redefined.
Sam

One other way is to use blocks:

# code that does this:
def chunk(&block) ($CHUNKS||=) << block end
END{ $CHUNKS.reverse_each{|ch| ch } }
# end special code :slight_smile:

chunk do

   x = foo()
   y = bar()
   puts x
   puts y
   exit(0)

end

chunk do

   def foo
     return "foo"
   end

   def bar
     return "bar"
   end

end

Of course, you'd name it something other than chunk. And there's probly a one liner for it, too, but I didn't have enough time to clean it up much.

cheers,
Mark

···

On Jul 30, 2004, at 7:31 AM, Lloyd Zusman wrote:

Is there a way to define forward references to functions? Due to my own
personal eccentricities, I like to have the main body of a program
appear at the top of its source file, and the functions it uses at the
end.

By "define forward reference", I mean something analogous to the
following C construct:

  static char* foo(); /* forward reference */
  static char* bar(); /* forward reference */

  main () {
    printf("%s\n", foo());
    printf("%s\n", bar());
    exit(0);
  }

  char* foo() {
    return ("foo");
  }

  char* bar() {
    return ("bar");
  }

If I could make use of forward references in ruby, the above program
could look something like this:

  # somehow, define a forward reference to function foo()

  # somehow, define a forward reference to function bar()

  # program starts here

  x = foo()
  y = bar()
  puts x
  puts y
  exit(0)

  # real function definitions ...

  def foo
    return "foo"
  end

  def bar
    return "bar"
  end

Am I totally out of luck, or is there some kind of ruby trick I can
perform which will give me this capability?

Michael Neumann <mneumann@ntecs.de> writes:

Lloyd Zusman wrote:

Is there a way to define forward references to functions? Due to my own
personal eccentricities, I like to have the main body of a program
appear at the top of its source file, and the functions it uses at the
end.

[ ... ]

Wrap this code into a END block:

END {
   x = foo
   y = bar
   ...
}

Aha! And this got me to think of a similar way to do it that is even
more C-like:

  def main
    puts foo
    puts bar
    exit(0) # or it could be this: return (0)
  end

  def foo
    return "foo"
  end

  def bar
    return "bar"
  end

  END { exit(main) }
  # ... or without the END block as long as the last line of
  # the file is exit(main)
  
Thank you very much!

···

Regards,

   Michael

--
Lloyd Zusman
ljz@asfast.com
God bless you.

"Robert Klemme" <bob.news@gmx.net> writes:

"Lloyd Zusman" <ljz@asfast.com> schrieb im Newsbeitrag
news:d62dd0tu.fsf@asfast.com...

Is there a way to define forward references to functions? Due to my own
personal eccentricities, I like to have the main body of a program
appear at the top of its source file, and the functions it uses at the
end.

[ ... ]

Just define them duplicately, the first time with an empty body:

# "prototypes"
def foo;end
def bar(name)end

# main stuff
x = foo()
y = bar()
puts x
puts y
exit 0

# "functions"
def foo
  # foodoo
end

def bar(name)
  # bardo
end

Thank you very much, but this doesn't appear to work. Here's what I
tried:

  def foo;puts "forward ref of foo";end
  def bar(arg);puts "forward ref of bar(#{arg})";end

  foo()
  bar('abc')
  exit(0);

  def foo
    puts "foo"
  end

  def bar(arg)
    puts "bar: #{arg}"
  end

When I ran it, it produced the following output:

  forward ref of foo
  forward ref of bar(abc)

In other words, the second function definitions did not override the
first ones.

···

--
Lloyd Zusman
ljz@asfast.com
God bless you.

Sam McCall <tunah.usenet@tunah.net> writes:

Lloyd Zusman wrote:

Is there a way to define forward references to functions? Due to my own
personal eccentricities, I like to have the main body of a program
appear at the top of its source file, and the functions it uses at the
end.

In ruby, function definitions are code that gets executed, rather than
declarations that get found in the source file and put into a table.
So basically, the definitions have to come before the code that uses
them (but not before the definition of the methods that use them) in the
program flow. Therefore, if you want the main code at the top of the
file, put it in an END block or a method as already mentioned, or in a
separate file etc.
Defining stubs at the top won't work, because your main code runs before
the methods are redefined.
Sam

Thank you very much, and thanks to all the rest of you for your helpful
replies. Based on all this, I have settled on the following approach,
which I have mentioned earlier in this thread:

  def main
    # my main routine

···

#
    # ... etc. ...
    #
    return (exitcode) ### or this: exit(exitcode)
  end

  def function1
    # ... etc. ...
  end

  def function2
    # ... etc. ...
  end

  # other functions ...

  # final line ...
  exit(main)

--
Lloyd Zusman
ljz@asfast.com
God bless you.

Mark Hubbart <discord@mac.com> writes:

[ ... ]

One other way is to use blocks:

# code that does this:
def chunk(&block) ($CHUNKS||=) << block end
END{ $CHUNKS.reverse_each{|ch| ch } }
# end special code :slight_smile:

chunk do

   x = foo()
   y = bar()
   puts x
   puts y
   exit(0)

end

chunk do

   def foo
     return "foo"
   end

   def bar
     return "bar"
   end

end

Of course, you'd name it something other than chunk. And there's probly
a one liner for it, too, but I didn't have enough time to clean it up
much.

This is probably a bit hard to maintain due to its not-so-obvious
algorithm. But it's clever!

Thank you very much.

···

--
Lloyd Zusman
ljz@asfast.com
God bless you.

"Lloyd Zusman" <ljz@asfast.com> schrieb im Newsbeitrag
news:1xit1d8o.fsf@asfast.com...

"Robert Klemme" <bob.news@gmx.net> writes:

> "Lloyd Zusman" <ljz@asfast.com> schrieb im Newsbeitrag
> news:d62dd0tu.fsf@asfast.com...
>> Is there a way to define forward references to functions? Due to my

own

>> personal eccentricities, I like to have the main body of a program
>> appear at the top of its source file, and the functions it uses at the
>> end.
>>
>> [ ... ]
>
> Just define them duplicately, the first time with an empty body:
>
> # "prototypes"
> def foo;end
> def bar(name)end
>
> # main stuff
> x = foo()
> y = bar()
> puts x
> puts y
> exit 0
>
> # "functions"
> def foo
> # foodoo
> end
>
> def bar(name)
> # bardo
> end
>

Thank you very much, but this doesn't appear to work. Here's what I
tried:

  def foo;puts "forward ref of foo";end
  def bar(arg);puts "forward ref of bar(#{arg})";end

  foo()
  bar('abc')
  exit(0);

  def foo
    puts "foo"
  end

  def bar(arg)
    puts "bar: #{arg}"
  end

When I ran it, it produced the following output:

  forward ref of foo
  forward ref of bar(abc)

In other words, the second function definitions did not override the
first ones.

Indeed. Darn, should've done a real test - and not just a mental test. I'm
sorry. I guess the lession to learn here is, just don't do it. Or use
comments as prototypes.

Regards

    robert

"Lloyd Zusman" <ljz@asfast.com> schrieb im Newsbeitrag
news:m3wu0l6kpd.fsf@asfast.com...

Sam McCall <tunah.usenet@tunah.net> writes:

> Lloyd Zusman wrote:
>> Is there a way to define forward references to functions? Due to my

own

>> personal eccentricities, I like to have the main body of a program
>> appear at the top of its source file, and the functions it uses at the
>> end.
> In ruby, function definitions are code that gets executed, rather than
> declarations that get found in the source file and put into a table.
> So basically, the definitions have to come before the code that uses
> them (but not before the definition of the methods that use them) in the
> program flow. Therefore, if you want the main code at the top of the
> file, put it in an END block or a method as already mentioned, or in a
> separate file etc.
> Defining stubs at the top won't work, because your main code runs before
> the methods are redefined.
> Sam

Thank you very much, and thanks to all the rest of you for your helpful
replies. Based on all this, I have settled on the following approach,
which I have mentioned earlier in this thread:

  def main
    # my main routine
    #
    # ... etc. ...
    #
    return (exitcode) ### or this: exit(exitcode)
  end

  def function1
    # ... etc. ...
  end

  def function2
    # ... etc. ...
  end

  # other functions ...

  # final line ...
  exit(main)

Sorry, but I get the feeling that you are trying to make Ruby similar to C
too much. IMHO the result is worse than straight ruby code. Let Ruby be
Ruby and C be C. :slight_smile:

Kind regards

    robert

"Robert Klemme" <bob.news@gmx.net> writes:

"Lloyd Zusman" <ljz@asfast.com> schrieb im Newsbeitrag
news:m3wu0l6kpd.fsf@asfast.com...

[ ... ]

  def main
    # my main routine
    #
    # ... etc. ...
    #
    return (exitcode) ### or this: exit(exitcode)
  end

  def function1
    # ... etc. ...
  end

  def function2
    # ... etc. ...
  end

  # other functions ...

  # final line ...
  exit(main)

Sorry, but I get the feeling that you are trying to make Ruby similar to C
too much. IMHO the result is worse than straight ruby code. Let Ruby be
Ruby and C be C. :slight_smile:

I just want to have my program's main body at the top of the program
file, and the subsidiary functions at the end. The only thing C-like
about this is the fact that I chose the word "main" for the routine that
houses the main body of code.

This construct is not necessary. I could just as easily name the main
routine as "foobar", and it would look less C-like without losing the
fact that the main body of the code comes first in the program file.

Never fear ... the code that I write tends to look ruby-ish and not
C-like. :slight_smile:

···

Kind regards

    robert

--
Lloyd Zusman
ljz@asfast.com
God bless you.

"Lloyd Zusman" <ljz@asfast.com> schrieb im Newsbeitrag
news:m3n01g5p5c.fsf@asfast.com...

"Robert Klemme" <bob.news@gmx.net> writes:

> "Lloyd Zusman" <ljz@asfast.com> schrieb im Newsbeitrag
> news:m3wu0l6kpd.fsf@asfast.com...
>>
>> [ ... ]
>>
>> def main
>> # my main routine
>> #
>> # ... etc. ...
>> #
>> return (exitcode) ### or this: exit(exitcode)
>> end
>>
>> def function1
>> # ... etc. ...
>> end
>>
>> def function2
>> # ... etc. ...
>> end
>>
>> # other functions ...
>>
>> # final line ...
>> exit(main)
>
> Sorry, but I get the feeling that you are trying to make Ruby similar to

C

> too much. IMHO the result is worse than straight ruby code. Let Ruby

be

> Ruby and C be C. :slight_smile:

I just want to have my program's main body at the top of the program
file, and the subsidiary functions at the end. The only thing C-like
about this is the fact that I chose the word "main" for the routine that
houses the main body of code.

This construct is not necessary. I could just as easily name the main
routine as "foobar", and it would look less C-like without losing the
fact that the main body of the code comes first in the program file.

Here's another idea: put your code into two files and require (or load) the
helper code.

Or put your helper code after __END__ and use eval to compile it:

eval DATA.read

p foo()
p bar()

__END__

def foo
  "foo"
end

def bar
  "bar"
end

Never fear ... the code that I write tends to look ruby-ish and not
C-like. :slight_smile:

Dare you! :slight_smile:

Kind regards

    robert

"Robert Klemme" <bob.news@gmx.net> writes:

"Lloyd Zusman" <ljz@asfast.com> schrieb im Newsbeitrag
news:m3n01g5p5c.fsf@asfast.com...

[ ... ]

I just want to have my program's main body at the top of the program
file, and the subsidiary functions at the end. The only thing C-like
about this is the fact that I chose the word "main" for the routine that
houses the main body of code.

This construct is not necessary. I could just as easily name the main
routine as "foobar", and it would look less C-like without losing the
fact that the main body of the code comes first in the program file.

Here's another idea: put your code into two files and require (or load) the
helper code.

I know that I can do that. But often I just want one file. I believe
that the best use of `require' or `load' is to include code from shared
libraries. Putting simple subsidiary routines in one or more separate
files often complicates installation and maintenance.

Or put your helper code after __END__ and use eval to compile it:

[ ... etc. ... ]

That can work, but if I ever want to put real data after __END__ and
read it via the DATA handle, I'd be out of luck.

Never fear ... the code that I write tends to look ruby-ish and not
C-like. :slight_smile:

Dare you! :slight_smile:

OK. Attached is a ruby program that I recently wrote. It is a
specialized "tail -f". In addition to standard "tail -f" capabilities,
it also can simultaneously tail multiple files, and in addition, it will
detect if a new file has replaced the one that is being tailed, in which
case it starts tailing the newly created file automatically.

The second feature is useful when I'm tailing log files that get
recycled. For example, if syslog always writes log data to a file
called, say, "foobar.log", and if once a day the following commands are
run ...

  /bin/rm -f foobar.log.old
  /bin/mv foobar.log foobar.log.old
  kill -HUP $pid # where $pid is the process ID for syslogd

... then after these commands are invoked, syslog will start writing
log data to a new, empty "foobar.log" file. If I had done this ...

  tail -f foobar.log

... then I would keep looking at the no-longer-changing "foobar.log.old"
file after the log files are recycled. But if I invoke my new command
(which I call "rtail") as follows ...

  rtail foobar.log

... then once the logs are recycled, the data that is being added to
"foobar.log" will continue to appear in real time.

Here's the code ...

rtail (9.5 KB)

"Lloyd Zusman" <ljz@asfast.com> schrieb im Newsbeitrag
news:m33c383xee.fsf@asfast.com...

> Here's another idea: put your code into two files and require (or load)

the

> helper code.

I know that I can do that. But often I just want one file. I believe
that the best use of `require' or `load' is to include code from shared
libraries. Putting simple subsidiary routines in one or more separate
files often complicates installation and maintenance.

True. It's a tradeoff: it seemed to me that having prototypes was a
paramount requirement of you.

> Or put your helper code after __END__ and use eval to compile it:
>
> [ ... etc. ... ]

That can work, but if I ever want to put real data after __END__ and
read it via the DATA handle, I'd be out of luck.

Yes, of course.

>> Never fear ... the code that I write tends to look ruby-ish and not
>> C-like. :slight_smile:
>
> Dare you! :slight_smile:

OK. Attached is a ruby program that I recently wrote. It is a
specialized "tail -f". In addition to standard "tail -f" capabilities,
it also can simultaneously tail multiple files, and in addition, it will
detect if a new file has replaced the one that is being tailed, in which
case it starts tailing the newly created file automatically.

<snip/>

Here's the code ...

Very nice! I like especially the documentation. Some remarks from cursory
glancing though:

- I would not use Thread.critical since it is error prone. *If* you use
it, you should use this idiom, because it ensures that Thread.critical is
reset properly:

Thread.critical = true
begin
  # stuff
ensure
  Thread.critical = false
end

But, in your example this is superior:

require 'monitor'
# My list of threads.
$fileThreads = .extend MonitorMixin
# later
$fileThreads.synchronize do
  # do stuff with $fileThreads
end

- You are using exit a bit too much IMHO, especially since you have
"exit(rtail)" but rtail invokes exit, too. Usage of exit reduces
reusability of code and thus I would limit it to the to level of the script,
something like

begin
  # do MAIN stuff
  exit 0
rescue Exception => e
  $stderr.puts e
  exit 1
end

  And within the rest of the script I'd use exceptions. Patterns like this
are inferior

    begin
      block = self.read(testsize)
    rescue
      return false
    end
    # further code that works with block

Instead put all the code for the clean case into the block or leave the
rescue completely out here and handle the exception on a higher level. That
makes things much easier.

- There is File.split:

# old: $program = $0.sub(/^.*\//, '')
$dir, $program = File.split $0

I hope, that was not too frustrating... :slight_smile:

Regards

    robert

"Robert Klemme" <bob.news@gmx.net> writes:

"Lloyd Zusman" <ljz@asfast.com> schrieb im Newsbeitrag
news:m33c383xee.fsf@asfast.com...

[ ... ]

[ ... ] Putting simple subsidiary routines in one or more separate
files often complicates installation and maintenance.

True. It's a tradeoff: it seemed to me that having prototypes was a
paramount requirement of you.

Well, actually, what's important (or at least desirable) to me is not
prototypes in and of themselves, but rather, just to have the main body
of the code near the top of the file.

[ ... ]

Very nice! [ ... ]

Thank you.

[ ... ] I like especially the documentation. Some remarks from cursory
glancing though:

require 'monitor'
# My list of threads.
$fileThreads = .extend MonitorMixin
# later
$fileThreads.synchronize do
  # do stuff with $fileThreads
end

Why not just use the 'sync' module that is already being utilized in
the program? i.e. ...

  $fileThreads = .extend(Sync_m)

- You are using exit a bit too much IMHO, especially since you have
"exit(rtail)" but rtail invokes exit, too. Usage of exit reduces
reusability of code and thus I would limit it to the to level of the script,
something like

begin
  # do MAIN stuff
  exit 0
rescue Exception => e
  $stderr.puts e
  exit 1
end

Thanks. But how about this slight variation? Since I had exit(rtail),
I could just do it this way ...

  # at the bottom of the script ...
  begin
    rtail
    result = 0
    # or if I want: result = rtail
  rescue Exception => e
    $stderr.puts("!!! #{e}")
    result = 1
  end
  exit(result)

... and then raise exceptions every other place where I was using 'exit'.

  And within the rest of the script I'd use exceptions. Patterns like this
are inferior

    begin
      block = self.read(testsize)
    rescue
      return false
    end
    # further code that works with block

Instead put all the code for the clean case into the block or leave the
rescue completely out here and handle the exception on a higher level. That
makes things much easier.

Yes, that's a good approach in many cases, and I will do so in those
instances. However, in a few places, I have different kinds of 'rescue'
responses for different steps within the flow of control. Look at
$fileReadProc in my program, for example. I want my error message to
distinguish between "unable to open", "unable to stat", "invalid
device", etc., and I want to use my own error message text for each of
these instances. I don't see how to avoid a series of short
begin/rescue/end blocks in this case.

Hmm ... well, I could do this, but I don't like it:

  $errorMessage = 'unknown error'
  begin
    $errorMessage = 'unable to open'
    # open the file
    $errorMessage = 'invalid device'
    # do stuff that fails if the item is not a file
    $errorMessage = 'unable to stat'
    # do stat-related stuff
    $errorMessage = 'message for next likely exception to be raised'
    # ... etc. ...
  rescue
    begin
      f.close
    rescue
      # file may or may not be open when exception occurs
    end
    output([nil, "!!! #{$errorMessage}: #{item}]")
    abortMyself()
  end

In the case I have shown here, I prefer the smaller begin/rescue/end
blocks, even though that's more verbose. It will be clearer to future
maintainers.

- There is File.split:

# old: $program = $0.sub(/^.*\//, '')
$dir, $program = File.split $0

Yes. I'm just in the habit of doing this myself, especially when I
don't want the '$dir' part.

I hope, that was not too frustrating... :slight_smile:

No, not at all. Everything is much appreciated.

···

--
Lloyd Zusman
ljz@asfast.com
God bless you.

"Lloyd Zusman" <ljz@asfast.com> schrieb im Newsbeitrag
news:m3fz7711m6.fsf@asfast.com...

<snip/>

> [ ... ] I like especially the documentation. Some remarks from cursory
> glancing though:
>
> require 'monitor'
> # My list of threads.
> $fileThreads = .extend MonitorMixin
> # later
> $fileThreads.synchronize do
> # do stuff with $fileThreads
> end

Why not just use the 'sync' module that is already being utilized in
the program? i.e. ...

  $fileThreads = .extend(Sync_m)

Oh, I overlooked that. Is that std Ruby? (Monitor and Mutex are)

> - You are using exit a bit too much IMHO, especially since you have
> "exit(rtail)" but rtail invokes exit, too. Usage of exit reduces
> reusability of code and thus I would limit it to the to level of the

script,

> something like
>
> begin
> # do MAIN stuff
> exit 0
> rescue Exception => e
> $stderr.puts e
> exit 1
> end

Thanks. But how about this slight variation? Since I had exit(rtail),
I could just do it this way ...

  # at the bottom of the script ...
  begin
    rtail
    result = 0
    # or if I want: result = rtail
  rescue Exception => e
    $stderr.puts("!!! #{e}")
    result = 1
  end
  exit(result)

I prefer this:

  # at the bottom of the script ...
  begin
    exit rtail
  rescue Exception => e
    $stderr.puts("!!! #{e}")
    exit 1
  end

because it's more robust if you change your mind and want to do different
things (like not exiting). It keeps information more local. Maybe this is
a habit I got from Java because compilers can warn you if you put the exit
(or return for methods) into their respective neighborhood and forget one of
them.

.. and then raise exceptions every other place where I was using 'exit'.

Yes, definitely.

> And within the rest of the script I'd use exceptions. Patterns like

this

> are inferior
>
> begin
> block = self.read(testsize)
> rescue
> return false
> end
> # further code that works with block
>
> Instead put all the code for the clean case into the block or leave the
> rescue completely out here and handle the exception on a higher level.

That

> makes things much easier.

Yes, that's a good approach in many cases, and I will do so in those
instances. However, in a few places, I have different kinds of 'rescue'
responses for different steps within the flow of control. Look at
$fileReadProc in my program, for example. I want my error message to
distinguish between "unable to open", "unable to stat", "invalid
device", etc., and I want to use my own error message text for each of
these instances. I don't see how to avoid a series of short
begin/rescue/end blocks in this case.

Hmm ... well, I could do this, but I don't like it:

  $errorMessage = 'unknown error'
  begin
    $errorMessage = 'unable to open'
    # open the file
    $errorMessage = 'invalid device'
    # do stuff that fails if the item is not a file
    $errorMessage = 'unable to stat'
    # do stat-related stuff
    $errorMessage = 'message for next likely exception to be raised'
    # ... etc. ...
  rescue
    begin
      f.close
    rescue
      # file may or may not be open when exception occurs
    end
    output([nil, "!!! #{$errorMessage}: #{item}]")
    abortMyself()
  end

In the case I have shown here, I prefer the smaller begin/rescue/end
blocks, even though that's more verbose. It will be clearer to future
maintainers.

It will be even clearer if you break this code up into multiple method
invocations. Then you'll have methods like:

begin
  File.open("foo.txt") do |io|
    # IO is open here
    # do more stuff
  end
rescue Errno::Enoent => e
  $stderr.puts "ERROR: ..."
rescue OtherError => e
  ...
end

Reusing a global (!) for the current error message looks irritating to me.
A global is not really needed here. And having a single rescue clause for
multiple errors doesn't look good to me either.

> - There is File.split:
>
> # old: $program = $0.sub(/^.*\//, '')
> $dir, $program = File.split $0

Yes. I'm just in the habit of doing this myself, especially when I
don't want the '$dir' part.

Then you can do
$prog = File.split($0)[1]

Advantage of File.split is that it's platform independend. Only introduce
platform dependencies that are really necessary - that might make your life
much easier in the future.

Kind regards

    robert

"Robert Klemme" <bob.news@gmx.net> writes:

"Lloyd Zusman" <ljz@asfast.com> schrieb im Newsbeitrag
news:m3fz7711m6.fsf@asfast.com...

[ ... ]

Why not just use the 'sync' module that is already being utilized in
the program? i.e. ...

  $fileThreads = .extend(Sync_m)

Oh, I overlooked that. Is that std Ruby? (Monitor and Mutex are)

Sync_m has been around ever since 1.6.x, and it's excplicitly mentioned
in the Pickaxe book (on page 120, the last line of the "Condition
Variables" section of Chapter 11, "Threads and Processes"). You can see
the code in RUBYINSTALLDIR/lib/sync.rb

Thanks. But how about this slight variation? Since I had exit(rtail),
I could just do it this way ...

  # at the bottom of the script ...
  begin
    rtail
    result = 0
    # or if I want: result = rtail
  rescue Exception => e
    $stderr.puts("!!! #{e}")
    result = 1
  end
  exit(result)

I prefer this:

  # at the bottom of the script ...
  begin
    exit rtail
  rescue Exception => e
    $stderr.puts("!!! #{e}")
    exit 1
  end

because it's more robust if you change your mind and want to do different
things (like not exiting). It keeps information more local. Maybe this is
a habit I got from Java because compilers can warn you if you put the exit
(or return for methods) into their respective neighborhood and forget one of
them.

??? In your case, the problem you mentioned (forgetting exit or return)
seems _more_ likely, since you explicitly code 'exit' in two places. In
my version, it only appears once. Using your construct ...

  # at the bottom of the script ...
  begin
    exit rtail
  rescue Exception => e
    $stderr.puts("!!! #{e}")
    ###exit 1
    accidentally_forget_to_exit()
  end

If I want to do something other than exiting, then I can do the
following with my construct:

   # at the bottom of the script ...
   begin
     result = rtail
   rescue Exception => e
     $stderr.puts("!!! #{e}")
     result = 1
   end
   ###exit(result)
   do_something_other_than_exiting(result)

It will be even clearer if you break this code up into multiple method
invocations. Then you'll have methods like:

begin
  File.open("foo.txt") do |io|
    # IO is open here
    # do more stuff
  end
rescue Errno::Enoent => e
  $stderr.puts "ERROR: ..."
rescue OtherError => e
  ...
end

Yes, I often do that. It just seems like overkill in my small app.

Reusing a global (!) for the current error message looks irritating to
me.

Yep. That's why I said that I don't like it. I gave that example to
show how undesirable it is.

Then you can do
$prog = File.split($0)[1]

Advantage of File.split is that it's platform independend. Only introduce
platform dependencies that are really necessary - that might make your life
much easier in the future.

Good point. I have now replaced the $0.sub(...) call with this:

  File.basename($0)

I believe that it's better than the File.split version, because it is
giving me exactly what I want: the basename of the file. That makes the
code more self-documenting; and besides, I already use File.basename
elsewhere in the code for the same purpose.

···

--
Lloyd Zusman
ljz@asfast.com
God bless you.

"Lloyd Zusman" <ljz@asfast.com> schrieb im Newsbeitrag
news:m3vfg2tsvl.fsf@asfast.com...

"Robert Klemme" <bob.news@gmx.net> writes:

> "Lloyd Zusman" <ljz@asfast.com> schrieb im Newsbeitrag
> news:m3fz7711m6.fsf@asfast.com...
>>
>> [ ... ]
>>
>> Why not just use the 'sync' module that is already being utilized in
>> the program? i.e. ...
>>
>> $fileThreads = .extend(Sync_m)
>
> Oh, I overlooked that. Is that std Ruby? (Monitor and Mutex are)

Sync_m has been around ever since 1.6.x, and it's excplicitly mentioned
in the Pickaxe book (on page 120, the last line of the "Condition
Variables" section of Chapter 11, "Threads and Processes"). You can see
the code in RUBYINSTALLDIR/lib/sync.rb

Oh, once again learned something new. But as far as I can see it's only
mentioned at this single location - no examples no additional
explanations.

>> Thanks. But how about this slight variation? Since I had

exit(rtail),

>> I could just do it this way ...
>>
>> # at the bottom of the script ...
>> begin
>> rtail
>> result = 0
>> # or if I want: result = rtail
>> rescue Exception => e
>> $stderr.puts("!!! #{e}")
>> result = 1
>> end
>> exit(result)
>
> I prefer this:
>
> # at the bottom of the script ...
> begin
> exit rtail
> rescue Exception => e
> $stderr.puts("!!! #{e}")
> exit 1
> end
>
> because it's more robust if you change your mind and want to do

different

> things (like not exiting). It keeps information more local. Maybe

this is

> a habit I got from Java because compilers can warn you if you put the

exit

> (or return for methods) into their respective neighborhood and forget

one of

> them.

??? In your case, the problem you mentioned (forgetting exit or return)
seems _more_ likely, since you explicitly code 'exit' in two places. In
my version, it only appears once. Using your construct ...

  # at the bottom of the script ...
  begin
    exit rtail
  rescue Exception => e
    $stderr.puts("!!! #{e}")
    ###exit 1
    accidentally_forget_to_exit()
  end

Yeah, but you'll soon recognize that the program does not exit. While
it's more difficult ro recognize that it exits in both cases but you
wanted it to do something else in once case IMHO. Maybe it's a matter of
taste or my usage to Eclipse's excellent Java support which gives you
compile error messages and warnings that help a lot. Of course, Ruby is
not compiled... :slight_smile:

If I want to do something other than exiting, then I can do the
following with my construct:

   # at the bottom of the script ...
   begin
     result = rtail
   rescue Exception => e
     $stderr.puts("!!! #{e}")
     result = 1
   end
   ###exit(result)
   do_something_other_than_exiting(result)

Yeah, but that treats both cases (ok and error) the same and you have to
make a distinction in do_something_other_than_exiting(). That's typically
bad; it's better to have separate methods that handle each case
individually because methods then do just *one* thing and not two. Of
course, if you do the same in every case it's reasonable to have a single
method.

> It will be even clearer if you break this code up into multiple method
> invocations. Then you'll have methods like:
>
> begin
> File.open("foo.txt") do |io|
> # IO is open here
> # do more stuff
> end
> rescue Errno::Enoent => e
> $stderr.puts "ERROR: ..."
> rescue OtherError => e
> ...
> end

Yes, I often do that. It just seems like overkill in my small app.

Personally I prefer that kind of "overkill" over other strategies.

> Reusing a global (!) for the current error message looks irritating to
> me.

Yep. That's why I said that I don't like it. I gave that example to
show how undesirable it is.

Ah, ok.

Good point. I have now replaced the $0.sub(...) call with this:

  File.basename($0)

I believe that it's better than the File.split version, because it is
giving me exactly what I want: the basename of the file. That makes the
code more self-documenting; and besides, I already use File.basename
elsewhere in the code for the same purpose.

Yeah, much better. I didn't think of File#basename.

Kind regards

    robert