Should an error be thrown here? (A Function calls itself)

General FreeBASIC programming questions.
Munair
Posts: 1286
Joined: Oct 19, 2017 15:00
Location: Netherlands
Contact:

Re: Should an error be thrown here? (A Function calls itself)

Post by Munair »

caseih wrote:EDIT: wait a second. Your little screen shot seems to indicate you want a runtime warning. That's simply not possible in FB (nor in C).
It is not a runtime warning. It is a compiler warning while assembler output is being generated.
caseih
Posts: 2157
Joined: Feb 26, 2007 5:32

Re: Should an error be thrown here? (A Function calls itself)

Post by caseih »

Oh gotcha. That wasn't clear at all.

Note that the warning is actually false, though. In your example code there is no possibility of recursion, since the recursive call is in unreachable code. The correct compiler warning would probably want to be something about the fact there is unreachable code.

Anyway it's a unique feature I've not seen anywhere else. I'm sure it's useful to you and people who use SharpBASIC. I don't expect to see in FB, however.
Last edited by caseih on Apr 15, 2020 22:11, edited 1 time in total.
Munair
Posts: 1286
Joined: Oct 19, 2017 15:00
Location: Netherlands
Contact:

Re: Should an error be thrown here? (A Function calls itself)

Post by Munair »

caseih wrote:Note that the warning is actually false, though. In your example code there is no possibility of recursion, since the recursive call is in unreachable code. The correct compiler warning would probably want to be something about the fact there is unreachable code.
No, the code is not unreachable. Unlike FreeBasic, SharpBASIC uses the semicolon as statement terminator. As the comment says, testing an empty return statement without semicolon will include the next line.
caseih
Posts: 2157
Joined: Feb 26, 2007 5:32

Re: Should an error be thrown here? (A Function calls itself)

Post by caseih »

Oh okay. I see. That is definitely a gotcha. I see where you're coming from and why you would need that warning. Such a bug wouldn't happen in FB, hence I don't see a need for the warning.
Munair
Posts: 1286
Joined: Oct 19, 2017 15:00
Location: Netherlands
Contact:

Re: Should an error be thrown here? (A Function calls itself)

Post by Munair »

The reason why I checked FBC's behavior in this is because SharpBASIC is currently being written in FreeBasic, though eventually it's supposed to become a self-hosting compiler.
systemctl
Posts: 182
Joined: Mar 27, 2020 5:15

Re: Should an error be thrown here? (A Function calls itself)

Post by systemctl »

Munair wrote:I'm not here to say that FreeBasic should implement a hint / warning for potential infinite loops, but it would help if a switch could enable it to trace down potential pit falls. And yes, it can be done, as I'm currently developing just that for the SharpBASIC compiler.

Image
Hi. Is it me or anyone else think it's not BASIC but a mix between Python + Go + Pascal?

I think you should give your language another name.
Munair
Posts: 1286
Joined: Oct 19, 2017 15:00
Location: Netherlands
Contact:

Re: Should an error be thrown here? (A Function calls itself)

Post by Munair »

systemctl wrote:Hi. Is it me or anyone else think it's not BASIC but a mix between Python + Go + Pascal?

I think you should give your language another name.
Emphasis is on 'sharp'. And yes, it breaks with BASIC's tradition of verbosity and ambiguity. But it is still BASIC in that it has educational value and that it is easy to understand, even for someone not yet familiar with the language.
paul doe
Moderator
Posts: 1733
Joined: Jul 25, 2017 17:22
Location: Argentina

Re: Should an error be thrown here? (A Function calls itself)

Post by paul doe »

@Munair: B#? XD

I kind of like it. Sometime ago, I tried to spark my 11 yo daughter's curiosity (since she's been watching me doing it ever since she was born), and leverage her interest on the subject when we were 'working' together for the last compo organized by Lachie.

So, I quickly threw together a compiler for a Logo + Forth crossbreed, complete with turtle graphics for her to play with. She picked it up rather quickly, despite my concerns. I thought that the stack concept, along with working with it, were going to give her troubles; it turned out that it prompted some very interesting conversations about why the world at large has adopted infix notation instead of RPN (among other things) since we were studying the basic mathematical notions of term, factor, and parens at the time. Seems like teachers here in Argentina can't be bothered anymore with this kind of stuff...

