Hacker News new | comments | show | ask | jobs | submit login
Why ++[[]][+[]]+[+[]] = 10 in JavaScript (stackoverflow.com)
159 points by smharris65 1972 days ago | hide | past | web | 72 comments | favorite

Seems like "this is why Javascript sucks!" is a common reaction here, which I find strange on a "hacker" community. It's a fun little brainteaser, not production code. Use your head a little?

It demonstrates language issues that can (and often do) lead to problems in production. So the response is completely appropriate.

About the only problem I can think of here is that it makes it harder to filter/sanitize for XSS. But I don't think the problem here is Javascript. Look at SQL injection - trying to escape user input is just an endless game of whack-a-mole. The proper way to deal with it is parameterized queries. HTML doesn't have anything similar AFAIK.

I don't think this particular nuance of the languadge has much effect on productionilized code, this is a very specific observation built by someone who understands the nuances of JavaScript deeply. As such it would take the opposite of ignorance to get something like this into production, you would have to know the nuances of the language pretty deeply to get code like this into a system.

There are some gotchas is JavaScript like the (== for 0, null, ""), the floating scope of (this) and a few others but for the major use cases of JavaScript people only need to be aware of a handful of languadge nuances to not hang themselves. It has some quarks no doubt about it, but for the most part they are easily avoided or you have to know about them to be doing what you are doing in the first place.

My question is, when did that start working in Javascript?

Does this trick work in Brendan Eich's first JS implementaion in Netscape 2.0? Which came first, the spec or the implementation?

Funny thing, that.

The implementation came first. From what I understood, Microsoft looked at Netscape's implementation, wrote a spec from that and implemented it - so when time came to standardize it, Microsoft had a readily available spec (having written one after reverse engineering Netscape's implementation). Since Javascript has lots of little quirks, Microsoft didn't quite get everything right and so when the final spec was published, Netscape's implementation was actually in violation of it in a couple of places.

I guess that's funny depending on who you are.

A very valid question, haha. JavaScript is full of mysteries.

This sort of thing really bothers me with Javascript. Using the unary + operator on an array should be an error. Hiding errors by having implicit type convertions doesn't help me fix those errors.

You may say that users don't need to see to see strange error messages they don't understand. Quite right, what we need instead is to have a way for browsers to transmit uncaught exceptions in JS to the server.

What should the unary + operator do except for type coercion into a number? Or are you saying it should only work on strings?

It just doesn't seem like something that would happen accidentally, there's no reason to put + on something unless you are explicitly trying to coerce it into a number. It's not like unary minus where -x; could have some other semantic meaning for something that is already a number and you make a mistake and give it an array (which javascript has, and I think is a much more likely source of error than the unary plus).

Using an array (or a string for that matter) where only a number should be is an error. I'd like to see an exception thrown and the current JS uncaught-exception-handler would be invoked, assuming something else catches it.

If I want an array to be a number, I'll call .Count on the array or whatever the applicable property I want is.

I don't think you understand what I am trying to say.

The unary '+' operator is completely pointless if something is already a number, it is a no-op. Literally the only time anyone would ever type +x is if x is not a number, if someone chose to write +x and x turned out to unexpectedly be an array, pretty much the only thing that you know they were thinking of when they wrote the + was that they thought x isn't a number; maybe a string if they were using +x instead of parseFloat(x), but definitely not a number.

It just isn't a reasonable example of a situation where an array is being used where a number should be, +x where you know that x is a number would make no sense. If you talk about -x then that is completely different, people who write -x almost certainly expect it to be a number, and -[] === 0. Unary plus is just not the right example for awful type coercion here.

One of the core principles of JavaScript is to avoid errors whenever possible. Using + on arrays bothers me less than the fact that there is no error for division by zero.

It's not an error to divide by zero per the IEEE floating point specification, and you'll find the same behavior in most modern languages:



returns "foobar"

From wtfjs.com:

  ",,," == Array((null,'cool',false,NaN,4)); // true

Clever, but not as surprising...

(null,'cool',false,NaN,4) evaluates to the last expression - 4

Array(4) creates an array with 4 elements.

Array(4).toString() = ",,,"

You describe that as "not surprising"? Yikes.

You're surprised... why? You were expecting Python semantics?

Unsurprisingly, JavaScript is its own language.

