Porovnání Javy a Scaly v porovnávání
Do Scaly verze 3, vyvíjené jako projekt dotty, se možná dostane explicitní nullovost proměnných.
var x: String // nemůže být null var x: String|Null // může být null
Odersky a jeho gang tak chtějí odeseknout pár drobných z Hoarova omylu za miliardu dolarů a eliminovat tolik otravných NPE, jak jen bude možné. Nabízí se ale jedna další otázka: Zrychlí to výsledný program?
Může.
Ve Scale má porovnání na starosti operátor ==
, který se chová jako equals()
v Javě s jedninou výjimkou: null == x
nevyhodí NPE jako null.equals(x)
.
Scala tedy musí při porovnání provádět jednu kontrolu navíc.
Z metoda obsahující jen x.equals("xxx")
javac
vygeneruje tento bytekód:
0: aload_1 1: ldc #2 // String xxx 3: invokevirtual #3 // Method java/lang/String.equals:(Ljava/lang/Object;)Z 6: ireturn
A tuhle monstrozitu x == "xxx"
vyplodí scalac
:
0: aload_1 1: ldc #12 // String xxx 3: astore_2 4: dup 5: ifnonnull 16 8: pop 9: aload_2 10: ifnull 23 13: goto 27 16: aload_2 17: invokevirtual #16 // Method java/lang/Object.equals:(Ljava/lang/Object;)Z 20: ifeq 27 23: iconst_1 24: goto 28 27: iconst_0 28: ireturn
S přepínačem -optimize
je výsledný bytekód o něco menší, ale pořád delší než
produkt javac
.
JIT je velice efektivní v optimalizačních kouzlech, proto nezáleží jak to vypadá, ale jaký je reálný dopad na reálnou rychlost na reálném stroji.
Benchmark Score Error Units EqJava.strEqVar 6,162 ± 0,003 ns/op // "xxx".equals(str) EqJava.varEqStr 6,163 ± 0,009 ns/op // str.equals("xxx") EqScala.strEqVar 6,935 ± 0,014 ns/op // "xxx" == str EqScala.varEqStr 6,934 ± 0,010 ns/op // str == "xxx"
Rozdíl je malý, ale přesto viditelný. Takže když se o proměnné ví, že nemůže
být null, ==
operátor může vygenerovat jednodušší a o něco málo rychlejší
bytekód.