lobster icon indicating copy to clipboard operation
lobster copied to clipboard

Confusing error when there's space between for and opening brace

Open shamrin opened this issue 4 years ago • 7 comments

I'm following through the Shooter tutorial. It's very nicely done, thank you!

However, I've spent 5-10 minutes figuring why Lobster fails when there's space between for and (. I found the error message to be very confusing:

game.lobster(44): error: missing arg to builtin function: for
image

I've even managed to make the same mistake in gl_circle call, but the error message was totally different, and similarly confusing:

game.lobster(48): error: ) expected, found: ,
image

shamrin avatar Oct 14 '19 15:10 shamrin

Yes, that is unfortunate. It uses spacing in this case to distinguish between a regular function call, and a parentheses-less call that uses bracketing for precedence. For example, f (1 + 2) * 3 applies f to the whole expression (no parens for the call), but f(1+ 2) * 3 applies * to the result of the function call.

But yes, this makes for confusing errors. The question is, can this be fixed by special purpose error handling, better docs, or is deciding based on spacing just generally a bad idea (yes, it probably is). It's hard to remove them though, since parens-less calls are essential for making control structures look control-structury.

Opinions welcome.

aardappel avatar Oct 14 '19 23:10 aardappel

I don't have an opinion whether "deciding based on spacing" is a bad idea. Don't know enough about the language.

However, I wonder if Lobster could ban some_function ( sequence altogether. Let's say I've written:

f (1 + 2) * 3

What was my intent? It could be:

  1. I've made a typo. I actually meant f(1 + 2) * 3.
  2. I really wanted to apply f to the whole expression. In this case I could rewrite it as f((1 + 2) * 3).

shamrin avatar Oct 15 '19 07:10 shamrin

The error for f (1 + 2) * 3 could be something like:

game.lobster(48): error: space before (, did you mean `f(1 + 2) * 3`?

shamrin avatar Oct 15 '19 07:10 shamrin

I've searched for it in the Lobster repo: ag '[a-z] \(' tests/ modules/ samples/

Assuming you agree to disallow some_function ( sequence, in almost all of the examples you could either drop extra braces, or remove the space.

The only places I found where you have to add extra braces were the following:

assert (test_namespace_g {}).x == 1

assert (if manhattan(xy { 1, 1 }): xy { 1, 2 } else: xy { 3, 4 }).y == 2

assert (coroutine_for(coroutine refcoro(borrow)): assert(_ + "_" is string)) == "D"

assert (assert parse_data(typeof [bool], "[true]"))[0] == true

After the change:

assert((test_namespace_g {}).x == 1)

assert((if manhattan(xy { 1, 1 }): xy { 1, 2 } else: xy { 3, 4 }).y == 2)

assert((coroutine_for(coroutine refcoro(borrow)): assert(_ + "_" is string)) == "D")

assert((assert parse_data(typeof [bool], "[true]"))[0] == true)

shamrin avatar Oct 15 '19 07:10 shamrin

Lobster's current parsing is so generic, that even if, for and while are parsed as function calls. They have the same syntax as any other functions that take lambda arguments.. the point being that your own functions are on equal footing.

But that does stress that situation. if with your proposal now can either be:

if 1 + 2 < 3:

But now if for whatever reason I need to bracket 1 + 2, I need two sets of brackets, and spacing that is not familiar (it may take new users of Lobster a while to realize if is really a function call):

if((1 + 2) < 3):

Whereas with the current syntax, I can still do:

if (1 + 2) < 3:

One other solution is to simply stop treating the parsing of if (and for / while) as exactly the same as any other function call. This would be less elegant, but it would remove a bunch of warts from the function call parsing that were introduced just to make if look Python-esque. Like you say, most actual function calls can deal with needing (( since it doesn't happen that frequently.

But of course, the problem just shifts, because if I special case these 3, then someone is going to make the same mistake with e.g. map where they expect it to behave similary to for, except then maybe it doesn't.

One way I can think of getting rid of the significant space is to require functions to declare that they take an argument without brackets... but that also sounds kinda kludgy.

aardappel avatar Oct 15 '19 16:10 aardappel

maybe add a pipe operator, similiar to haskell's $ ? just a small thought

argvsc47 avatar May 15 '22 15:05 argvsc47

@argvsc47 that may be nice to add, but does not relate to the discussion above afaik?

aardappel avatar May 15 '22 16:05 aardappel

Checking 4 years later. Space after for is now allowed, very nice!

@aardappel, do you remember what change fixed it?

shamrin avatar Jan 09 '24 12:01 shamrin

What changed since my last comment is that if, for and while are now parsed independently from function calls, which will have fixed this issue for them.

It is still a problem in general, if you make a custom for loop myfor, it will run into your original errors if you put a space after it.. but I guess that doesn't happen as often.

aardappel avatar Jan 09 '24 18:01 aardappel