Implementation considerations in the ECMAScript standard (was {Weak|}{Map|Set})

David Bruant david.bruant at labri.fr
Fri Sep 16 09:50:41 PDT 2011


Changing the subject to something more relavant.

Le 16/09/2011 15:36, Andreas Rossberg a écrit :
> On 16 September 2011 15:17, David Bruant<david.bruant at labri.fr>  wrote:
>>> Well yes, but that's part of programming. In practice, all resources
>>> are finite. And the difference between finite and infinite space usage
>>> is a correctness criterium.
>>>
>>> Consider writing a server. If I cannot rely on tail call optimization
>>> then writing its message loop as a recursive function (e.g. actors
>>> style) would be incorrect. If I cannot rely on GC, then allocating an
>>> object for each received message would be incorrect. If I cannot rely
>>> on weak maps, then, say, mapping every message object to a return IP
>>> would be incorrect.
>> You are making a connection between program correctness and implementation
>> consideration of what you use to write these programs. It doesn't sound
>> right.
>>
>> "If I cannot rely on tail call optimization then writing its message loop as
>> a recursive function (e.g. actors style) would be incorrect."
>> =>  This is not true. If your server ever receives only one message, you
>> should be fine.
> Obviously, I was talking about a server that is expected to get an
> unbounded number of messages during its uptime.
>
>> The problem is in implementation limitation, not correctness
>> of your program. It turns out your programming style with nowadays
>> reasonable use cases (size of input, number of messages...) makes current
>> implementations fail. I agree that it is annoying, but it doesn't make your
>> program incorrect.
>> If we start considering implementation limitations as sources of program
>> incorrectness, then some ECMAScript programs will always be incorrect.
> The difference is, this limitation would be hit for the _normal_  use
> case of the server. If my program cannot deal with its expected use
> case, then it is incorrect.
What is the definition of normal use? Size of input? When machines will 
be powerful enough to handle your current normal case without tail call 
optimization, will the definition of "normal use" change?
Once again, program correctness [1] (tell me if you use "incorrect" 
differently and please define it if so) has nothing to do with 
implementation considerations of the plaform that run your program.
There is no contradiction in having a correct program which fails when 
implemented because of implementations issues (of the platform, not the 
program).

I do not think the ECMAScript standard is the the place where 
implementation considerations should be addressed. For that matters, 
people have been writing JavaScript programs for years and the spec 
doesn't say a word on implementations.

Also, why should tail call optimization should be standardized? There is 
a use case, but aren't there other implementation optimizations that 
could be considered? Should they all been standardized? Why this one in 
particular?
Really, once again, an appendix named "hints for implementors" or a 
different document or a page on the wiki would be better than a 
normative section. Saying that ECMAScript implementations aren't 
standard because they do not support one programming style sounds like a 
lot.


>> Regarding tail call optimization, as far as I'm concerned, an agreement
>> between implementors sounds like a more reasonable approach. There is no way
>> in the language to test this feature. In this video [1], David Herman
>> explains that a test can be written (at 40:40), but the test relies on
>> implementation limitations rather than the language by itself (unlike all
>> tests that can currently be found on test262).
> That is true, but whether some property can be observed from within
> the language itself, or only by its environment, is not relevant.
It is not for people who write programs, it is for implementors because 
it directly impacts their work. They are not implementing a language 
anymore (which they still were as of ES5.1), but a language and some 
implementation constraints.
Let imagine for a minute that tomorrow, implementors find another 
implementation trick which allows to run without crash the use cases 
that motivated the proper tail calls proposal, why would it be 
problematic? Why does it have to be this optimization in particular?


> There is no test that you can reliably write for a 'print' function.
> Still you want to be able to rely on it printing what you gave it.
I (if i was an implementor) would want to test my print function. I can 
decide to do it from within the language or not since i have more power. 
You can also test a function from outside a language (which is a more 
relevant choice for a print function).


> Or consider a sleep(secs) function. How would you test it?
Time cannot be formalized. The best we do is a human-acceptable 
approximation of it. For what it's worth, I recommand reading the ES5.1 
spec for Date.now(). I think that test262 does a pretty good job of test 
coverage for it.


>> "If I cannot rely on GC, then allocating an object for each received message
>> would be incorrect."
>> =>  Can you refine this point? I don't understand the connection between
>> garbage collection and correctness of your program.
>> I allocate objects on a daily basis and have never /relied/ on garbage
>> collection.
> I think you implicitly do, all the time. Just try turning off GC and
> see whether your programs still work reliably.
With or without GC, there are 2 possible behaviors for a program 
(assuming conformant platform):
- it works reliably
- it crashes (not reliably most of the time)
GC isn't of any help regarding reliability. It is helpful to make my 
program running reliably longer, that's all it does. If you disagree, 
please provide an example proving me wrong.

What I implicitely do is not relying on the GC, it's praying that the 
implementation (and GC in particular) is good enough to make my program 
run without crashing long enough.
That's what everyone does, I think.
Does this kind of prayers has a place in the spec?

Same thing for tail calls. We write a program in some style praying that 
the implementation will run it without crashing. Turns out, recursive 
tail calls make implementations often crash. Is it a good reason enough 
to impose something on the spec for that?

Tell me if i'm wrong, but until today, all implementation decisions have 
been made based on market considerations. JS is fast because of that. 
New classes of program can be run now while they couldn't before (in the 
sense that performance did not allow these programs to be efficient). 
See the video at [2].
I do not think it's the role of a language standard to have a word on 
implementation considerations. If there is a need for tail call 
optimization from the programmer side (to run some programs which use to 
fail without), well, implementations will adapt. If there is no push 
with that regard, I do not see why the spec should tell implementors 
what to do.
Also, there is a long history in JavaScript of implementations doing 
what they want regardless of spec. There may not be a need of another 
such case.

Spec driving features and market driving implementation choices sounds 
like a good trade-off.

David

[1] http://en.wikipedia.org/wiki/Correctness_%28computer_science%29
[2] http://blogs.intel.com/research/2011/09/pjs.php


More information about the es-discuss mailing list