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