Unfortunately, like most kids of her generation, her attention span is quite limited so she wrote 2 or 3 programs and decided that coding wasn't for her XD
Munair
Posts: 1286
Joined: Oct 19, 2017 15:00
Location: Netherlands
Contact:

Re: Should an error be thrown here? (A Function calls itself)

Post by Munair »

caseih wrote:The example you gave would not crash with a segmentation fault. Why do you think it would?
Apparently, I overlooked that statement. The code will definitely cause the program to crash because it will run out of stack space, also in FB. Try the following FB code:
Image.

This example, a procedure calling itself is the most obvious. But even if recursion is multiple levels deep and indirect with different procedures in-between, a 'stack' mechanism might be able to keep track of the depth and the procedures involved. By 'stack' I mean that a procedure called by another, is pushed on a list. The called procedure will do the same and so forth and so on. When a procedure ends, it pops off the previous one, which will be current again. Example:

Code: Select all

sub one()
  ' push previous proc (if any)
	pitr.push()
	pitr.proc = current_proc
	
	call two()
	
	' previous proc becomes current again
	pitr.pop()
end sub

sub two()
  
  'push proc 'one' (if it called 'two')
	pitr.push() 
	
	' 'two' becomes current
	pitr.proc = current_proc
	
	call one() ' recursion (if 'two' is called by 'one')
	
	' proc 'one' becomes current (if it called 'two')
	pitr.pop()
