@aaditmshah Apologies for my limited expertise in functional programming. How is your first example different from using normal let
statements?
const x = Math.random();
const y = x * x + 2;
const z = y * 3;
const a = z.toString();
And the difference with the proposed as
expression I can think of is that the data flow in let expression can be a DAG rather than a pipeline:
const a =
const x = Math.random() in
const y = x * x in
const z = x + 2 in
(y + z);
But in this case, I think we should fall back to the normal control flow to explicitly state the data dependency.
I can't speak for the usefulness of let expressions. But from the software engineering perspective, let expressions violate a principle (or coincidence) of declaring variables and make it harder to find the declaration of variables. I can peek at a line and quickly know there's a declaration if the line starts with let
, const
, import
, for
, function
, etc. I could find every local declaration with the regex ^\s*const
. Now how about this?
console.log("The sum of two numbers is ", a, "+", b, "=", const c = a + b in c);
This is Pandora's box that requires serious consideration before opening.
Another problem with let expressions is the scope problem. Should the const
variable be available outside the declaration ()
? That's something a developer cannot infer from the syntax, and one has to look up the spec if it has moved to another language to work on a project for some weeks and just moved back to JS.
The scope problem is something I would personally avoid. JS once had the infamous var
declaration:
console.log(foo); // undefined
if(true) {
var foo = "bar";
}
console.log(foo); // bar
@theScottyJam The %
variable in the pipeline proposal brings this problem back, in an inversed way. The scope might appear to be different than expected:
const a = 1 |> (2 |> % * %);
How do we distinguish (2 |> %) * %
and 2 |> (% * %)
? Again, we need to look up the operator precedence before we can be sure. It's not a well-known precedence like +
and *
. It's JS-specific.
Of course, you are able to write correct code if you are careful, just as how you know the scope problem of var
. But we want it to be obvious, and so obvious that we can grab a piece of code and understand what it is exactly doing without looking up the spec.
@markm This is really an intriguing trick! As for the difference:
- The
as
expressions & do
expressions have the extra power of embedding for
and if
statements.
- The
as
expressions & do
expressions can use await
, while function parameters cannot.
It is a Syntax Error if CoverCallExpressionAndAsyncArrowHead Contains AwaitExpression is true.
- The
as
expression & the pipeline proposal can discard temporary variables for GC.
- The
as
expression & the pipeline proposal also enable clean refactor history in line diff (e.g. git
). This is also the purpose of trailing commas, I believe. const a = ((
x = Math.random(),
- y = x * x + 2,
- z = y * 3
+ z = x * 3,
) => z.toString()
)();
const a = Math.random()
- as(x) { x * x + 2 }
as(x) { x * 3 }
.toString();