let-in if do-expr is problematic? (was: Re: proposal: let in if parentheses)
Just as a heads up, something semantically identical to this is what prompted this big shutdown from Mark Miller, and is why the bar raised pretty high since for new features:
Le 21 août 2018 à 21:20, Herbert Vojčík <herby at mailbox.sk> a écrit :
Hi!
It would be nice to know if do expressions have some a chance, otherwise some other syntax for let-in would be really helpful, especially now that we have arrow functions.
I would propose to use different variant of let (maybe also const):
OP 1:
let in a = b(), if (a) a.c();
OP 2:
let in a = b(), if (a) c(a);
Instead of const big = raw => { let cooked = cook(raw); return consumer => { // do things with consumer and cooked }; };
const big = raw => let in cooked = cook(raw), consume => { // do things with consumer and cooked };
In short,
let in binding = expr, stmt|expr
It may work for
const in
as well.Herby
P.S.: Alternative syntax is "let a=3, b=4, ..., in foo(a,b,c,d)" but this can only tell late if it is plain let-up-to-end-of-scope or local-scope-let, so not sure if that may be a problem; OTOH you can chain more of them and resembles classical let-in better.
Please, don’t take it too seriously: but have you thought about resuscitating the (in)famous with
statement?
const big = raw =>
do with ({cooked: cook(raw)})
consumer => {
// do things with consumer and cooked
};;
And no the two ”;”s are not a typo: I need to end both the with
statement and the const
declaration.
But more seriously... those sorts of “clever” syntaxes (let-in
or do-with
or whatever), apart from complicating the language, are in danger of raising as much issues than they’re resolving; the double-semicolon oddity is one of them.
es6 import-statements are effectively with-statements …
actually, they're async with-statements, with no callback-handling and non-obvious dependency-resolution logic, for those of us trying to debug them when things go wrong.
Kai, that makes no sense whatsoever, and isn't contributing productively to this thread. Dependency resolution logic is platform-specific - in browsers, it's "URLs", which I assume you understand, and in node using babel, it's "the same as require", which I'd assume any node user would understand. There's no relationship to "with" statements and no actual difficulty "debugging" them that I'm aware of after using them for years.
Please stay on topic, and keep to yourself comments that are nothing more than random toxicity about the JS language.
Dependency resolution logic is platform-specific
@jordan, platform-specific logic is not a real problem? the behavior of import-statement between babel (sync), native-browser (async), native-nodejs (sync???) are all subtly different. and yes, it's effectively a with-statement.
its not toxicity. its reminding tc39 of their mistakes, so they don’t repeat something again as stupid and harmful to industry/web-development in the future.
kai zhu kaizhu256 at gmail.com
It's off topic to the thread, so either way it's not appropriate to bring it up here.
It's not objectively a mistake, and calling it "stupid" is absolutely toxic. Be nice, or don't participate. I'll refer you to tc39/code-of-conduct which governs this list as well.
agree that “stupid” was a too-strong word, but the scope of es6-modules honestly was a mistake when we reflect on it with 20/20 hindsight. imagine an alternate-timeline where tc39 had instead gone with a smaller-scope/conservative/gatekeeper approach of expanding on commonjs-modules instead. most web-developers would probably agree such a scenario would've been more conducive to web-development:
-
it would’ve mitigated significantly, the tooling-hell associated with es6 web-projects that makes them riskier than es5 web-projects.
-
we wouldn’t have the issue of every es6 web-project being permanently stuck with context-switching between commonjs-modules and es6-modules, because its impossible to reinvent all relevant commonjs-modules as es6-modules
-
we wouldn’t have awkward conversations when teaching beginners on why the language has [soon-to-be] 3 different module-loading systems: 1) commonjs-require, 2) static-import, and 3) dynamic-import (which is essentially/cross-cutting commonjs-require except its not because we don’t want to admit that [asynchronous?] static-import turns out to be too confusing and difficult-to-use for frontend-developers).
this is a cautionary-tale of what happens in design-by-comittee, where not enough committee-members clearly thought-through the big-picture impact to industry of what they were doing.
kai zhu kaizhu256 at gmail.com
Herby, for those like myself who aren’t familiar with “classical let-in,” could you explain more about the objective? It’s not clear to me from the brief example what advantages this would provide.
The “let bindings in expression” originates in mathematics and logic.
I cannot speak for the original proposal but the major difference between this syntax is that it evaluates to an expression compared to the let statement which evaluates to undefined.
One benefit of “let in” is that it is easier to compose with other syntactic constructs which expect an expression.
The semantics of the “let bindings in expression” is to evaluate the expression after “in” with variables substituted by the definitions in the bindings. Essentially, the syntax allows you to create a modified scope for that one expression.
However, I find nested let expressions difficult to parse in my head and would personally not suggest this syntax to be added to the language. I use Haskell as my main programming language and there using the “where” syntax often leads to easier to read code than using “let … in”. 2018年8月24日(金) 17:41 Darien Valentine <valentinium at gmail.com>:
It would be nice to know if do expressions have some a chance, otherwise some other syntax for let-in would be really helpful, especially now that we have arrow functions.
I would propose to use different variant of let (maybe also const):
OP 1:
let in a = b(), if (a) a.c();
OP 2:
let in a = b(), if (a) c(a);
Instead of const big = raw => { let cooked = cook(raw); return consumer => { // do things with consumer and cooked }; };
const big = raw => let in cooked = cook(raw), consume => { // do things with consumer and cooked };
In short,
let in binding = expr, stmt|expr
It may work for
const in
as well.Herby
P.S.: Alternative syntax is "let a=3, b=4, ..., in foo(a,b,c,d)" but this can only tell late if it is plain let-up-to-end-of-scope or local-scope-let, so not sure if that may be a problem; OTOH you can chain more of them and resembles classical let-in better.