"WAT²" von Tim Hegemann
WAT²
Gary Bernhard’s talk:
https://www.destroyallsoftware.com/talks/wat
Let’s talk about JavaScript
> [] + []
''
> [] + {}
'[object Object]'
> {} + []
0
> {} + {}
NaN
Or if your’re on V8:
> {} + {}
'[object Object][object Object]'
> Array(11)
[ <11 empty items> ]
> Array(11).join("wat")
'watwatwatwatwatwatwatwatwatwat'
> Array(11).join("wat" + 1)
'wat1wat1wat1wat1wat1wat1wat1wat1wat1wat1'
> Array(11).join("wat" - 1) + " Batman!"
'NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN Batman!'
https://www.w3schools.com/js/js_type_conversion.asp this will not really help to understand this (but they try…) {}
usually is refered as the ‘empty object’ somtetimes it’s just an empty block. V8 will always treat {}
as object and thus prints '[object Object][object Object]'
when evaluating {} + {}
. Firefox for example interprets the first {}
as empty block. {} + {}
evaluates like {}; +{}
converting the empty object to number and therefore returning NaN
.
> 3..toString()
'3'
> 3.toString()
Thrown:
3.toString()
^^
SyntaxError: Invalid or unexpected token
In JavaScript 3.
is a valid number literal 3.toString()
is not.
> ['10','10','10','10'].map(x => x + 1)
[ '101', '101', '101', '101' ]
> ['10','10','10','10'].map(parseInt)
[ 10, NaN, 2, 3 ]
The parameter of map
is function callback(currentValue[, index[, array]]
. The function parseInt
has parameters string
and radix
. So the index of every element is passed as radix with ‘10’ to the radix 0 is obviously 10, ‘10’ to the radix 1 is NaN, and so on…
> let a = []
undefined
> a[10] = 1
1
> a.length
11
> a[4294967296] = 42
42
> a[4294967296]
42
> a.length
11
The value of the length property is an integer with a positive sign and a value less than 2 to the 32nd power (232). Numeric overflow is not handled correctly.
Let’s talk about Python
>>> a = [[1]] * 7
>>> a
[[1], [1], [1], [1], [1], [1], [1]]
>>> a[1] = 7
>>> a
[[1], 7, [1], [1], [1], [1], [1]]
>>> a[0][0] = 2
>>> a
[[2], 7, [2], [2], [2], [2], [2]]
References…
Let’s talk about Java
Integer a = 42;
Integer b = 42;
Integer x = 1000;
Integer y = 1000;
jshell> a == a
$5 ==> true
jshell> a == b
$6 ==> true
jshell> x == y
$7 ==> false
Objects in Java are compared by reference when using ==
. For numbers smaller than 256 Java has a common pool of objects with their Integer representations so these are the same objects. Larger numbers become separate objects so their references do not match.
jshell> 022 + 4
$8 ==> 22
022
is octal for 18.
jshell> (byte) + (char) - (int) + (long) - 1
$9 ==> 1
This just chains casting and unary operators on number types.
jshell> for (int i = 10; i --> 0;) {
...> println(i);
...> }
9
8
7
6
5
4
3
2
1
0
i-- > 0
Let’s talk about Scala
implicit class MyInt(i: Int) {
def is(j: Int): Boolean = i == j
def ⩵(j: Int): Boolean = i == j
}
@ 1 is 1
res1: Boolean = true
@ 1 ⩵ 1
res2: Boolean = true
@ 1 + 3 is 2 + 2
res3: Boolean = true
@ 1 + 3 ⩵ 2 + 2
cmd4.sc:1: overloaded method value + with alternatives:
(x: Double)Double <and>
(x: Float)Float <and>
(x: Long)Long <and>
(x: Int)Int <and>
(x: Char)Int <and>
(x: Short)Int <and>
(x: Byte)Int <and>
(x: String)String
cannot be applied to (Boolean)
val res4 = 1 + 3 ⩵ 2 + 2
^
Compilation Failed
Operators starting with a letter have a lower precedence than any other operator, those starting with a special character like ⩵ have higher precedence than any other operator. See https://scala-lang.org/files/archive/spec/2.11/06-expressions.html#infix-operations.