end sub
The same mechanism is also used by the SharpBASIC compiler to keep track of nested expressions (so that return types can be determined and checked.

In the case of procedures, the compiler can go through the list with each call and check if the same one has been called before and also how many times. A hint/warning could be raised immediately or after a specific amount of nesting, whatever. Currently SharpBASIC supports a compiler directive 'option norec' to indicate that recursion is not meant to occur or to deliberately raise the warning messages to see where in the program recursion occurs. Unintended recursion can then be tracked more easily.
caseih
Posts: 2157
Joined: Feb 26, 2007 5:32

Re: Should an error be thrown here? (A Function calls itself)

Post by caseih »

Sure you can tack as much runtime checking as you want onto a language. FB has some runtime checking you can enable with -exx, particularly in relation to bounds checking. But if you tack enough on, you'll end up with essentially an interpreter.

I repeat what I've said. I've never seen an actual segmentation fault in the wild from "accidental" recursion, at least the kind a compiler warning would flag. I've seen plenty of crashes from out of bounds referencing, though!

I can also see, however, how syntax choices you made in your SharpBASIC language can lead to such accidental recursion and crash (forgetting a semicolon). But as I mentioned, that kind of bug cannot be made in FB, or C. Personally if I were you I'd warn about the missing semicolon before I'd warn about the recursive call, or better yet make it impossible to make that kind of error. But I can understand and accept your recursion warning in this context.

Can you name any language other than SharpBASIC that can, with the right flag or "strict" option warn about recursion? I can't think of any.

Furthermore, how would you propose to detect and warn about recursive calls where more than one function is involved? Without doing some code path analysis, it's not a simple thing for a compiler. And like I said, the warning would be wrong nearly all the time.
Munair
Posts: 1286
Joined: Oct 19, 2017 15:00
Location: Netherlands
Contact:

Re: Should an error be thrown here? (A Function calls itself)

Post by Munair »

caseih wrote:Sure you can tack as much runtime checking as you want onto a language. FB has some runtime checking you can enable with -exx, particularly in relation to bounds checking. But if you tack enough on, you'll end up with essentially an interpreter.
The example is overly simplified. Actually SharpBASIC is not doing any runtime-checking (yet). The procedure stack happens at compile time when the procedure bodies are parsed. Same goes for nested expressions.
I repeat what I've said. I've never seen an actual segmentation fault in the wild from "accidental" recursion, at least the kind a compiler warning would flag. I've seen plenty of crashes from out of bounds referencing, though!
Beginners definitely make that kind of mistake, and it is easy to make, thinking you return a function's result, but calling it again in the process. Most professional compilers like C, C++ are hardly beginner friendly in this respect.
Personally if I were you I'd warn about the missing semicolon before I'd warn about the recursive call, or better yet make it impossible to make that kind of error. But I can understand and accept your recursion warning in this context.
It is impossible to warn about missing semicolons if the code over several lines is syntactically correct. I made the recursion mistake myself while testing (luckily), which inspired me to support recursion warning.
Can you name any language other than SharpBASIC that can, with the right flag or "strict" option warn about recursion? I can't think of any.
Not that I know of, but that is not an indication. My programming experience is limited to several BASIC and Pascal family languages and a bit of Go. And except for FPC, I have not tested all of them.
Furthermore, how would you propose to detect and warn about recursive calls where more than one function is involved? Without doing some code path analysis, it's not a simple thing for a compiler. And like I said, the warning would be wrong nearly all the time.
I will have to do further testing to see what does and what doesn't work. But at least a comparison can be made against the procedure that started the chain.
caseih
Posts: 2157
Joined: Feb 26, 2007 5:32

Re: Should an error be thrown here? (A Function calls itself)

Post by caseih »

Munair wrote:It is impossible to warn about missing semicolons if the code over several lines is syntactically correct.
Not impossible at all. To the parser the syntax tree looks the same whether its over several lines or one line.
I made the recursion mistake myself while testing (luckily), which inspired me to support recursion warning.
Yes I can see how your chosen syntax would lend itself to making that mistake. But you wouldn't have made that mistake in FB code, since multi-line statements require an explicit continuation character. Hence no warnings are necessary in the FreeBASIC compiler. That's my point really, and the topic of this extended thread.

I can see that you might want a warning in your language. But perhaps you might want to revisit this aspect of your syntax. For example, eliminate the redundant "functionname=result" syntax and just do simply, "return result." You've got the luxury of being able to make this change early on before there's any pre-existing code that depends on it. Doing this would completely prevent this type of problem.

Hopefully you'll get SharpBASIC to the point where you can use it to make itself! That's when the fun begins.
Munair
Posts: 1286
Joined: Oct 19, 2017 15:00
Location: Netherlands
Contact:

Re: Should an error be thrown here? (A Function calls itself)

Post by Munair »

caseih wrote:For example, eliminate the redundant "functionname=result" syntax and just do simply, "return result."
That syntax is not redundant at all. There are times when you want to set the function result before leaving the function, even in FreeBasic:

Code: Select all

function tparse.label_new() as tlabel

	label_new = "_L" + str(lcnt)
	lcnt = lcnt + 1
	
end function
Of course, there are work-arounds, but they always lead to extra code. The return statement often suffices, but it generates a jump instruction to the end of the function, which is not always necessary.
marcov
Posts: 3462
Joined: Jun 16, 2005 9:45
Location: Netherlands
Contact:

Re: Should an error be thrown here? (A Function calls itself)

Post by marcov »

One side of the problem is the double use of "=" for assignment and equality. You might also want to reconsider that.

I also think that I would never choose functioname= syntax for a new language, but rather the result:= syntax, even though it wouldn't matter for this example I think. Simply because when refactoring you have to also rename all instances of it.

Note that depending on FPC mode, an extra () is required for recursion.
caseih
Posts: 2157
Joined: Feb 26, 2007 5:32

Re: Should an error be thrown here? (A Function calls itself)

Post by caseih »

Right, I see what you're saying. Everything involves tradeoffs. Some end up being more costly than others. Your combination of FB-style function return syntax (a return statement as well as a function=expression syntax), the optional end of statement semicolon, the calling of functions without (), and allowing "=" as an assignment operator inside expressions, leads to the problem of accidentally recursively calling your function. Changing even one of those things would eliminate the problem. Given the probability of this being a source of bugs for the programmer, it's worth considering the options to change one or more of those four factors. There's nothing wrong with learning from the mistakes of other languages! Having an improved language is better than a compiler warning any day.

I like Marcov's suggestion of having a standard name for the function result that's not the same as the name of the function. I think other languages do that. FreeBASIC allows you to use "Function=someval" which is a more sensible thing than using the name of the function.
Post Reply