Are line label pointers possible?

General FreeBASIC programming questions.
dodicat
Posts: 7987
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Are line label pointers possible?

Post by dodicat »

Surely one valid reason to use goto?

Code: Select all

#cmdline "-exx"
On Error Goto errors
#define MyErrors(x) print #x

Dim As Long Ptr p
p[4]=5
Print "p[4] = ";p[4]

errors:
Select Case Err
Case 0:  MyErrors(No Error) 
Case 1:  MyErrors(Illegal Function Call) 
Case 2:  MyErrors(File Not found signal) 
Case 3:  MyErrors(File I/O Error) 
Case 4:  MyErrors(Out of memory) 
Case 5:  MyErrors(Illegal Resume) 
Case 6:  MyErrors(Out of bounds array Access) 
Case 7:  MyErrors(Null Pointer Access) 
Case 8:  MyErrors(No privileges) 
Case 9:  MyErrors(interrupted signal) 
Case 10:  MyErrors(illegal instruction signal) 
Case 11:  MyErrors(floating Point Error signal) 
Case 12:  MyErrors(segmentation violation signal) 
Case 13:  MyErrors(Termination request signal) 
Case 14:  MyErrors(abnormal termination signal) 
Case 15:  MyErrors(quit request signal) 
Case 16:  MyErrors(Return without Gosub) 
Case 17:  MyErrors(End of file) 
Case Else:MyErrors(undefined Error)
End Select

Sleep 
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Are line label pointers possible?

Post by jj2007 »

caseih wrote: Feb 09, 2022 15:44The problem with catching errors before they occur is that on modern, multi-process, multi-user systems, you can get subtle race conditions. For example files could could changed or pulled out from under you. Between the time it takes your program to check for a file's existence, and then to open it, the file could be erased.
I made a quick test on my 8 year old trusty machine:

Code: Select all

Intel(R) Core(TM) i5-2450M CPU @ 2.50GHz
86 µs for testing existence
40 µs for opening file
16 µs for closing file
42 µs for testing existence
27 µs for opening file
12 µs for closing file
90 µs for testing existence
50 µs for opening file
19 µs for closing file
53 µs for testing existence
33 µs for opening file
14 µs for closing file
45 µs for testing existence
32 µs for opening file
14 µs for closing file
45 µs for testing existence
30 µs for opening file
14 µs for closing file
42 µs for testing existence
30 µs for opening file
14 µs for closing file
42 µs for testing existence
30 µs for opening file
14 µs for closing file
42 µs for testing existence
43 µs for opening file
16 µs for closing file
48 µs for testing existence
28 µs for opening file
13 µs for closing file
These are microseconds, not milliseconds. IMHO it would need a very, very special setup to make your scenario happen. However, I agree with the rest of your post. If there is a problem in my 22k lines editor, I let it crash, mercilessly - no SEH. Instead, my just-in-time debugger takes over, I look at the most recent calls and try to figure out what caused the crash. Handling exceptions might look nicer to the user, but SEH creates a false feeling of security, and, as you rightly notice, it's very difficult to debug.
marcov
Posts: 3463
Joined: Jun 16, 2005 9:45
Location: Netherlands
Contact:

Re: Are line label pointers possible?

Post by marcov »

Munair wrote: Feb 09, 2022 11:25 As of QuickBASIC 7.1 PDS there was ON LOCAL ERROR GOTO for use in procedures but I don't remember the details. From the FB manual I understand that fbc supports but ignores the LOCAL clause. I haven't actually used it in FB.
Global on goto as a catch all is fine for small potatoe batch stuff. However it is no substitute for exceptions.

The easiest way to imagine the use of exceptions is a long running server like a webserver. Such application have a hardened core somewhere that handles the requests, and calls business code to process them and generate response pages.

Now, not all codepaths of that business code run very often, and you when you encounter an inconsistency you just want to abort.

