top | item 7585693

Nerdsniping: A glimpse into a stubborn mind

145 points| philip_roberts | 12 years ago |blog.andyet.com

92 comments

order

vernie|12 years ago

Yikes. I understand that companies use these posts as a form of advertising, but seeing your "application security specialist" struggling with such a basic expression gives me pause.

romanovcode|12 years ago

I was working with this guy - he always tried to prove that everything is possible wasting time. He ALWAYS over-complicated simple things. He was horrible to work with and everyone hated him.

Not to say you are just like him etc. but this post reminded me of him because it was probably exactly what he would do.

kbenson|12 years ago

Wasting other people's time is a negative, but deepening your understanding of a topic by examining edge cases is generally worthwhile, IMHO.

e28eta|12 years ago

I think it's worth pointing out the article writer recognizes this is a distraction. In the comic, nerd sniping causes people to forget they're crossing the street and they wind up being hit by a car, which is a pretty serious distraction from the task at hand.

mncolinlee|12 years ago

And this is why Javascript can be such an awful language. Leaving off a single equals has such a profound effect, often without a new coder even realizing it while reading the code.

Imagine what happens to your code when someone tries to write a function for its side effects similar to the example seen in the blog post. Then releases it in production for it to break in six months with a feature change.

briantakita|12 years ago

> And this is why Javascript can be such an awful language. Leaving off a single equals has such a profound effect, often without a new coder even realizing it while reading the code.

You get used to this as you get seasoned with javascript. Every language has it's quirks. The human brain is remarkably adaptable to using tools & dealing with intricacies. I personally utilize & appreciate the difference between == and === to reduce complexity in the code. I assume the reader also understands such differences.

I also find automated testing, logging, a module system like commonjs, and linters to be useful when programming in javascript. Once these are in place, systems written in javascript are remarkably maintainable & scale with complexity.

maxbucknell|12 years ago

At the end of the article, it is demonstrated that this can happen even with strict equality by overriding the getters. Any language with getter/setter support can do this. Operator overloading can be used for even nefarious ends.

The point is that side effects in code are dangerous, and can be used to mislead a reader.

If this happens, it is not the fault of JavaScript. Anyone who writes code like that for purposes other than demonstration or learning is a moron.

pmelendez|12 years ago

>"And this is why Javascript can be such an awful language."

To be fair, this is breaking Javascript and that is something you could do in other languages, for instance here is a similar version for C++:

http://pastebin.com/seySfpku

rmrfrmrf|12 years ago

There are ways to do stupid things in any language. I don't think anyone would ever tell you that redefining an integer as an object and overwriting its prototypes is an acceptable way to solve...any? problem.

sisk|12 years ago

I'm glad that you said, "can be" because language flexibility is a two way street. You can abuse dynamic typing for good and for evil. I, personally, don't think that's a case for declaring it not worthwhile, rather it reenforces investing the time to properly understand the language.

Fortunately, at this stage, we get the best of both worlds with syntax validators and linters. Abuse as appropriate (whatever that means) and be warned about the rest.

MatthewWilkes|12 years ago

Yeah, just use python!

  class B(object):
      def __eq__(self, other):
          return True

  b=B()
It's much more expressive

cruise02|12 years ago

> Imagine what happens to your code when someone tries to write a function for its side effects...

The language used can hardly be blamed for that.

marknutter|12 years ago

And then you realize that javascript runs everywhere and you smile to yourself and continue coding away.

ronaldx|12 years ago

The differences between programming syntax and elementary/Boolean algebra are very awkward to understand clearly and deal with correctly. We clearly understand mathematical algebra to work one way, and we naturally assume programming algebra works the same way, which it doesn't at all.

Here, the antagonist says that b can't be 1 and 2 at the same time, which would be self-evident in mathematical algebra, but turns out to be quite irrelevant to Javascript and to programming paradigms generally (since two statements will never be checked simultaneously).

This difference in how syntax is understood actually presents a barrier to programming for modestly trained mathematicians, who would otherwise be expected to excel.

nmrm|12 years ago

>This difference in how syntax is understood actually presents a barrier to programming for modestly trained mathematicians, who would otherwise be expected to excel.

Although this is true in general that syntax can be a barrier to entry, the article provides a particularly poor example. If anything, the article demonstrates how mathematical training is good preparation for many pitfalls of programming.

