Mark S. Miller (2015-07-14T16:18:58.000Z)
On Tue, Jul 14, 2015 at 10:59 AM, Andreas Rossberg <rossberg at google.com>
wrote:

> On 14 July 2015 at 16:48, Mark S. Miller <erights at google.com> wrote:
>
>> On Tue, Jul 14, 2015 at 2:31 AM, Andreas Rossberg <rossberg at google.com>
>> wrote:
>>
>>> I don't see why you need parens at all, see my previous post. But I
>>> wouldn't make the do-less forms the base syntax,; rather, only short-hands
>>> for the general thing. In particular, because the ability to have an actual
>>> block inside an expression is one primary motivation for having
>>> do-expressions in the first place.
>>>
>>
>> Ah. Take a look at my full proposal. The bizarre observation is that
>> extending the syntax of parens to contain approx a block-body, and
>> extending its meaning to creating a block-like scope for evaluating that
>> block-body, in addition to returning a value. In that case, we simply don't
>> need the "do" expression at all. Don't propose something unnecessarily
>> complex just because you expect that something simpler would be too
>> controversial. If it actually is too controversial, that's another matter.
>>
>
> I would very much dislike introducing a second syntax for blocks, though
> -- which is essentially what you are suggesting. Especially when curly
> braces provide a much better visual clue for the extent of a scope than
> innocent plain parens do. It's the natural expectation for a C-like
> language, too.
>

I can see that. I'm torn.




>
> In the design of any modern language the whole notion of block of course
> is totally obsolete. But JavaScript has its C heritage, and I doubt bolting
> on something alien would make it a prettier language.
>
> ...Ah, it's 2015, and we still have to come up with ways to overcome the
>>> archaic statement/expression distinction from the stone ages. :)
>>>
>>
>> Between Gedanken, Smalltalk, and Actors, almost everything we do in oo
>> dynamic language design was already conceived right by the early '70s.
>> Retrofitting without breaking things takes much longer than invention ;)
>>
>
> Well, statements vs expressions was already found unnecessary before OO,
> in the early 60s -- consider Algol 68. (Let alone Lisp, which is late 50s.)
>


For that part specifically, sure. Gedanken also had full indefinite extent
lexical closures. It might have been the first to do so -- Lisp was
dynamically scoped at the time and Actors had not yet been invented. I've
always been puzzled why Gedanken has not gotten more attention --
especially since it was mainly by John Reynolds. Check it out -- you'll be
impressed.