But the call chain nesting might have descended already several levels, and each level potentially has to do things to restore the status quo to not leave memory leaks or corrupt other state. Some of them might be much used code, some less.

This is what the various do catch and finally stages do. Rewind state on an "special" even so that the long running application can go on without losses. Without manual "asm ret" tuning.

Now try to imagine implementing something like that with a global "on error goto". I might be missing something, but IMHO this is not the same thing.
jj2007 wrote: Feb 09, 2022 12:10

Code: Select all

print "Hello World"
Dim lptr as any ptr

if 0 then
  label1:
  asm mov dword ptr [lptr], offset label1
  print "this is label 1 at ";lptr
  asm ret
endif

asm call label1
print "that was cute"

Sleep
Calling a line label works perfectly, in 32- and 64-bit FB, but I have no idea where and why it could be useful.

Same for ON ERROR GOTO. Occasionally, I use a Try...Catch...Finally construct, but I must be a bit desperate to do that; in 99% of all cases, avoiding errors before they throw an exception is the far better alternative.
See above. While doing an assembler call and matching ret, is a fun experiment, it is in no way a substitute of exceptions which allow a piece of code to handle fixing state (program state but also e.g. allocations, closing files etc) locally when somewhere deeper the call chain aborts with an exception.
Last edited by marcov on Feb 10, 2022 10:35, edited 1 time in total.
caseih
Posts: 2158
Joined: Feb 26, 2007 5:32

Re: Are line label pointers possible?

Post by caseih »

jj2007 wrote: Feb 09, 2022 16:59These are microseconds, not milliseconds. IMHO it would need a very, very special setup to make your scenario happen.
I agree it's not likely something that most FB programmers would probably care about, but I can think of other scenarios where look before you leap will not work. In fact, it's always better to just go ahead and perform the file operation and deal with the error afterwards. There's just no way you as a programmer can anticipate every possible way something might fail in advance. For example, you might check for the existence of a file, but forget to check for write permissions. Or maybe the directory permissions are too restrictive, preventing you from even creating the file in the first place. And in some cases, OS-level mandatory access controls are in effect that aren't even visible to your program. And there are many more scenarios. These are far more likely to bite you than a race condition.
adeyblue
Posts: 301
Joined: Nov 07, 2019 20:08

Re: Are line label pointers possible?

Post by adeyblue »

marcov wrote: Feb 09, 2022 18:26 Global on goto as a catch all is fine for small potatoe batch stuff. However it is no substitute for exceptions.

Plus lots of explanation...
You didn't need to go that far to prove your point. All you needed was:
On (Local) Error Goto doesn't actually work in FB if the Error statement is in a different stack frame than the one that setup the handler.

As in, the goto happens but the stack isn't unwound, so if your Goto handler touches any local variables or tries to do exotic things like 'return', you're very likely going to crash.

To wit, this doesn't work

Code: Select all

Function OpenFile(fileName as String) As Long
    Error 5
    Return 6
End Function

Sub MyFancyFunc()
    On Error Goto ErrorLabel
    dim fileName As String = "nonexistantfile.fil"
    dim number As Long = &H1234
    Print "Normally, fileName = " & fileName & ", number = 0x" & Hex(number)
    dim retVal as Long = OpenFile(fileName)
    Print "OpenFile returned " & Str(retVal)
    Exit Sub

ErrorLabel:
    dim e as Long = Err
    Print "Caught error " & Str(e) & ", fileName = " & fileName & ", number = 0x" & Hex(number)
End Sub

MyFancyfunc()
Print "End of program"
dodicat
Posts: 7987
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Are line label pointers possible?

Post by dodicat »

You wouldn't just jump into error handling, on error goto or a try block, without looking at a help file first.

Remark: Presently, the Local clause (authorized only inside Sub/Function) is ignored by the compiler, and the error handler can be either in the scope of the same procedure the On [Local] Error is in, or in the main part of the module (if defined before the procedure).
Exception if -gen gcc is used: when the On [Local] Error is inside a Sub/Function, the error handler also must always be inside that same procedure.

