| Home | Forums | Reviews | Guides | Newsgroups | Register | Search |
![]() |
| Thread Tools |
| Lloyd Zusman |
|
|
|
| |
|
Mark Hubbart
Guest
Posts: n/a
|
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? 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 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 |
|
|
|
|
|||
|
|||
| Mark Hubbart |
|
|
|
| |
|
Robert Klemme
Guest
Posts: n/a
|
"Lloyd Zusman" <> schrieb im Newsbeitrag news:... > > 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. > > > > Dare you! > > 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... Regards robert |
|
|
|
|
|||
|
|||
| Robert Klemme |
|
Lloyd Zusman
Guest
Posts: n/a
|
"Robert Klemme" <> writes:
> "Lloyd Zusman" <> schrieb im Newsbeitrag > news:... >> >> [ ... ] >> >> [ ... ] 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... No, not at all. Everything is much appreciated. -- Lloyd Zusman God bless you. |
|
|
|
|
|||
|
|||
| Lloyd Zusman |
|
Robert Klemme
Guest
Posts: n/a
|
"Lloyd Zusman" <> schrieb im Newsbeitrag news:... <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 |
|
Lloyd Zusman
Guest
Posts: n/a
|
"Robert Klemme" <> writes:
> "Lloyd Zusman" <> schrieb im Newsbeitrag > news:... >> >> [ ... ] >> >> 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 God bless you. |
|
|
|
|
|||
|
|||
| Lloyd Zusman |
|
Lloyd Zusman
Guest
Posts: n/a
|
Mark Hubbart <> 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 > > 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 God bless you. |
|
|
|
|
|||
|
|||
| Lloyd Zusman |
|
Robert Klemme
Guest
Posts: n/a
|
"Lloyd Zusman" <> schrieb im Newsbeitrag news:... > "Robert Klemme" <> writes: > > > "Lloyd Zusman" <> schrieb im Newsbeitrag > > news:... > >> > >> [ ... ] > >> > >> 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... > 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 |
|
|
|
|
|||
|
|||
| Robert Klemme |
|
Lloyd Zusman
Guest
Posts: n/a
|
"Robert Klemme" <> writes:
> "Lloyd Zusman" <> schrieb im Newsbeitrag > news:... >> >> [ ... ] >> >> 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. Yes, sync.rb (containing Sync_m and Synchronizer_m) is not mentioned or documented anywhere else that I can find. I'm not sure where I stumbled upon it ... I probably saw it used in someone else's code and then investigated it. Although the mutex and monitor classes also can work here, I prefer Sync_m in this case because its name reflects the exact use to which I am putting it: synchronization. > [ ... ] > > 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... > >> 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. Yes. Here I always want to exit. If I wanted to do something different on exit and on error, I would structure this code snippet differently. >> [ ... ] >> >> Yes, I often do that. It just seems like overkill in my small app. > > Personally I prefer that kind of "overkill" over other strategies. Adding a number of small methods would decrease maintainability of my particular program, IMO. That is not true in general, and I indeed do this on other kinds of projects. However, think that it does apply in this case. But there is plenty of room to differ here. I refactored the code even more, based on our discussions and some ideas of my own. If you're interested, I can privately email you the latest version. -- Lloyd Zusman God bless you. |
|
|
|
|
|||
|
|||
| Lloyd Zusman |
|
Robert Klemme
Guest
Posts: n/a
|
"Lloyd Zusman" <> schrieb im Newsbeitrag news:... > "Robert Klemme" <> writes: > > > "Lloyd Zusman" <> schrieb im Newsbeitrag > > news:... > >> > >> [ ... ] > >> > >> 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. > > Yes, sync.rb (containing Sync_m and Synchronizer_m) is not mentioned or > documented anywhere else that I can find. I'm not sure where I stumbled > upon it ... I probably saw it used in someone else's code and then > investigated it. Although the mutex and monitor classes also can work > here, I prefer Sync_m in this case because its name reflects the exact > use to which I am putting it: synchronization. Monitor and Mutex are also fixed terms in the MT community. It looks, like everyone put his term in here. difference between Monitor and Mutex is that Monitor is reentrant while Mutex is not. As far as I can see Sync and Sync_m are reentrant, too: require 'thread' require 'monitor' require 'sync' [Monitor, Sync, Mutex].each do |cl| x = cl.new puts "outside"; p x begin x.synchronize { puts "first"; p x; x.synchronize { puts "nest"; p x } } rescue Exception => e puts e end end > Adding a number of small methods would decrease maintainability of my > particular program, IMO. That is not true in general, and I indeed do > this on other kinds of projects. However, think that it does apply in > this case. > > But there is plenty of room to differ here. Yeah, often these things are at least partly a matter of taste and individual habit. > I refactored the code even more, based on our discussions and some ideas > of my own. If you're interested, I can privately email you the latest > version. [x] interested [ ] not interested Cheers robert |
|
|
|
|
|||
|
|||
| Robert Klemme |
|
|
|
| |
![]() |
| Thread Tools | |
|
|
Similar Threads
|
||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| Thunderbird 0.7 / 0.8 Forward | Mark Dalgua | Firefox | 1 | 10-22-2004 06:56 AM |
| How to forward ports... | =?Utf-8?B?Y29tZWR5XzE3?= | Wireless Networking | 1 | 08-03-2004 11:45 PM |
| Thunderbird 0.5 doesn't forward attachments + little issue with news | carreg3|j'aime pas le spam| | Firefox | 5 | 04-04-2004 12:59 PM |
| Re-forward declaration of types which were already forward declared | qazmlp | C++ | 1 | 02-15-2004 07:00 PM |
| Hot to change the forward header...? | Marius | Firefox | 0 | 08-27-2003 06:42 PM |
Powered by vBulletin®. Copyright ©2000 - 2013, vBulletin Solutions, Inc..
SEO by vBSEO ©2010, Crawlability, Inc. |




