Open straight-shoota opened 1 year ago
I'm not sure about (a). A
def
without parenthesis cannot have parameters, so this case should be pretty unambiguous.
I agree—at least for Crystal—but it should be noted that this is already enforced in the parser, most likely to mirror Ruby.
For context, it's possible in Ruby to define a parenthesis-less, parameterized method. For example, the following is valid:
def f x
puts x
end
In Crystal, however, this would raise a syntax error because all method headers must have parentheses around parameters.
In both languages, def foo bar end
raises a syntax error. In Ruby, it's impossible to determine whether bar
is a parameter to foo
(def foo(bar) end
) or if foo
is parameterless and calls some bar
method defined elsewhere (def foo() bar end
). In Crystal, bar
cannot be a parameter since it isn't enclosed by parentheses. However, this wouldn't be immediately obvious to a Rubyist who is new to Crystal.
Yeah, it's probably better to be strict about parameterless defs, even though it's technically unambiguous in Crystal.
Actually, the formatter already takes care of removing the potentially ambiguous syntax.
The first example from the OP formats like this:
def foo : Array
(String)
[1]
end
So the alternative is definitely considered ill-formed. But it's actually unambiguous and maybe it's fine to keep accepting it as valid code? If you want your code to be formatted in a sane way, you should use the formatter anyway =)
I believe this is related!
def foo : Int32
switch = true
if switch 10 else 0 end # syntax error: Error: unexpected token: "else"
end
puts foo
The above doesn't compile but with an inserted ;
it prints 10
.
def foo : Int32
switch = true
if switch ; 10 else 0 end # works
end
puts foo
@stefandd switch 10
is interpreted as a function call with args, and else
appears out of nowhere (syntax error). Adding the semicolon tells crystal to not look for args, and it parses correctly.
The compiler currently does not require a clear delimiter between the head and body of a method.
For example,
def foo : Int32 1 end
is valid syntax.There are some oddities:
def foo 1 end
is not valid, butdef foo() 1 end
is.Some typos can cause surprising behaviour. The following code is valid:
The return type restriction is
Array
.(String)
is parsed as the first expression in the method body.A variation of that appears in #6191:
I think requiring an explicit delimiter could improve the last examples because they would lead to (meaningful) syntax errors.
This comment form @FnControlOption in https://github.com/crystal-lang/crystal/pull/11854#issuecomment-1518168910 makes a concrete suggestion:
I'm not sure about (a). A
def
without parenthesis cannot have parameters, so this case should be pretty unambiguous.