"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.

Last modified: Wednesday, 11 December 2019, 6:42 PM