I was playing around with imperative control structures and had the following code:
type result 'a = {mutable list: list 'a};
let firstN (n: int) (l: list 'a) :list 'a => {
let result: result 'a = {list: []};
let start = 0;
let stop = min (n - 1) (List.length l);
for i in start to stop {
result.list = List.append [List.nth l i] result.list
}
};
The formatter would work, but I'd get a compile error that the return type was unit. That made sense, so I tried to return the result.list:
type result 'a = {mutable list: list 'a};
let firstN (n: int) (l: list 'a) :list 'a => {
let result: result 'a = {list: []};
let start = 0;
let stop = min (n - 1) (List.length l);
for i in start to stop {
result.list = List.append [List.nth l i] result.list
}
result.list;
};
Now the formatter wouldn't work and the compiler said it was looking for a closing block for the for-loop. I was confused and couldn't figure out what was wrong.
The solution ended up being this:
type result 'a = {mutable list: list 'a};
let firstN (n: int) (l: list 'a) :list 'a => {
let result: result 'a = {list: []};
let start = 0;
let stop = min (n - 1) (List.length l);
for i in start to stop {
result.list = List.append [List.nth l i] result.list
};
result.list
};
I noticed that when I put semi-colons at the end of the for loop block and at the end of the List.append expression in the first example, the formatter took them away. By complete coincidence, I put at the end of the for-loop block after putting result.list in there, and ah-ha! it worked.
long story short, semi-colons being omitted from the last expression in a block can cause a lot of confusion! when the formatter gets rid of a semi-colon, I don't expect to have to add it back when I add another line to try to make the compiler happy.
Interestingly, @yunxing and I realized that enforcing final semicolons eliminates some confusion around punning of single field records. Doing so might kill two birds with one stone.
ah, so this _had_ been logged already. I'd also like to see semicolons retained at the end of functions that have multiple expressions to avoid confusion. They are already implicitly mandatory for single-expression functions, due to the lack of braces:
let f = (x) => x + 1;
I don't think you'd get any objection to adding the final semicolons back. Feel free to send a PR (I think this one is pretty easy).
I like more rust's approach on semicolon, it's more similar to ocaml's one, the expression to be returned does not have semicolons
Reason's current parser also does not require the final semicolon. It does, however, print it - and this is so that you can more easily copy/paste lines between easily. Also, printing the final semicolon prepares us to finally accept single field punned records like {this}.
I think I'll close this out unless there's any specific request in light of recent changes (we automatically add the final ; back)
Most helpful comment
I don't think you'd get any objection to adding the final semicolons back. Feel free to send a PR (I think this one is pretty easy).