Surprisingly, its semantics and "features" are often bizarre and sweat-inducing when compared to other languages. (Surprising for such a widely-used language).


It's surprising if you haven't used javascript before I guess.

"Surprising" doesn't mean non-deterministic. So you're saying anyone who has simply used JavaScript shouldn't be surprised by that snippet you posted? It's a glowing example of surprising semantics.

You can use javascript for years and never come across a situation where you'd do or see several of the things found in that small statement.

I made that point in another thread as well, if you stick to the meat and gravy of JavaScript you just don't hit on these nuances of the languadge. I am generally not a fan of clever programming tricks or "magic code" and if you are then JavaScript becomes a tempest, but if you are using it to glue interfaces together, build some widgets and manage events you just don't get into the ugly side of JavaScript, it's not my favorite languadge but it get's the job done and it is efficient as far as development effort goes.

There are only 3 things, which aren't surprising to anyone who has done much js.

  1). a list of expressions eg (foo,bar,baz) evaluates to the last one.
  2). Array(4) creates an empty array of 4 elements
  2). Array(4).toString() = ",,,"

I don't think the comma operator wouldn't be surprising to an experienced js programmer. I can't remember a single piece of serious code where I could see it in use.

The same applies to the void operator, I can think of one or two cases at most where it would be useful, but I don't see anyone using it.

Thought some and came up with an way to convert whichever natural number you want into this form.


It depends on underscore.js for the functional bits.

Wow, those are really unfortunate variable names.

I've never seen the term "gook" outside of a racial slur context.

Changed. Figured that the time it would have taken to write up something about people being able to look past racial slurs blah blah blah was more than just "fixing" it.

Also, I meant to say thank you as well. I would like to avoid offending anyone with variable name choices. So, thank you for pointing that out.

I feel like it was probably from something like http://en.wikipedia.org/wiki/Gobbledygook which, (as far as I know,) has no racial context.

I can't find a link to a page, from some time ago, in which every letter and number was obtained combining only parentheses and punctuation.

It's linked directly in the original question?


I wonder how people come up with this kind of code to begin with?

This comes from an attempt to write valid JavaScript without using any letters or numbers. It's partly for the sake of demonstrating it's possible and part for security testing reasons, to show that poorly written input validation filters can be bypassed.

True! you wont use it. I guess it'll end up being just an Interview Question.

The correct interview question is, “Write a filter that blocks executable JavaScript but allows text.” And the correct answer is “Kobayashi Maru."

The correct interview question is, “Write a filter that blocks executable JavaScript but allows text.

I would hire you on the spot, my post history is littered with how irrelevant these type of questions are to gauging ones ability to develop real world solutions. You pretty much summed up the irony nicely.

This is the reason I prefer strongly typed languages. Allowing developers to play fast and loose with data types only leads to less maintainability down the road and makes code difficult to read.

I am not a PL expert, but is this a strong vs. weak type problem or an implicit conversion problem? My layman’s (simplistic) model is that “weakly typed” languages allow entities to change their type at runtime, strongly typed languages do not.

But what we have here is an expression where entities are being implicitly converted into intermediate values, along with operators that do different things based on the values they are given. For example, the behaviour of the “+” infix operator in JavaScript could be replicated in any strongly typed language that has pattern matching:

  x:string + y:string -> concat(x,y)
  x:stringable + y:string -> concat(toString(x), y)
  x:string + y:stringable -> concat(x, toString(y))
  x:numeric + y:numeric -> sum(x,y)
I recall implicit conversion being one of the gotchas in C++. While its casts break strictly strong typing, a program with lots of implicit conversions can behave just about as mysteriously as the example JavaScript.

Back in the day when I wrote C++ (by gaslight, after I rode my penny farthing to the office), any one-argument constructor was presumed to be an implicit conversion unless you provided the “explicit” keyword.

UPDATE (and thanks to the hacker who pointed me in this direction):


It seems that the expression “Strong typing” subsumes both the concept of static typing (variables and/or values do not change their types) and of coercion. (Along with other issues such as whether programmers can deliberately evade restrictions).

If I were to rewrite my question, I would ask if this is a strong typing problem overall or just the subset of strong typing issues concerning coercion?

So part of the issue with this code is implicit coercion, which is not “strong typing,” but the other is polymorphic operators like “+”, which are independent of strong vs. weak typing.

