Sour syntax
With sweet and umami down, time for a syntax form that just leaves a sour taste and I’ve got just the one.
In our last stop in this tour around the javascript syntax palate, we saw the semi-scrutable “with”. That syntax form is described in the earliest version of the ECMAScript standard, and described there more formally than it’s treated here. There’s scope chains and activation objects and anonymous code and all kinds of things in there — like Prego tomato sauce. Like sauce in a jar, language standards are half aspiration and half apology. Just in the middle between the two is enough to get you a meal closer to tomorrow. My own bachelor go-to move was to heat the jar of sauce in the pot of boiling water used for the pasta. In both cuisine and computing, let the crimes of my youth be a cautionary tale.
Whether Prego or Python, it’s in there. Married six month and already your wife’s using a programming language from a .JAR?
What’s not always captured in the standard is that there was some family feud about the precise recipe or a simmering dispute between rival systems that forced the standardization process. There’s a at least a pinch of Microsoft‘s JScript in the journey from Netscape Javascript to the ECMAScript. I prefer something more like a primer than a standard — learning how to make the sauce by watching a beloved relative do it. Our syntax primer today is about initialization in javascript.
Before I lose you, here’s a piece of good, old-fashioned, C:
localhost:~/papertiger$ cat foo.c #includeint main(int argc, char **argv) { int bar = bar; int baz = (baz = 7, baz); printf("recall that int var = expr; is equivalent to int var; var = expr;\n"); printf("bar: %d (probably 0 but possibly random because bar is uninitialized)\n", bar); printf("baz: %d (should be 7)\n", baz); { int foo = (foo = 3, foo); printf("foo: %d (should be 3)\n", foo); { int foo = foo; printf("foo (again): %d (probably 0, but possibly random because this foo is uninitialized)\n", foo); } } } localhost:~/papertiger$ make CFLAGS=-Wall foo cc -Wall foo.c -o foo localhost:~/papertiger$ ./foo recall that int var = expr; is equivalent to int var; var = expr; bar: 0 (probably 0 but possibly random because bar is uninitialized) baz: 7 (should be 7) foo: 3 (should be 3) foo (again): 0 (probably 0, but possibly random because this foo is uninitialized) localhost:~/papertiger$
This may be a silly point, but in the case of int foo = ( foo = 3, foo); , we are able to update foo and then reference it in the middle of its own initialization. Although this may seem to be a feature of limited and dubious utility, it falls out from the fact that initialization at time of declaration is a convenience feature which is exactly equivalent to int foo; foo = ( foo = 3, foo); In this latter case, it should be clear that there is no point at which we reference an indeterminate value of foo.
OK?
Javascript is superficially similar to C, but only superficially. Javascript is a dynamically typed language vs. C’s static types, but C/C++ can be pushed surprisingly close to javascript here with typedef struct { … some stuff … } let;
localhost:~/papertiger$ cat foo.js let bar; bar = (bar = 1, bar); console.log("bar: (should be 1) " + bar); let foo = (foo = 1, foo) console.log("foo: (should be 1) " + foo); localhost:~/projects/fireplace$ node foo.js bar: (should be 1) 1 /home/papertiger/foo.js:4 let foo = (foo = 1, foo) ^ ReferenceError: Cannot access 'foo' before initialization at Object.(/home/papertiger/foo.js:4:16) at Module._compile (internal/modules/cjs/loader.js:1114:14) at Object.Module._extensions..js (internal/modules/cjs/loader.js:1143:10) at Module.load (internal/modules/cjs/loader.js:979:32) at Function.Module._load (internal/modules/cjs/loader.js:819:12) at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:75:12) at internal/main/run_main_module.js:17:47 localhost:~/papertiger$
So what happend? Why could we assign bar but not foo?
Javascript has invented a difference between assignment at declaration and subsequent assignment, and in doing so exposed a bizarre corner of the language with a little-explored point between declaration and initialization for no apparent advantage. As in the C case, there was no bad syntax, or even uncertainty about what the value of foo should be.
As a user, this leaves a sour taste in my mouth. If I were a bad user, I would guess that this fissure in the runtime between declaration and initialization could be driven into a crack — like botulism poisoning the contents of a less than fully cooked jar.
The best sauces benefit from time and reduction, where ingredients and flavors fold back on themselves. Javascript, like Prego, was put in the jar a little too soon. Is the stuff in there? Sure, but less than fully developed. Is it a good base? Well, both Prego and javascript have some sugar, but otherwise yeah.