Mathematicians are used to working with various equivalence relations, even in the same context. So if a modestly trained mathematician saw == and ===, she would immediately ask "what is the difference between these two ER's?".

And then when she finds out the essential difference is that you can override ==, it would be clear that all bets are off.

I can't imagine any mathematician taking more than a few minutes and a google search -- let alone 11 days -- to figure out this loophole.

minusSeven|12 years ago

Umm , you missed a key point here. The first comparison is == while the second one is ===. These 2 are different. The == checks equivalent. Mathematically speaking he should have used === in both places.

These things are more of quirks of javascript than anything else. The post did nothing but made me hate javascript. Try doing the same in Java !

Dewie|12 years ago

> Here, the antagonist says that b can't be 1 and 2 at the same time, which would be self-evident in mathematical algebra, but turns out to be quite irrelevant to Javascript and to programming paradigms generally (since two statements will never be checked simultaneously).

This isn't really a problem if b is enforced to be immutable.

gyepi|12 years ago

Nerdsniping reminds me of the Walt Whitman poem:

   There was a child went forth every day;
   And the first object he look’d upon, that object he became;
   And that object became part of him for the day, or a certain part of the day, or for many years, or stretching cycles of years.
It's especially bad if you'd really rather be doing something other than what you're currently doing.

tatalegma|12 years ago

"I want my code to execute if port is 80 or 443, and http is false"

Couldn't you simply do this?:

if ((a==='80'||b==='443') && http===false) { ... }

cowsandmilk|12 years ago

I think the goal was

if (a==='80' || (b==='443'&&http===false)) {...}

level|12 years ago

Call me nitpicky, but it always bugs me when someone references some content, but doesn't link to it. Specifically the XKCD and Stackoverflow links. Link to the comic and question specifically, rather than making me go hunt for that content.

alistairjcbrown|12 years ago

> I guess we’ve messed with the prototype too much, and JavaScript isn’t really convinced it’s still a proper number anymore.

You're comparing a literal number with an object, which are not the same type.

  2 === new Number(2)
  // => false
  2 == new Number(2)
  // => true

scjody|12 years ago

> Have I learned anything directly useful?

You probably haven't. But a less experienced programmer has learned why you should always use ===.

adamman|12 years ago

The example at the end of the article shows how you can have the same problem while always using ===.

tarpherder|12 years ago

Might not be Java but still interesting, it made me think of one of my favorite little quirks in C++:

  #include <cmath>
  
  //Floating point model: Strict:Precise:Fast
  //Will code execute
  float a = nanf("");
  if (a == a)//S:No P:No F:Yes
      (do something);

  if (a != a)//S:Yes P:Yes F:No
      (do something);

  if (a < 0.f || a > 2.f)//S:No P:No F:Yes
      (do something);

  if (isnan(a))//S:Yes P:Yes F:Yes
      (do something);

NaN's (Not A Number) can propagate a long way through your code, possibly reaching places where they cause real problems. When dealing with input, especially networking, one should always check for NaN's. Basically the rule with NaN's is: The comparison always returns false if any NaN is involved. But as you can see; specifying the fast model throws that out of the window. (Code was otherwise unoptimized.)

In the third statement an otherwise fine check is done to make sure the value in a is sane, it doesn't get changed but its certainly not what you'd want it to be.

Whole lots of fun can be had when serving this to game servers. :D

mfonda|12 years ago

I think there was a more general question here that was missed: can a == x && a == y ever be true for any arbitrary values of a, x, and y, where x != y.

From a logical point of view, no, this can never be true. I would suspect this can never be true in javascript, and could only be made true in a language where you can override == to always return true.

I think when most developers use the word "never", what they really mean is "never (within the current context)". This makes conversations a lot simpler. Imagine how difficult conversations would be if you always had to qualify never. "This can never be true (assuming a weird valueOf method hasn't been defined and assuming I didn't modify the javascript interpreter to always return true for == and assuming ...)".

lmkg|12 years ago

I think there are a few cases of non-transitive equalities in JavaScript, specifically around falsey values. Part of it also has to do with whether x is the right-side input or the left-side input, because that changes type coercion rules.

Aha, found one:

  ['0'] == 0
  > true
  [0] == 0
 > true
  [0] == ['0']
 > false