So on error goto is either in the main block or in each sub, along with it's associated label, or both.
RockTheSchock
Posts: 252
Joined: Mar 12, 2006 16:25

Re: Are line label pointers possible?

Post by RockTheSchock »

I really don't understand why there is any need for on error or goto. I.e. if you use the OpenFile or GetMouse Function you get a return value, which can be checked. You can jump out of any nested loop (FOR,DO,WHILE) by using

Code: Select all

FOR i = 1 TO 10
  FOR j = 1 TO 10
    FOR k = 1 TO 10
      EXIT FOR, FOR, FOR
    NEXT
  NEXT
  PRINT "never gets executed"
NEXT
You have also the statement CONTINUE, which helps to jump over some code at the end of a loop. And there you can control exactly at which level you want to continue your loop:

Code: Select all

CONTINUE FOR, FOR
Let's say you have a procedure writing some records to a file. Convert it to a function which returns 0 on success or an errorcode on failure. The procedure calling your WriteRecords() function should also be converted to a function analogous. The procedure with your mainloop should process all errors returned by your functions.
marcov
Posts: 3463
Joined: Jun 16, 2005 9:45
Location: Netherlands
Contact:

Re: Are line label pointers possible?

Post by marcov »

RockTheSchock wrote: Feb 19, 2022 21:49 I really don't understand why there is any need for on error or goto. I.e. if you use the OpenFile or GetMouse Function you get a return value, which can be checked.
Now such a routine gets changed and adds one more return value and you have to check all your ifs again. Exceptions allow many of the inbetween levels to just react to any exceptions and not all need to understand all the details (just to bring their own world in a consistent state again).
RockTheSchock
Posts: 252
Joined: Mar 12, 2006 16:25

Re: Are line label pointers possible?

Post by RockTheSchock »

marcov wrote: Feb 19, 2022 22:08Now such a routine gets changed and adds one more return value and you have to check all your ifs again. Exceptions allow many of the inbetween levels to just react to any exceptions and not all need to understand all the details (just to bring their own world in a consistent state again).
I know what you mean, but there is no point in using goto unless it is for error handling. At least until there will be some other way of error handling. But as an example of what we are talking about i wrote a little script:

Code: Select all

Function WritingToFile(filename As String, buffer As String) As Integer
Dim As Integer openresult, putresult, closeresult
	
Dim f As Integer	
f = FreeFile