>
> /Andreas
>
>
> On 14 July 2015 at 01:33, Mark S. Miller <erights at google.com> wrote:
>>>
>>>> Interesting. Got me thinking. Here's an alternate proposal I'll call
>>>> "do expressions without the 'do'."
>>>>
>>>> At <
>>>> https://people.mozilla.org/~jorendorff/es6-draft.html#sec-expression-statement>
>>>> we have the syntax of the expression statement. Ignoring sloppy "let"
>>>> nonsense, this says that an expression statement cannot begin with "{",
>>>> "function", or "class".
>>>>
>>>> At <
>>>> https://people.mozilla.org/~jorendorff/es6-draft.html#sec-ecmascript-language-statements-and-declarations>
>>>> are the legal ES6 statements. Note that most of these begin with a keyword
>>>> that cannot possibly be legal at the beginning of an expression. Therefore,
>>>> adding all these initial-statement-keywords to the list of things that
>>>> cannot begin an expression statement would break nothing. They already
>>>> cannot begin an expression statement.
>>>>
>>>> With the expression statement prohibition in place, now we can allow
>>>> all these forms to be expressions. As with "{", "function", or "class", if
>>>> you want to state such an expression in expression-statement position,
>>>> surround it with parens.
>>>>
>>>> Because all these new forms will look bizarre and confusing, at least
>>>> at first, let's say these always need surrounding parens to be expressions.
>>>> I think that would help minimize confusion.
>>>>
>>>> If we do this, the oddest duck is "{", since it begins an object
>>>> literal expression. This proposal gives us no straightforward way to
>>>> express an block expression. "function" and "class" are less odd, since
>>>> their existing expression forms mean what you almost might expect by this
>>>> new rule -- even though they are initial-declaration-keywords rather than
>>>> initial-statement-keywords.
>>>>
>>>> The remaining initial-declaration-keywords are "let" and "const". We
>>>> already made "let" insane regarding these issues in sloppy mode, so I'm
>>>> going to ignore that. But let's consider "const" and strict "let". These
>>>> already cannot appear at the beginning of an expression, so it would not
>>>> break anything to add them to the prohibition list for the beginning of
>>>> expression statements.
>>>>
>>>> No current expression can add any binding to the scope in which the
>>>> expression appears. Let's examine the consequences of having parens --
>>>> rather than containing a "{"-block to create a nested scope with a value
>>>> (which would conflict with object literals), instead simply define a
>>>> block-like nested scope with a value. This would allow declarations and
>>>> statements within the parens, much like the current "do" proposal. It would
>>>> even be consistent enough with the existing semantics of paren-surrounded
>>>> function and class expressions: Someone who sees these as a function or
>>>> class declaration within its own nested scope, whose value was the value
>>>> being declared, would rarely be surprised by the subtle difference between
>>>> that story and the current semantics.
>>>>
>>>> Having parens accept a list of declarations and statements rather than
>>>> just an expressions seems like a radical change that must break something,
>>>> but I can't find a problem. Am I missing something?
>>>>
>>>> Examples inline:
>>>>
>>>>
>>>>
>>>> On Mon, Jul 13, 2015 at 5:47 PM, Isiah Meadows <impinball at gmail.com>
>>>> wrote:
>>>>
>>>>> I was reading a recent thread
>>>>> <https://esdiscuss.org/topic/allow-try-catch-blocks-to-return-a-value> where
>>>>> do-expressions simplified a common try-catch use case, and I was wondering
>>>>> if `do` could be simplified to an expression? It would allow for this to be
>>>>> solved very easily, but also add a lot more flexibility in this proposal,
>>>>> as well as avoiding some ugly nested braces.
>>>>>
>>>>> I know it would cause an ambiguity with `do-while` loops, but that
>>>>> could be resolved with a single token lookahead of "if the next token is
>>>>> the keyword `while`, then the block body is the body of a do-while loop,
>>>>> else it is the body of the block statement in a `do` expression".
>>>>>
>>>>> As for the EBNF, do-expressions could be parsed with a goal symbol of
>>>>> either `+While` or `-While`, with do-while statements spec-wise effectively
>>>>> being treated as do-expressions without an init part run repetitively, but
>>>>> mandated to be statements.
>>>>>
>>>>> ```js
>>>>> // Do expression
>>>>> let foo = do {
>>>>>   foo(0)
>>>>> };
>>>>>
>>>>
>>>> let foo = (foo(0));
>>>>
>>>> This seems as broken as the original. In both cases, unless I'm missing
>>>> something, this is a TDZ violation when the right side evaluates foo.
>>>> Mistake?
>>>>
>>>>
>>>>>
>>>>> let tried = do try {
>>>>>   foo(0)
>>>>> } catch (e) {
>>>>>   throw e
>>>>> };
>>>>>
>>>>
>>>> let tried = (try { foo(0) } catch (e) { throw e });
>>>>
>>>>
>>>>
>>>>>
>>>>> // Do-while statement
>>>>> let i = 0;
>>>>> do {
>>>>>   foo(i)
>>>>> } while (i++ < 10);
>>>>>
>>>>> // Combined:
>>>>> let i = 0;
>>>>> let foo9 = do do {
>>>>>   foo(i) // can have side effects, foo9 = foo(9)
>>>>> } while (i++ < 10);
>>>>> ```
>>>>>
>>>>
>>>> let i = 0;
>>>> let foo9 = (do { foo(i) } while (i++ < 10));
>>>>
>>>>
>>>>
>>>>>
>>>>> Another example of where this could come in handy: simplifying
>>>>> asynchronous code.
>>>>>
>>>>> ```js
>>>>> function readConfig() {
>>>>>   fs.readFileAsync('config.json', 'utf8')
>>>>>     .then(JSON.parse)
>>>>>     .then(contents => do if (contents.unexpectedProperty) {
>>>>>       throw new Error('Bad property') // rejects the promise
>>>>>     } else {
>>>>>       doSomething(contents)
>>>>>     })
>>>>>     .catch(err => process.domain.emit('err', error))
>>>>> }
>>>>>
>>>>
>>>> ...
>>>> .then(contents => (if (contents.unexpectedProperty) {
>>>> ...
>>>> }))
>>>> ...
>>>>
>>>>
>>>>>
>>>>> // With only block statement
>>>>> function readConfig() {
>>>>>   fs.readFileAsync('config.json', 'utf8')
>>>>>     .then(JSON.parse)
>>>>>     .then(contents => do {
>>>>>       if (contents.unexpectedProperty) {
>>>>>         throw new Error('Bad property') // rejects the promise
>>>>>       } else {
>>>>>         doSomething(contents)
>>>>>       }
>>>>>     })
>>>>>     .catch(err => process.domain.emit('err', error))
>>>>> }
>>>>>
>>>>> // Without do-expressions
>>>>> function readConfig() {
>>>>>   fs.readFileAsync('config.json', 'utf8')
>>>>>     .then(JSON.parse)
>>>>>     .then(contents => {
>>>>>       if (contents.unexpectedProperty) {
>>>>>         throw new Error('Bad property') // rejects the promise
>>>>>       } else {
>>>>>         doSomething(contents)
>>>>>       }
>>>>>     })
>>>>>     .catch(err => process.domain.emit('err', error))
>>>>> }
>>>>> ```
>>>>>
>>>>> As you can see, the more general version does simplify things a little.
>>>>>
>>>>> Also, if-statements look better than long ternaries IMHO, and are less
>>>>> repetitive than their counterpart, repeated assignment (us lazy typists...):
>>>>>
>>>>> ```js
>>>>> let foo = do if (someCondition) {
>>>>>   value
>>>>> } else if (someOtherCondition) {
>>>>>   value + 1
>>>>> } else if (someEdgeCase) {
>>>>>   addressEdgeCase(value)
>>>>> } else {
>>>>>   value
>>>>> }
>>>>> ```
>>>>>
>>>>
>>>> let foo = (if (someCondition) {
>>>> ...
>>>> })
>>>>
>>>>
>>>>
>>>>>
>>>>> --
>>>>> Isiah Meadows
>>>>>
>>>>> _______________________________________________
>>>>> es-discuss mailing list
>>>>> es-discuss at mozilla.org
>>>>> https://mail.mozilla.org/listinfo/es-discuss
>>>>>
>>>>>
>>>>
>>>>
>>>> --
>>>>     Cheers,
>>>>     --MarkM
>>>>
>>>> _______________________________________________
>>>> es-discuss mailing list
>>>> es-discuss at mozilla.org
>>>> https://mail.mozilla.org/listinfo/es-discuss
>>>>
>>>>
>>>
>>
>>
>> --
>>     Cheers,
>>     --MarkM
>>
>
>


-- 
    Cheers,
    --MarkM
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20150714/57fb6a82/attachment-0001.html>
d at domenic.me (2015-07-25T02:54:10.059Z)
On Tue, Jul 14, 2015 at 10:59 AM, Andreas Rossberg <rossberg at google.com> wrote:

> I would very much dislike introducing a second syntax for blocks, though
> -- which is essentially what you are suggesting. Especially when curly
> braces provide a much better visual clue for the extent of a scope than
> innocent plain parens do. It's the natural expectation for a C-like
> language, too.
>

I can see that. I'm torn.


> Well, statements vs expressions was already found unnecessary before OO,
> in the early 60s -- consider Algol 68. (Let alone Lisp, which is late 50s.)


For that part specifically, sure. Gedanken also had full indefinite extent
lexical closures. It might have been the first to do so -- Lisp was
dynamically scoped at the time and Actors had not yet been invented. I've
always been puzzled why Gedanken has not gotten more attention --
especially since it was mainly by John Reynolds. Check it out -- you'll be
impressed.