openlang

The array nobody asked for

CoffeeScript returns the last expression of every function, and a for loop is an expression. So a handler that ends in a loop written for its side effects compiles to JavaScript that collects every iteration's value into an array and returns it. Nobody reads that array. The docs suggested ending such functions with true or null, and I still catch myself typing a trailing null in plain JavaScript, where it does nothing.

The conversation continues 4

Follow the reasoning
  1. Permalink

    ReScript returns the last expression too and never builds that array, because a for loop there has type unit. An unused value mid-block gets a warning suggesting ignore, and I'm not sure what that teaches a learner.

  2. Permalink

    The array is the harmless case. The interesting one is a handler whose last line happens to be a boolean.

    If the handler is attached with addEventListener, the return value is ignored and whatever the loop or comparison produced is just garbage. If it's assigned to onclick, a returned false cancels the default action. If it's a jQuery handler, false also stops propagation, because jQuery treats it as preventDefault() plus stopPropagation(). So the same compiled return is noise in one setup, a link that won't follow in another, and a click the parent never hears about in the third.

    A refactor preview that marks the implicit return as unused would be wrong in two of those three. It should say where the function is attached before it calls anything dead.

  3. Permalink

    That one did more damage than the arrays ever did (and I suspect it's a good part of the reason the advice existed at all, since a trailing null or true keeps jQuery quiet where a stray false does not, and the docs never quite spelled that out). The usual victim was a toggle. A click handler ending in @open = not @open compiles to return this.open = !this.open;, which returns false on every second click. Every other click toggled the panel and also ate the event. It looks like a flaky toggle until you read the compiled return line, which is an easy line to read past.

  4. Permalink

    Plain JavaScript still has the concise arrow. useEffect(() => fetchList()) hands React a promise and the dev console complains, and useEffect(() => { fetchList() }) returns undefined, which is roughly what that trailing null was for.

Other sides of the same question

  1. round(2.5) gives 2, and learners don't believe it

    Learners keep guessing that round(2.5) is 3, and both languages I reach for say 2. Python gives the integer 2, Julia gives 2.…

  2. 3 + 4 * 2 is 14, and that is the easy part

    Everyone new to Smalltalk meets 3 + 4 * 2 early and gets told it's 14, because binary messages go left to right with no arith…

  3. Translating old CoffeeScript by hand is a decent JavaScript lesson

    An unfashionable exercise that works better than it has any right to. Give a learner a small old CoffeeScript file and have t…