Wikipedia has a good page on this subject. In a nutshell, "strong/weak" typing is not formally defined. Usually languages are called weakly typed when they allow a lot of implicit type coercion or just don't strictly enforce types. It's not at all unique to dynamically typed languages. C is pretty weakly typed, for example. And a static language could just as easily have a quirk like this JavaScript thing.


Update to your update:

Strong typing does not subsume static typing. Ruby, for example, is dynamic and quite strongly typed. You can't bypass the type system at all, and the only real coercion is to boolean, which follows a very simple rule.

While the phrases don’t seem to have strict definitions, by the Wikipedia description of Strong Typing ,there is an overlap with Static Typing:

The mandatory requirement, by a language definition, of compile-time checks for type constraint violations. That is, the compiler ensures that operations only occur on operand types that are valid for the operation. However, that is also the definition of static typing, leading some experts to state: "Static typing is often confused with StrongTyping”...

Fixed and invariable typing of data objects. The type of a given data object does not vary over that object's lifetime. For example, class instances may not have their class altered.


I guess this is one of those things where the correct response to any claim about “Strong,” “Static,” “Weak,” or “Dynamic” typing is to ask the speaker what, specifically, he is thinking of.

In this case, you and I are exploring the subject in some depth, but the person who originally used the phrase “Strongly Typed” is silent, so neither of us has any idea what he had in mind.

The thing is in a weakly typed language you can implement functions that do coercion, while a strongly typed language will not let you as generally there is a fixed type (or type class) to each parameter. That does not mean the standard built in or library functions have to do javascript levels of coercion though, I think there are better balances.

I wrote an article where I tried to lay out the definitions of these terms: http://alexgaynor.net/2010/nov/19/programming-languages-term...

Strong typing: A type system that I like and feel comfortable with Weak typing: A type system that worries me, or makes me feel uncomfortable


I have been in the industry for 16 years and have some pretty big code bases, in a variety of languages, under my belt (not trying to brag just setting the back-story). In thinking back, I cannot recall a single instance where any member of my team was bitten by an accidental conversion or a type safety issue. I have been fortunate to work with some good people, but some of them where average in their ability to actually write code, yet we never had these issue. I find it hard to believe that my situation is unique and I think the type safety Strong/Weak argument is a little overblown, I just don't encounter it in real life and don't know many other developers that do.

I spent much of a week tracking down a bug in a Clojure program where primitive false was being sent through a network, and read back in as boxed false. It looked right when printed out, yet somehow the wrong branch of an if-statement was being taken. This was in a program under 2000 lines, in my first semester of college, before I had ever held a full-time programming job.

Most people are not trained to notice these kinds of problems, or the simple checks that can stop them from confusing a list of lists and a list of lists of lists. But if you take a step back and think hard about what's happening to your time, you'll find that many hours are sunk chasing problems that are, in many ways, simple. Having static checks is like always having someone to read code over your shoulder.

Sure my case is anecdotal at best, and maybe I have just been lucky, but my experience has been that implementing UI's with JavaScript is as fast of a development cycle as doing it in Java or C#. In fact the UI space is dominated by languages such as JavaScript and Objective-C where type safety is loose. I don't believe that fact means that they are superior, but they are as productive as strong typing for UI development in my experience. That being said, I do prefer strong typed languages for middleware and server development, some will differ on that, but it is what I am comfortable with and it works for me.

I think a lot of the hate against statically-typed languages is because people associate them with languages like C# and Java (as opposed to e.g.: OCaml), which lack not only many of the higher-order functional features that we've come to expect in both static and dynamic languages, but also the soundness guarantees that come from actual type-safety.

If you're more productive in JavaScript, it's probably not because you can write a function that converts either an string or an integer to an array2. More likely, it's because you don't need to manufacture a new class every time you want a one-line handler.

If you're more productive in JavaScript, it's probably not because you can write a function that converts either an string or an integer to an array2.

Right which was my point in my other post where I said I just don't run into it that much. It is rare that we run into situations where we have to do tricky stuff with the type system. If we do we usually hide it behind a well tested API so that it is isolated and reusable. It's just not the problem domain that we solve for (most of the time) in web and mobile development. As such for my work flow the type safety of a languadge, does not factor in all that much. At least until I hit the middleware layer then I tend to use Java, but much of that decision is out of comfort and volume of libraries available.

