Blog-Archiv

Sonntag, 17. September 2017

String Comparisons in Java, EcmaScript and TypeScript

We always have to shift our minds when developing web applications, because we use several programming languages for them. Currently I am using:

  1. Java

  2. EcmaScript (JavaScript, JS)
    EcmaScript is a superset of JavaScript, so every JS source is also valid ES source, but not vice versa. Only "modern" HTML-5 browsers can interpret ES.

  3. TypeScript
    TypeScript also is a superset of JavaScript, every JS source is valid TS, but not vice versa. You need a compiler to translate from TS to JS.

String Comparisons

I tried to find out whether string comparisons work the same in all three languages. There are two kinds of comparisons, that of identity

if (s == t)

and that of equality

if (s.equals(t))

This was Java code.
In JavaScript (and TypeScript) similar exists, for identity

if (s === t)

and equality (let's call it "JS equality":-)

if (s == t)

Mind that the use of === and !== is strongly recommended, because == and != have a complicated conversion logic, see "Hard and soft comparisons". I will show this gotcha in the following example.

Plain Strings and Objects

In the following example, I distinguish between plain strings like

s1 = "10";

and actually allocated string objects like

s2 = new String("20");

Both is possible in all three languages.

The Java compiler optimizes plain strings in a way that it puts all equal definitions into just one place. It doesn't do this for allocated string objects, because these are constructed at runtime.

Most likely the JavaScript interpreter does similar things. Let's try it out.

EcmaScript Example Source

Four strings are used for this test: s1 and t1 are plain strings, s2 and t2 are string objects. They get compared to each other using both identity- and equality-comparisons.

var s1 = "10";
var t1 = "10";

var s2 = new String("20");
var t2 = new String("20");

alert(
    "\n s1 === t1: "+(s1 === t1)+
    "\n s1 == t1: "+(s1 == t1)+
    "\n s2 === t2: "+(s2 === t2)+
    "\n s2 == t2: "+(s2 == t2)
);

You can try this out on JsFiddle web page.

Here comes the result:

 s1 === t1: true
 s1 == t1: true
 s2 === t2: false
 s2 == t2: false

Line one is not intuitive: s1 === t1, which is an identity comparison. The programmer has written two different strings!

But mind the surprising equality comparison in line four:

new String("20") is not equal to new String("20") in JS, and unfortunately also not in TS!

A strong motivation to avoid the new operator.

TypeScript Example Source

Use the same source as for JS. You can try out on the TypeScript Playground. The result is the same as for JS.

Unfortunately TS does not fix these JS gotchas. Whatever surprise you experience on JS language level, you will have the same in TS.

Java Example Source

You need a Java development kit to try this out.

public class Test
{
     public static void main(String[] args) {
        final String s1 = "10";
        final String t1 = "10";
 
        final String s2 = new String("20");
        final String t2 = new String("20");
        
        System.out.println(
            "\n s1 == t1: "+(s1 == t1)+
            "\n s1 equals t1: "+s1.equals(t1)+
            "\n s2 == t2: "+(s2 == t2)+
            "\n s2 equals t2: "+s2.equals(t2)
        );
    }
}

Output is:

 s1 == t1: true
 s1 equals t1: true
 s2 == t2: false
 s2 equals t2: true

Mind the correct equality comparison in line four, now it is true as expected. Line one and two are exactly the same as in JS, due to compiler-optimized strings.

Nevertheless the difference between plain strings and string objects is a little puzzling, surely it is not intuitive.

Resume

Although both Java and JS are C-style programming languages, there seems to have been no common sense about how to perform comparisons.

Why was it called JavaScript? I always call it JS, and I am glad about the renaming to EcmaScript. The name JavaScript makes newcomers believe it is a Java script-interpreter. What a mistake!




Keine Kommentare: