0xDEADBEEF

RSS odkazy
««« »»»

Porovnání Javy a Scaly v porovnávání

20. 12. 2019 #JVM #Scala #Java

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.

píše k47 (@kaja47, k47)