Type systems aren't there to help you do tricky stuff. They're there to protect you from the silly mistakes we all make when doing normal stuff.

Maybe you've created a button that puts some text in an element, but, in some rare cases, due to other events on the page, that element doesn't exist. The user clicks the button, document.getElementById returns null, and a nice error message pops out.

In JavaScript, you might discover this after a lot of testing. In DynXML, you would never be able to make that bug in the first place -- you'd get a type error.

(JavaScript has the advantage, though, of not being vaporware. As the low-paid undergraduate doing the implementation work on DynXML, this is my fault.)

Remember, being able to write a function that converts either a string or an integer to an array is exactly the kind of thing that dynamically typed languages let you do that statically-typed languages don't. If you're not doing that kind of thing, you're better off with a statically-typed language (when available).

This is a "Javascript has retarded semantics" problem, nothing more. This would never work in Lisp.

Moreover, despite being a strongly-ish typed language, C++ has pretty ridiculous implicit conversion semantics, only statically rather than dynamically.

I don't see how this example justifies your position, though. Nobody will ever write "++[[]][+[]]+[+[]]" to mean "10" in anything but an obfuscated code contest.

No they will, in every horribly thought out interview that someone who thinks they are smart writes in on a white board and asks applicants to solve it. As if these trick questions some how give insight into ones ability to solve real world problems. These are exactly the kind of obscure fringes of a languadge that an interviewer with an ego loves. When they reality is whether one can solve it or not, amounts to a hill of beans as to whether one is a good JavaScript programer or not. In fact if they are using these fringe practices in their code base they are writing unmaintainable code, which makes them a less desirable developer.

Great, then you know who not to work for.

I agree that 'magic code' and obfuscation is pretty much ego stroking, but this doesn't seem like a good argument against the whole idea of using weakly typed languages.

No I was not arguing against weak typing, just taking the opportunity to highlight how these kind of questions are used. I have no issue with weak typing. I don't get too dogmatic about such viewpoints. My comment was rather an attempt to highlight where a lot of this type of trivia knowledge is used and misapplied.

This has nothing to do with playing fast and loose with data types, and everything to do with implicit conversions between data types. This code would work just as well in a fully statically typed language with the same conversion rules.

No it's not. This is an argument against poor management, not any particular programming language feature. If you have someone writing code like this in production you have a management problem. Review code, use and create clearly defined code standards, use validators, use "strict" mode, and most of all use your brain.

A bad craftsman always blames their tools.

Definitely agree. Unfortunately the tools sometime make it easier to shoot yourself in the foot. No matter how smart you are.

And sometime smart people tend to think they're invincible/bullet-proof. Not too many people have high-level discipline. And those that have high-level discipline tend to be shunned by "hackers" because "hackers" hate "processes". They just want to write fun code.

Hence the circle of evil.

there's a time in the place for everything. static/dynamic typing is a trade off between short-term development pace and long term maintenance. strong/weak typing is a trade off between enforcing high-level constraints and, well, i'm not exactly sure, but (void*) is used all the time in baremetal C . ... that said, i've never read an opinion that weak-typing to the extent possible in javascript is a great idea.

void* is used in C to interact with the raw bytes. In some sense, the raw bytes are the only type in C. You can try to maintain a distinction between a struct RECT{int width; int height;} and a struct POINT{int x; int y;}, but it's perhaps more appropriate to think of that as documentation for the programmer than as an actual type system. As long as your code has poorly-behaved neighbors, the types offer no guarantees.

Reminds me of the J programming language

Hold up, I think I just stumbled on to a fellow alum.

(Surely no other university teaches that language besides mine, right?)

Which university are you talking about?

(I'm learning J and other APL derivatives right now by myself by experimenting with the J docs and pinging the amazing people at the J software forums).

Trinity University in San Antonio. One of our profs has been working on J for decades.

You haven't, I just think that it's a wonderful language. I really wish it was Open Source...it makes me sad.

J is open source and free software as of March 2011 under GPLv3.

See you at the J software forums.

I was thinking about brainfuck.

If you rely on that sort of thing in production code, you're doing it wrong.

Wow, -1 points! Are the two of you saying that this is a good thing for production code?

Putting this in the category of "not going to think hard about this, because it's only going to make me upset and angry."

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | DMCA | Apply to YC | Contact