Open dgp1130 opened 8 years ago
Done. I've updated the Language Grammar
wiki page to reflect the new changes.
I'm not completely sure of the best way to indent if-statements #OCD. The best I could come up with was:
valid: if a then b
else if c then d
else if e then f
else g
end;
Though that can become hard to read if a single if-then becomes too long. This makes it a little difficult to distinguish a condition from its result however. Only other thing I could really think of:
valid: if a then
reallyLongExpressionOfLotsOfStuff
else if c then
reallyLongExpressionOfLotsOfStuff
else if e then
reallyLongExpressionOfLotsOfStuff
else
reallyLongExpressionOfLotsOfStuff
end;
That works better for long lines, but looks pretty bad for short ones. Of course all if-bodies will only be one expression, so the extra line and indent would be rarely needed. Both of these also use a semicolon on its own line, which I really like for terminating blocks like this without braces but that's certainly not a common notation. I guess it's ultimately up to the programmer, but we'd probably want to have an official style of some kind to encourage best practices.
Regarding a more important topic: there is one possible issue regarding typing. There is the case where the developer writes an if-statement which can return different types. Such as:
if @useBoolean then true else if @useInteger then 1 else "useString" end
This could result in some strange behavior, since different user inputs would dynamically change the type of the if-statement's result. Such a case would generally be either a conceptual error on the part of the programmer, or it would be someone using the dynamic typing with a overloaded operator (technically correct, but very stupid).
if @useInteger then 1 else "hello" end + if @useInteger then 2 else "world" end
// Returns either 3 or "helloworld"
I think the best thing here would be to detect if-statements that return different types and throw a TypeError at compile-time (this is also what the SQL case statement does). Unfortunately, we currently have dynamic typing, so we don't know the type until run-time, making this impossible to detect. On the plus side, #48 will allow us to change that behavior since typing will be explicitly defined in the Uniform code at compile-time. We will need to move our type-checking code from run-time to compile-time and define each operation as returning a certain type.
Just realized, there is one case that could cause issues.
if a then
b
else
if c then
d
else
e
end
end
This makes sense, and should work. There are plenty of reasons to write code like this if the logic works like that conceptually. However this won't parse because we ignore whitespace and there is actually an extra end
token. It would really be parsed like:
if a then
b
else if c then
d
else
e
end // Only one end tag
Logically, the two statements are equivalent, but grammatically the first one is invalid (would throw ParsingError, unexpected token "end"). I'm not sure what to do about this. We definitely shouldn't factor whitespace into parsing and I don't think it's a good idea to allow either number of end
s.
I checked against SQL to see how it addresses this, but it dodges the issue altogether.
case a
when b then c
when d then e
else f
end
It uses when
as an else if
so there is no ambiguity between an else
followed by an if
and an else if
. I guess that explains why they didn't use the far more intuitive if-then syntax we went with. I definitely don't like their syntax, but I can't think of a better way of phrasing it. We could make elseif
one word, that would allow the parser to distinguish between the two cases. Unfortunately it would be very easy to add a space when it shouldn't be there and vice versa, which would throw errors at the end
line and be difficult to understand for users. We could use otherwise
in place of else
I suppose, though that would be a little weird and is kind of a long keyword. Not sure what the best course of action is here.
https://docs.oracle.com/cd/B19306_01/server.102/b14200/expressions004.htm
After discussing the issue with Sawyer, we decided to change else if
to elif
. This creates a clear distinction between an elif
and an else
followed by an if
. It is still easy for a user to accidentally use else if
instead of elif
, so I added a warning whenever it detects an else
immediately followed by an if
with no newline between them. The user will still get the "ParsingError: Unexpected token 'end'" error, but it will be accompanied by a warning explicitly calling out their mistake. I definitely think this is the best solution.
I think we overlooked the necessity of an if-statement. It's generally more of an imperative tool, but I think it can still be applicable here. This would work similarly to the SQL case statement.
The
else
clause would be required, because the if statement must return a value, in any case which occurs. An example of this would be counting the number of members of a family.