I adored Eliss when it released. I still use it at one of the single best examples of how a touch UX radically changes the computing experience by aligning software behavior with physical intuitions.
Consider multitouch. Conventional mouse-desktop thinking orients us to one pointer and a one-point interaction mode. "Normal Users" (aka, the Your Mom archetype) new to the touch experience and to Eliss almost always use a single finger to drag around the screen objects, switching to two only to pinch. But around level 3, the game ramps up in difficulty, and this is when the magic happens. The user starts falling behind. Without asking or thinking about it, nearly every single one of them suddenly starts using their other hand. Nobody told them it would work! These are users terrified of clicking the File menu, because it once ate their Word document. Experimentation has a huge mental inhibition, and yet touch is so intuitive it bypasses the block. I've asked all these users whether they noticed -- and while this isn't rigorous by any degree -- nearly all of them reported they did not. This is magic.
Thank you Steph Thirion, for hours of enjoyment in Eliss as well as a lovely natural experiment in UX.
Yeah, I agree with the other comments -- the greatest JS scoping gotcha involves unbound methods.
var o = { a:13, add:function(b){ return this.a + b; } };
o.add(42); // => `55`
var add = o.add;
add(42); // => `NaN`, because `this.a` is (presumably) `undefined`
var a = 3;
add(42); // => `45`, because `this.a` is resolved to `window.a`, as `window` is the global variable used as the method context when we call an unbound function (which is stupid (`null` would have been a way better choice, Brandon)).
This is the sort of thing you learn and just get over to reach the level of javascript mastery. Yeah, some things are silly. But you know what? You only get to write one language to access the dynamic web.
For unknown reasons, ARC has truncated my code-comment. It read:
// => `45`, because `this.a` is resolved to `window.a`, as `window` is the global variable used as the method context when we call an unbound function (which is stupid (`null` would have been a way better choice, Brandon)).
I've always heard them referred to as "Generic Functions", though the Wikipedia article is annoying opaque.
The important quality (in my practical understanding) is that a generic function's specialization is decoupled from the object system -- delegating to `x.__iter__()` doesn't require `x` inheriting a method from a parent; the process `iter(x)` uses to delegate might not even require any type information about `x` at all.
In both cases, the key observation is to realize that the meaning of the numbers is more important than the numbers (or how they're calculated, per se). This point is kind of abstract--especially compared to the salient examples in both pieces--but if you're looking to understand why this error is so common, look first to the fact that it's not an error of stupidity or insufficient maths.
You can sometimes avoid a big practical problem (e.g., an avenue to attack your system via diluting meaning ("spam")) by abstractly considering the meaning behind the structures available to you.
Some of the most frustrating problems I've seen are due to misunderstanding or rare semantics rather than mistakes. Examples might include the specifics of floating-point math, or exactly how numeric coercion works. This is especially bad when the result isn't easy to eyeball as right or wrong.
For example, we could force a double-valued transcendental function to float and back for a small loss of precision in normal cases:
#define sin(d) ((double)sinf(d))
Which yields...
double i = 10
--> i = 10.0000000000
sin(i) = -0.5440211109
sinf(i) = -0.5440211296
delta = 0.0000000187
double i = 0.25
--> i = 0.2500000000
sin(i) = 0.2474039593
sinf(i) = 0.2474039644
delta = -0.0000000051
double i = 9999999.999999
--> i = 9999999.9999989998
sin(i) = 0.4205487007
sinf(i) = 0.4205478132
delta = 0.0000008875
(Format string was %25.10f, fwiw.)
Another idea: Let's say we know the application relies on rand() to produce the correct distribution for testing, or maybe to generate session keys. Changing the semantics of the RNG won't result in a compiler bug, but it might result in the tests failing to cover all cases, or a horrible security breach.
You know, I still have a 50-odd Erlang article queue. So I'm not saying I want every day to be Haskell Day, but I'm also not saying I'd be terribly upset if I had a few hundred articles on Haskell to keep me warm at night...
What do you use for this queue? I can't possibly keep up with all the reading I come across, and often just relegate it to Readability, Instapaper, Delicious, Xmarks, etc. Would be very interested to hear how someone else handles this.
You might also look into Berkeley JE. It's an in-process KV store, which might be a minor crimp for you, but it's more mature than god and transparently handles paging to disk and shadowing. We used it as durable working memory for a high volume stream-processing application, bundling rows together into pages, compressing them, and then letting JE handle caching and GC. It does an excellent job.