-
• #2
Fri 2021.10.15
'Per the standard, the condition in loops is an Expression,'
Hi @user135362 when challenging referencing an outside document, providing the link to that document will assist us all in evaluating your concern.
As I see it:
The conditional expression for a while statement must evaluate true or false.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/while
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator
In the sample provided
x = costlyAccessor(i++)
will always evaluate TRUE based on the truthy rules. Result: endless loopAlso,
>while(0,0);
can never evalute TRUE. Result: never executesSo, as I see it, and as none of the references I have just found make any mention of using the comma operator within a while conditional, seems problematic.
Could be other reasons, but I'm sure this will open up to others for discussion. . . .
-
• #3
@Robin, I am attempting to report a parsing error, not a semantic error, and “while (0,0);” is a minimal reproduction. It is not intended to be a full, useful program; just the shortest and simplest snippet I can concoct that triggers the error, to assist with debugging. I did also explain what real examples would look like and why I care.
I apologise for not including the link https://tc39.es/ecma262/multipage/ecmascript-language-statements-and-declarations.html#sec-while-statement ; I truly didn't think it was necessary, because I thought everyone here would know what the comma operator is and does. Mea culpa.
In any case, the standard, at that link, says this:
Syntax
WhileStatement[Yield, Await, Return] :
while ( Expression[+In, ?Yield, ?Await] ) Statement[?Yield, ?Await, ?Return](and similarly for for statements, which are also affected by the bug).
I don't really understand your point about truthiness. “x = costlyAccessor(i++), p(x.a, x.b)” returns the value of p(…), not the value of x. Per https://tc39.es/ecma262/multipage/ecmascript-language-expressions.html#sec-comma-operator-runtime-semantics-evaluation :
13.16.1 Runtime Semantics: Evaluation
Expression : Expression , AssignmentExpression- Let lref be the result of evaluating Expression.
- Perform ? GetValue(lref).
- Let rref be the result of evaluating AssignmentExpression.
- Return ? GetValue(rref).
In short, it does the same thing as in every other language in the C family, evaluating the value on the left, then evaluating and returning the value on the right. The use in loop conditions is generally consider to be the principal motivation for the existence of the operator, since elsewhere you can usually accomplish the same thing with some unpacking and a semicolon. Admittedly it is more commonly used in for loops than in while loops, but again, I was seeking the easiest example to debug the grammar on.
- Let lref be the result of evaluating Expression.
-
• #4
@user135362 ,
quite interesting... did not know about this and more so would not even dare to go there... because, when I make compute statements like
if (x=a>3) { ...x...; }
- and I like to do that a lot - because I'm right away need thatx
and don't want to spend / waste another few bytes and I'm aware about the resources and the architecture of Espruino - I already get flagged with a warning that an expression is expected and not a assignment.To be forthcoming for Espruino, it is not Espruino issue but the issue of the IDE - more so its lint - and many other IDEs/lints. I have another attitude borne out of language and compiler building, which is to put the 'continuation-char' on the next line and not at the end... which reduces the error issue greater than 50% and making copying around easy... and makes clear for the reader in the first few chars on the line that things are still going on without having to go read up all to the end of the line - often with scrolling - to figure. (btw, making parens around the assignment hides its very nature and makes lint to see it is a (logical) expression... haha... so much for a machine to control the spirit... of course I could ignore the orange warning triangle.... but I love to also not have to see warnings not to be taken care of. The source is too (2) bytes longer - almost lost what I gained - but to my luck and support: minifier gets rid of it... and if not, let's fix the minifier).
Going on in 'the meta of the metas': the source code has to the way that is is the easiest FOR A HUMAN to read and quickly grok what is going on without having to ingest all things in every detail. The computer - compiler or parser - does not really care anyway and is (most of the time) scalable - I - as a human and individual - I am not scalable.
Returning to the subject at hand: 'getting to know Espruino' taught me and keeps me teaching new things and changes me. Being rooted in general purpose and reuse and (useful) formalism had to give a bit way to what the goal is and is in sync with @Gordon ultimate rational that triggered the birth of Espruino: make it as simple as possible... you could also say: lean as possible. Just because it a thing was done or a spec says you can do it does not mean you should do it... that goes with a teaching I got shoved down the throat very early in my life (cynical): Warum einfach wenn es kompliziert auch geht? - 'translated': why do it simple when it works complicated as well?
Where I see use of this feature of being able to do things in the parens for the condition - may be that's the reason the condition has to be in parens to allow a code block of which the last statement sets the value for the condition - is to not have things stated twice: before the loop's condition is taken into account and the loop starts starts as well as at the end of the loop. That's a typical pattern I never liked and if this will work in Espruino, I will sure take advantage of it; but there is a big BUT: what is the cost in execution and footprint for the interpreter to have to deal with this and make the loop slower than needed.
I can live with many constraints Espruino has, because I could easily declare them as exotic... and exotic coding is against maintenance and against simple growth...
May be not worth 2cts, not even 1, but for sure a 1/2 one... how should I 'feel' about that: :\ ... or :>
So lets fry the bigger fish!
-
• #5
Sat 2021.10.16
Thank you for posting that link @user135362 allowing us all to be on the same page. It eliminates the reader's possible confusion as to which reference is being used. The number of times a reference has been made to inacurate document detail, or an in process document constantly changing.
The references I mentioned indicate a conditional expression to be evaluated within the while, while that comma operator contains both a statement expression as well. So should the statement expression also be evaluated as a conditional as in the reference example shown?
As you pointed, I've only ever seen that in use to separate a list of increment operators inside the end of a for loop, and I have to agree with @allObjects that it adds too much confusion when not quickly readable/understandable by the onlooker.
Another 'gotcha' is that it wouldn't be possible to insert Espruino's WebIDE editor side debugger statement at that point in order to single step debug. (didn't test that though)
Also, if we keep expanding our expectations, feature creep will eventually not leave enough RAM for us to play!
-
• #6
I don't quite understand the question. The comma operator is a normal operator valid in any full Expression (13.16 ). It is historically descended from Algol68's semicolon operator, and (despite the different precedence) semantically related to JS's
&&
operator. Like&&
it processes the left argument and returns the right; unlike&&
it voids the left argument and proceeds unconditionally. In fact, I suspecta, b
could be defined (semantically) as!a < 2 && b
or some such stupidity.Syntactically it has only one oddity, which is that it, like the bare assignment operator, is also used for other things, such as forming VariableDeclarationLists (14.3.2) and ArgumentLists (13.3), which means that there are places where the semantic expectation is an expression but the syntax restricts you to an AssignmentExpression to resolve the ambiguity of which kind of comma is expected.
In any case, none of this has anything to do with the conditions in control constructs, which are uniformly and uncomplicatedly Expressions (14.6, 14.7.2.1, 14.7.3.1, 14.7.4, 14.7.5, 14.12).
There's also no case to be made that it is a semantic restriction of Espruino or its debugging mechanism, since the semantically identical
while ((0, 0));
parses and executes flawlessly. This is nothing but an issue with Espruino's internal grammar, as far as I can see, either a typo (I hope) or an utterly capricious decision to alter the syntax ofwhile ()
while not even making the same change forif ()
.To the argument that this feature of the language is not pretty and adds confusion, all I can say is that today it was recommended to me that I replace
search: while (…) while (…) if (…) break search;
(which Espruino does not implement) with
(() => {while (…) while (…) if (…) return;})();
. It does not appear that prettiness and lack of visual confusion is the driving force behind this project(!). And, for goodness' sake, if you really hate the comma operator so passionately, why allow it inif
andswitch
?Orthogonality and lack of bugs are generally considered virtues in the programming language community; I'm honestly not sure what's going on here. If it's that efficiency trumps usability, then what's the point of Espruino at all? C, or indeed assembly, is easy enough to write; I came here in the expectation that things would “just work” without too much hassle :-}.
-
• #7
...and they actually work... because a warm, living body and a whole community is behind Espruion, rarely seen such a galvanization of spirits. It is smaller than any other ...uino world, but it is a refreshing to step into world of justified uniqueness, where amazing things by amazing people of all walks of life get done.
-
• #8
it was recommended to me that I replace
search: while (…) while (…) if (…) break search; (which Espruino does not implement) with
(() => {while (…) while (…) if (…) return;})();I did not recommend that. I suggested real named function that would do the search and return the result that was found. Didn't see whole code so maybe it does not fit well. The idea was to split larger complex code into smaller functions for better readability and possibly also reusability.
It does not appear that prettiness and lack of visual confusion is the driving force behind this project
Well, I find your original code with label and break already visually confusing and not pretty :-)
-
• #9
Sat 2021.10.16
reply to post #6
'no case to be made that it is a semantic restriction of Espruino or its debugging mechanism'
No, not semantic restriction, I don't believe it is possible to insert the debugger statement within a list/container as, (previously discovered years ago) must be on it's own line. Haven't tested recently.
ref: 'then what's the point of Espruino at all?'
A month ago I put together some links on the history and comparison to the evolution of Arduino:
'I came here in the expectation that things would “just work” without too much hassle'
Arduino had an army of devlopers over a twenty year period while Espruino is one/couple/community in just over a five year period. IMO Espruino is light years ahead with it's ease of setup (just plug it in) and near instant ability to start writing code and interactive debugging. Major bonus for the young mind and those just exploring the world of code.
As this thread has now uncovered, agrees with my assessment that Espruino is starting down the path of bloatware trying to do too many things with too little resources. Microsoft tried that and look what happened to their marketshare.
'if you really hate the comma operator so passionately, why allow it in if and switch?'
That question should be directed at the originators of the project. I'm an end user like yourself with a need to support 10-16 year olds with just the basics along with the Blockly graphical editor. Espruino ver 1V95 was perfect as ES5 features are all I require.
Point of note: With the close of the Bangle V2 KickStarter campaign, It is likely that shipping will be under way with their limited time to respond timely.
-
• #10
Thanks for this! I just added an issue for it here to keep track: https://github.com/espruino/Espruino/issues/2068
Hopefully it should be a reasonably straightforward fix.
I noticed you reported another issue for arrow functions inside arrow functions. Out of interest, are you hitting these because of code you've written, or are you running through some tests like test262?
-
• #11
@Robin I'm sorry, I misunderstood you! But it's genuinely a place where control constructs are required, since the double loop that wants to terminate early is working on a significant amount of lexically visible state. Of course this can can be skinned in many different ways, I can't look at the design of JS and not think that its own (very different from C) labels were put there for precisely this use case, and they involve a lot less clutter (both visual and conceptual) than any of the many ways of reifying the loop.
@Gordon It's new code, so I'm able to work around the limitations, but it's real code, not a test suite. I have a number of watch faces and related features that I'm working on in the emulator in anticipation of receiving my Bangle 2. When I have real hardware to try them on I'll likely upload some or all of them.
-
• #12
Thanks! That's really interesting - Espruino's got over 10,000 users now, and it's pretty unlikely that any of them hit any issues with language features - but you've hit several!
Having said that, it may be you're the only one that's bothered to isolate and report them - and I can't stress enough how grateful I am for you taking the time to do that. There definitely aren't enough people giving clear, well-researched bug reports with simple test cases :)
I just fixed this (the
while(0,0)
issue). It won't be in the emulator yet, but the next time I do an update it will be.And thanks - I can't wait to see what some of your apps are :)
Per the standard, the condition in loops is an Expression, but Espruino evidently parses it as AssignmentExpression, disallowing the comma operator. This is particularly painful contexts like
Minimal reproduction:
Oddly, if and switch have no such problem.