Closed TheSpyder closed 1 month ago
Counter argument: perhaps defining a lazy
should be a changed to bracket-less syntax to match this pattern. As discussed in discord last night, it's confusing:
https://discord.com/channels/235176658175262720/235199119747055616/711938366194843788
Rather than lazy(myFunction(something))
it would be nice to have lazy myFunction(something)
. I think this would solve the ambiguity compared to otherFunction(myFunction(something))
; the brackets here for lazy()
make it less friendly imo, not more.
Parentheses were added for constructing lazy values in #2376. However I guess we missed adding them to the lazy(...)
pattern as well at the time (I didn't know it could be a pattern at the time). I think for overall consistency it's better to add it to the pattern e.g. let lazy(x) = lazy(1);
.
I didn't know about it either until the blog post 😂
I agree we should be consistent, but after the discord discussion I think I'm leaning towards reverting to never have brackets rather than adding them to the pattern matching.
We should consider overall syntax consistency. Reason syntax makes any kind of value construction look like function application e.g. let x = Some(0);
. And conversely so does destructuring e.g. let Some(y) = x;
. This simplifies the syntax overall–you don't need to remember a special rule for constructing and destructuring lazy values.
I think special syntax for special things makes sense, for example in JS await
doesn't use function syntax. If reasonml ever adds that directly (instead of via let.await
) it will definitely be expected to not use function syntax.
For constructing values, sure, function syntax makes sense. But lazy
doesn't construct a value, it suspends constructing a value.
Reason has already added let-operators. It's part of the language now. [Edit: I think I misunderstood you, do you mean if Reason adds await
syntax after already adding let-operators? That's possible I suppose but I don't think it's worth considering too much.]
lazy
constructs a value of type Lazy.t
.
Yes, I meant adding await
even though we have let-operators. let.await
isn't the same thing; it requires a library to implement it.
Lazy.t
is only a value in the strictest sense of the word. As far as developers using it are concerned, it's about as much of a value as Promise.t
is. lazy(1+2)
doesn't produce 3
until you force the computation.
But the whole point of promises is to turn asynchronous computations into first-class values that can be passed around. Lazy values are values in exactly the same sense. Anyway I think we are really in #bikeshedding territory now.
We are definitely bikeshedding, but if I do nothing brackets will be added. I'm growing more convinced reverting brackets is the better answer.
But the whole point of promises is to turn asynchronous computations into first-class values that can be passed around. Lazy values are values in exactly the same sense.
Yes, they are both special values that suspend computation from the line of code they're defined in, which is why having special syntax for both seems fine to me. let.await
is a form of special syntax, so is await
if that later becomes important enough to include, but I can't define let.lazy
.
await
is not constructing a promise, it's binding to an existing promise and letting a continuation run on it. It's not the same as lazy(...)
. In fact JavaScript promises don't even suspend computation, they run eagerly. So the semantics of await
really are quite different. In the hypothetical low probability of await
being added to Reason, it's perfectly sensible for it to look like JS await
.
Promises suspend computation at the line of code they are defined on, yes they run after the current stack frame but that's an implementation detail.
I don't actually use async
/await
so I always get them confused. I guess async
is the one I meant then? My point was that JS programmers are already used to special syntax that changes how the line of code operates, whether that's binding to the promise result or creating the promise to begin with. We should be fine with it too.
We've spent quite a bit of time talking about a hypothetical async/await syntax for Reason, something I'm fairly sure will not happen now that let-operators are officially part of the language. But just to be clear. There's no special syntax in JS for creating promises, unless you count marking a function as async
which lifts its return value into a promise. But this is syntactically separate from the return
statement itself.
As I mentioned before, we already have a syntax for constructing values in Reason, and it looks like function application. Yes, constructing lazy values is semantically different, but it's not different enough that it warrants some special rule. Consider that in OCaml syntax, it looks like normal function application too: let x = lazy 1
. I don't see any justification for Reason to be different.
I have come across a case where
refmt
not only supports v2 syntax but outputs it 😮While reading the BuckleScript blog post about the new lazy encoding, I noticed a cool way to unpack
lazy
values without callingLazy.force
:let (lazy(value)) = myLazyValue;
Or rather, that's what I expected the syntax to be. Turns out the syntax in the blog post is not only valid reason, it's the syntax
refmt
converts the above to. No brackets.let lazy value = myLazyValue;
proof this syntax works: https://reasonml.github.io/en/try?rrjsx=true&reason=DYUwLgBAtgngMgQwF4wGoOAVxBAvBYZGACgCIALAS1IEoBuAKAYHoAqCAd3IUgEkIQADwAOIAMaRWzBqEjFCKYgDcM2GjTzR4RdFhCMAUgGcAdMAD2Ac2WqQ9Jm07dIAJxAAzKJHOYww30YQUjLgBEQQKnqasIgoutiGphbWkWqMQA
I'm using