Transitivity of equality can also never be relied upon when dealing with Floating Point numbers. This is correct and unavoidable behavior, but still surprising to many developers.

russellsprouts|12 years ago

Something like this could work, to some degree:

        a = {}
        a.valueOf = function() {
           var caller = arguments.callee.caller.toString();
           //parse the caller function, and return 
           //different values based on what comparison is being made. 
        }
But I think this is even worse than the getter on the global object.

tonyarkles|12 years ago

Here's a JavaScript example, based on what was in the article.

    var b = {c:0};
    b.valueOf = function() { this.c++; return this.c; }
    b == 1 && b == 2
    > true

aaronem|12 years ago

It's not often I see an HN thread which so aptly demonstrates the exact effect under discussion.

antinitro|12 years ago

var i=0;

var b = {};

b.valueOf = function () {

  return ++i:
};

if (b==1 && b==2) {//success}

gkop|12 years ago

  var i=0;
  var b = {};
  b.valueOf = function () {
    return ++i;
  };
  if (b==1 && b==2) { console.log("success")}

yeahbutbut|12 years ago

And so far everyone has missed telling the poor OP how to avoid writing two equality checks...

    if( [80, 443].indexOf(port) !== -1 && http === false )

skrebbel|12 years ago

Are you certain that that's an improvement?

cwmma|12 years ago

If( ~[80, 443].indexOf(port) && http=== false)

gcr|12 years ago

This kind of abuse is also available in Python!

    In [3]:
    class TheObjectThatIsEqualToAnything(object):
        def __eq__(self, other):
            return True

    In [4]:
    x = TheObjectThatIsEqualToAnything()

    In [6]:
    x == 3 and x == 5
    Out [6]:
    True

Grue3|12 years ago

It's not necessarily abuse. I once had to code a dummy object that supported all arithmetic operations with normal numbers and had a special comparison logic that it is never equal to itself. Then you could test if something is a number or a dummy object by comparing it to itself.

wambotron|12 years ago

I think the answer to "can something be fuzzy equal to one value and strictly equal to another in JS?" has an easy answer that doesn't take much effort to find. This might be cooler in another language, though.

var b = 2;

b == '2'; // true

b === 2; // true

mikeryan|12 years ago

I think you missed a bit of his point which was to make that exact expression evaluate as true

(b == 1 && b===2 && b === herpderp)

neil_s|12 years ago

This is what I was gonna say! I don't know much JS, but after @sgdesign 's recent primer, the answer to the first two conditions seems obvious, b=="2" and b===2. Herpderp is just a cop out, since you could have infinite other variables that b equals, if you set the value to the same thing!

forrestthewoods|12 years ago

And here we all are reading this post during work hours. My god, the amount of productivity lost because of that simple question in chat!

mathattack|12 years ago

Is this a case of readability versus theoretical perfection?

drvortex|12 years ago

0.25 = 0.25

1 - 3 + 2.25 = 4 - 6 + 2.25

1^2 + 2(1)(1.5) + (1.5)^2 = (2)^2 - 2(2)(1.5) + (1.5)^2

Since a^2 - 2ab + b^2 = (a - b)^2

(1-1.5)^2 = (2-1.5)^2

1 = 2

QED.

peterkelly|12 years ago

And now for exercise 2:

Port the solution to Haskell

chrra|12 years ago

  newtype X = X (IORef Int)
  instance Num X where
    fromInteger = X . unsafePerformIO . newIORef . fromInteger
  instance Eq X where
    (X a) == (X b) = unsafePerformIO $ do
                       x <- readIORef a
                       y <- readIORef b
                       writeIORef a $ x+1
                       return $ x == y

  ghci> a <- fmap X $ newIORef 1
  ghci> a == 1 && a == 2
  True
Edit: formatting.

okasaki|12 years ago

even more general:

    let a = 1; _ == _ = True in a == 1 && a == 2

cinitriqs|12 years ago

so...

(everything == all && all == everything) == stardust/code

Dewie|12 years ago

Defining a number to be a procedure (or 'word' in the parlance) is simple in Forth.

> : a 2 ;

> : 2 3 ;

> a 2 =

> a 3 =

The two flags on the top of the stack are now equal.

ssdfsdf|12 years ago

This took you 11 days?!

poweribo|12 years ago

the classic feigned surprise