Stringy Objects
Article Index
Stringy Objects
Solution

Solution

The answer is in the nature of the value passed and in the way that the exact comparison === operator works.

When the rest of the program was examined the following was found:

s2=new String("yes");
answer(s2);

A user of the utility function had been super object-oriented and created a String object set to "yes" and passed it into the function. Unfortunately === tests for identity and when two objects are concerned identity is rather stronger than just having the same data stored.

Two variables are only identical if they reference the same object and hence s2==="yes" is is clearly false as s2 references one string object and "yes" is a completely different string object  hence the comparison is false.

To see that this is the case try:

s1="yes";    
answer(s1);
s2=new String("yes");
answer(s2);

You will see true for the first call to answer and false for the second. To explore this a little further try:

s2=new String("yes");
s3=new String("yes");
alert(s2===s3);

The result is that false is displayed because s2 and s3 reference different objects, even though they seem to have the same value. To get an example of identity you have to write:

s2=new String("yes");
s3=s2;
alert(s2===s3);

which does display true.

What is perhaps more surprising is that if you try:

s2=new String("yes");
s3=new String("yes");
alert(s2==s3);

you still get false even though the test is supposed to be one of equality of value. The problem here is that Javascript doesn't have a clear value type to automatically convert the string objects to. 

If you think all of this is obvious try and predict the outcome of:

s2=new String("yes");
s3=new String("yes");
alert(s2.toString()===s3);
alert(s2.toString()==s3)

The first is false the second is true.  In fact, you can use any method that returns a string in place of toString.

For example:

s2=new String("yes");
s3=new String("yes");
alert(s2.toLowerCase()===s3);
alert(s2.toLowerCase()==s3)

gives the same result, i.e. false, true. The reason is that all string methods return a primitive value type, not a string object.

Despite what many tutorials say, a string literal is a different data type to a string object. Whenever you make use of a string literal as if it was a string object it is automatically converted to a string object before its use. So you can use a string literal as if it was a string object - but it isn't.

Perhaps the final confusion is that if you create a string object using the constructor function without new you get a primitive string value type, i.e. a string literal. That is:

s2=String("yes");
s3="yes";
alert(s2.toString()===s3);
alert(s2.toString()==s3);

displays true and true because s2=String("yes");  is exactly the same as s2="yes". So not using the new operator makes a big difference.

Hence when you compare a string literal to a string object using the identity operator === the result is always false as they are not the same object.

Slightly more surprising is when you compare two string objects using the equality operator == then the result is again always false as Javascript doesn't auto-implement a conversion to a string literal before the comparison.

However if you compare a string object to an apparently equal string literal you get false if you use === and true if you use ==. The first result is because they are different objects, the second is because the string literal determines the type used for the test for equality and in this case the string object is automatically converted to a string literal.

Finally, using the String function without new gives you a string literal, but with a new operator you get a string object.

Who would have thought that comparing two strings could be so tricky?

Banner

Pattern

It's difficult to give a simple avoiding pattern for this problem. In its complete generality comparing strings is tricky.

  • If you can rely on the fact that one of the comparisons will be a string literal then the equality operator is the safest option as
        x==string literal
    gives the same answer irrespective of whether or not x is string object or literal.

So this is one example where == is to be preferred over ===.

  • If you can't guarantee that one of the items will be a string literal then the problem is much more difficult and the best you can do is:
      x.toString()==y.toString();
    or
      x.toString()===y.toString();
    which gives the same result if x and y are string objects or literals.

However, there is the small problem of what happens if x and y are more general objects, i.e. not string objects.

Notice that the problem with defining equality and identity is not just poor implementation of Javascript - it arises whenever you have a weakly typed language and dynamic objects.

Equality for value types is relatively easy to define 1==1 obviously, but equality for weakly typed objects is more difficult what does MyObject==YourObject mean?

On the other hand identity for objects is always easy to define - do variables reference the same object? Mix this with the automatic conversion of value types to objects and you have a potential problem.

 javascriptpuz

Banner

More Puzzles

Sharpen Your Coding Skills
Sharpen your Coding Skills - Elevator Puzzle

Introducing Melvin and Bugsy, characters who figure in a series of challlenges from Joe Celko. Sharpen your coding skills with puzzles that will both amuse and torment you.


Javascript
The Undefined Defined Variable

Here's a teaser that poses a practical problem - one that's happened in everyday Javascript programming. See if you can work out the answer before looking at its solution and the pattern to follow to  [ ... ]


Sharpen Your Coding Skills
The Best Sub-Array Problem

At first glance this puzzle seems trivial, all you have to do is find a sub-array, in an array of numbers,  that sums to the largest value. It sounds almost too easy to need a solution, let alone [ ... ]


Other Articles

<ASIN:1871962579>

<ASIN:1871962560>

<ASIN:1871962501>

<ASIN:1871962528>

<ASIN:1871962625