If f>0 Then 'got free handle
   openresult = Open(filename For Binary Access Write As #f)
	If openresult = 0 Then 'Successfully opened file
	   putresult = Put(#f, , buffer)
	   If putresult  = 0 Then 'successful put to file
	   	closeresult=Close(#f)
	   	If closeresult =0 Then 'successful closing file
	   		Return 0
	   	Else
	   		Return closeresult 'error on closing
	   	EndIf
	   Else 'error on put 
	   	Close #f  	
	   	Return putresult 	
		End If
	Else 'error on open
	   Close #f
		Return openresult
	End If
Else 'no free filehandle found
	Return 3 'File I/O error or maybe use custom error code 
End If


End Function


Function GenerateFile(fileName As String, txt As String,code As UByte) As Integer
Dim buffer As String = txt

For i As Integer=0 To Len(buffer)-1
	buffer[i]=(buffer[i]+code) Mod 256 
Next
Return WritingToFile("MyTest.txt", buffer)
End Function


'--------------------------------------
Dim result As Integer
Dim As String text,codestring
Dim As Integer code

Do 
	Line Input "Code: ",codestring
	code=ValInt(codestring) Mod 256
	Print "Code:",code
	Line Input "Text: ",text
	
	If Len(text)>0 Then
		result=GenerateFile("MyTest.txt",text,code)
	End If
Loop Until Len(text)=0 Or result<>0

If Result<>0 Then 
	'Error Handling
EndIf
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Are line label pointers possible?

Post by jj2007 »

Nice example, RockTheSchock :D
Munair
Posts: 1286
Joined: Oct 19, 2017 15:00
Location: Netherlands
Contact:

Re: Are line label pointers possible?

Post by Munair »

If I'm not mistaken

Code: Select all

openresult = Open(filename For Binary Access Write As #f)
returns the same as:

Code: Select all

Open filename For Binary Access Write As #f)
openresult = err
I often use this in combination with a file object like:

Code: Select all

type tfile
  errflg  as integer
  path    as string
  hnd     as integer
  declare sub fopen_read()
end type

sub tfile.fopen_read()
  hnd = freefile
  err = 0 
  open path for input as #hnd
  errflg = err
end sub
marcov
Posts: 3463
Joined: Jun 16, 2005 9:45
Location: Netherlands
Contact:

Re: Are line label pointers possible?

Post by marcov »

RockTheSchock wrote: Feb 20, 2022 1:02 there is no point in using goto unless it is for error handling. At least until there will be some other way of error handling. But as an example of what we are talking about i wrote a little script:
- using a goto out of a nested IF is faster with many compilers. That's not errorhandling, just avoiding a sequence of jumps with one single one.
- There are some applications in lowlevel RTS code that defy the procedural rules, where it keeps more code in HLL before having to resort to assembler.
Munair
Posts: 1286
Joined: Oct 19, 2017 15:00
Location: Netherlands
Contact:

Re: Are line label pointers possible?

Post by Munair »

marcov wrote: Feb 20, 2022 10:21 - using a goto out of a nested IF is faster
or nested loops for that matter (preferably using the same syntax).

I added the jump statement to SharpBASIC today, but to minimize the possibility of spaghetti code the statement is only allowed inside subroutines and functions, which from assembly point of view is also less complex.
speedfixer
Posts: 606
Joined: Nov 28, 2012 1:27
Location: CA, USA moving to WA, USA
Contact:

Re: Are line label pointers possible?

Post by speedfixer »

I second marcov's statement.
GOTO is crucial for exiting a complex series of tests and statements without trying to write or keep track of a bunch of unwinding code or levels of nesting.

david
angros47
Posts: 2329
Joined: Jun 21, 2005 19:04

Re: Are line label pointers possible?

Post by angros47 »

angros47 wrote: Feb 05, 2022 16:17
marcov wrote: Feb 05, 2022 13:20
Conceptually it is possible, but it would hurt optimization chances if you would actually use it. (e.g. the compiler would have to flush all the register variables before such label and before the goto). This because a goto to such pointer would basically have to be a "jmp" instruction, and the state (registers, stack pointer) would have to be the same for the goto <storedpointer> and the label. So basically it probably would change optimization level for that procedure to -O0
This makes sense. Also, a line label can be reached both with GOTO and with GOSUB

Hard but possible for native backend but making gcc understand that would be extremely hard.


I imagined something like that, but I wanted to hear other opinions, too. Doing that in assembly would be pretty simple, doing the same in C is not officially supported. Actually, in gcc it would be pretty easy, because gcc does support line label pointers:

https://gcc.gnu.org/onlinedocs/gcc/Labe ... alues.html

Yet, this is achieved by an extension to the standard C, so if someone needs to use a compiler different from gcc it would not work (and FreeBasic is supposed to work with other C compilers, too, like clang, so it cannot rely on gcc-only features)
Maybe PB ddn't optimize much, and it was simpler for them. (and even then you should check procedures that use them if PB didn't locally disable certain/all optimizations)
I confirm: first, PowerBasic compiles directly to executable, it has much less intermediate passages. Also, many optimizations that are automated in FreeBasic must be done manually (like using a register to represent a variable: http://manmrk.net/tutorials/basic/Power ... tement.htm)
Post Reply