Well, it took 7 years, but I finally found a use for "goto" outside of BASIC. In my particular case, it was within a Ruby C extension. I wanted to create 'tail -f' functionality for monitoring the Windows event log. It makes sense when you take blocks into consideration. To wit:
e = EventLog.open("Application")The tail method sits in an infinite loop (which is accomplished with the 'goto'), yielding a (custom) struct every time a record is written to the event log.
e.tail{ |rec| puts "Record added to log" p rec }
On a stranger note, the Windows function NotifyChangeEventLog() can only detect a maximum of one change every five seconds. That means, even if 20 records were written to the event log in under 5 seconds, that block would only pick up the first one. No, there's no way around it.
For the record, I know of exactly two necessary uses of goto in Perl.
Re:I don't see the goto
djberg96 on 2004-10-29T22:57:22
static VALUE eventlog_tail(VALUE self){
ELS* ptr;
VALUE rbBlock, rbSource, rbServer;
HANDLE hEvent;
DWORD dwWaitResult;
int rv;
Data_Get_Struct(self,ELS,ptr);
eventblock:
hEvent = CreateEvent(
NULL,// default security attributes
FALSE, // no manual reset
FALSE, // create as not signaled
NULL // no event name
);
rv = NotifyChangeEventLog(ptr->hEventLog, hEvent);
if(0 == rv){
rb_raise(cEventLogError,ErrorDescription(GetLastError()));
}
dwWaitResult = WaitForSingleObject(hEvent, INFINITE);
if(dwWaitResult == WAIT_FAILED){
CloseHandle(hEvent);
rb_raise(cEventLogError,
"WaitForSingleObject() failed in notify() method");
}
else{
VALUE rbLast;
rbSource = rb_iv_get(self,"@source");
rbServer = rb_iv_get(self,"@server");
rbLast = read_last_event(ptr->hEventLog,rbSource,rbServer);
if(rb_block_given_p()){
rbBlock = rb_block_proc();
}
else{
rb_raise(cEventLogError,"block missing for notify_change()");
}
rb_funcall(rbBlock,rb_intern("call"),1,rbLast);
}
CloseHandle(hEvent);
goto eventblock;
return self;
}Re:I don't see the goto
btilly on 2004-10-30T00:59:48
First of all that is written in C, not Ruby. There are a number of situations where you need a goto in C that you wouldn't in Perl or Ruby because of the availability of named loop control.
Secondly I don't see why you aren't using while to get the infinite loop rather than goto.
Thirdly you can save some lines by not always using braces. For instance:if(rb_block_given_p())
rbBlock = rb_block_proc();
else
rb_raise(cEventLogError,"block missing for notify_change()");Re:I don't see the goto
djberg96 on 2004-10-30T02:27:32
First of all that is written in C, not Ruby.I said is was a C extension for Ruby. I showed you the frontend. The C code above is the backend.
Secondly I don't see why you aren't using while to get the infinite loop rather than goto.
I suppose I could have done while(1) or something. It just didn't feel right.
Thirdly you can save some lines by not always using braces.
I hate that, sorry.
Re:I don't see the goto
btilly on 2004-10-30T02:54:41
1, 3. Fair points.About the second. I'd suggest re-reading Go To Statement Considered Harmful. The fact that your indentation and control structures are in conflict makes your program's flow of control harder to understand upon first reading. Even if you aesthetically prefer a goto to an infinite while loop, I'd suggest that you indent from the label to the goto so that that section jumps out at the maintainer.
Re:I don't see the goto
djberg96 on 2004-10-30T03:26:11
I'd suggest that you indent from the label to the goto so that that section jumps out at the maintainer.Roger that.
:)