48
What Can Scala Puzzlers Teach Us? Daniel C. Sobral

What can scala puzzlers teach us

Embed Size (px)

DESCRIPTION

A look at some of the most common puzzlers faced by Scala beginners.

Citation preview

Page 1: What can scala puzzlers teach us

What Can Scala Puzzlers Teach Us?Daniel C. Sobral

Page 2: What can scala puzzlers teach us

Disclaimer #1: "Puzzlers"

● Java Puzzlers (the book/presentations):○ Weird behavior in Java that is difficult to predict or

explain● This presentation:

○ Weird behavior in Scala that confounds beginners■ (and sometimes experienced programmers)

○ FAQs, not Fun

Page 3: What can scala puzzlers teach us

I can't speak for any of the people who contributed to create and turn Scala into what it is. Furthermore, if you learn anything from this presentation, learn that a perfect understanding of Scala is an unlikely achievement...

Disclaimer #2: don't trust me.

Page 4: What can scala puzzlers teach us

Symbols, operators and punctuation

● What does it mean?● Where can I find information about it?● WTF?

Page 5: What can scala puzzlers teach us

The symbol puzzler

Source: Stack Overflow

Page 6: What can scala puzzlers teach us

The Origin of the Symbols

● Punctuation elements of the language○ @ # ( ) [ ] { } , . ; : ` ' "

● Keywords, reserved symbols and XML○ <- => <: >: <% // /* */ _* <? <!

● Normal definitions from libraries○ <:< =:= ☆ ★ η :/

● Underscore○ All of the above!

Page 7: What can scala puzzlers teach us

Symbols may be part of the language or come from external libraries; it can be difficult to tell where they begin and end; they are difficult to search for on the Internet, non-mnemonic and unpronounceable.

Page 8: What can scala puzzlers teach us

Then why?

def f(xs: Array[Int], a: Int, b: Int) =

for (i <- xs.indices)

xs(i) = a * i + b

Page 9: What can scala puzzlers teach us

So that libraries can extend the language seamlessly

def f(xs: M[T], a: T, b: T) =

for (i <- xs.indices)

xs(i) = a * i + bFor M and T library-types that support these operations

Page 10: What can scala puzzlers teach us

Which still doesn't really justify unicode...

Page 11: What can scala puzzlers teach us

Advice regarding Symbols

● Learn the language:○ What symbols are "built-in"○ The syntax rules

● If exploring code using unknown libraries,○ Use an IDE to explore it

harsh, indeed...

Page 12: What can scala puzzlers teach us

implicit def KleisliCategory[M[_] : Monad]: Category[({type λ[α, β] = Kleisli[M, α, β]})#λ] = {

new Category[({type λ[α, β] = Kleisli[M, α, β]})#λ] {

def id[A] = ☆(_ η)

def compose[X, Y, Z](f: Kleisli[M, Y, Z], g: Kleisli[M, X, Y]) = f <=< g

}

}

Let's try to figure this one out

Page 13: What can scala puzzlers teach us

implicit def KleisliCategory[M[_] : Monad]: Category[({type λ[α, β] = Kleisli[M, α, β]})#λ] = {

new Category[({type λ[α, β] = Kleisli[M, α, β]})#λ] {

def id[A] = ☆(_ η)

def compose[X, Y, Z](f: Kleisli[M, Y, Z], g: Kleisli[M, X, Y]) = f <=< g

}

}

Split Scala Syntax from Identifiers

Page 14: What can scala puzzlers teach us

implicit def KleisliCategory[M[_] : Monad]: Category[({type λ[α, β] = Kleisli[M, α, β]})#λ] = {

new Category[({type λ[α, β] = Kleisli[M, α, β]})#λ] {

def id[A] = ☆(_ η)

def compose[X, Y, Z](f: Kleisli[M, Y, Z], g: Kleisli[M, X, Y]) = f <=< g

}

}

Identify what we are defining

Page 15: What can scala puzzlers teach us

implicit def KleisliCategory[M[_] : Monad]: Category[({type λ[α, β] = Kleisli[M, α, β]})#λ] = {

new Category[({type λ[α, β] = Kleisli[M, α, β]})#λ] {

def id[A] = ☆(_ η)

def compose[X, Y, Z](f: Kleisli[M, Y, Z], g: Kleisli[M, X, Y]) = f <=< g

}

}

Where we are using our definitions

Page 16: What can scala puzzlers teach us

implicit def KleisliCategory[M[_] : Monad]: Category[({type λ[α, β] = Kleisli[M, α, β]})#λ] = {

new Category[({type λ[α, β] = Kleisli[M, α, β]})#λ] {

def id[A] = ☆(_ η)

def compose[X, Y, Z](f: Kleisli[M, Y, Z], g: Kleisli[M, X, Y]) = f <=< g

}

}

What's left are outside identifiers

Page 17: What can scala puzzlers teach us

The Underscore

● What does it mean?● Why does it work here but not here?● WTF?● It's everywhere! It's the borg operator!

Page 18: What can scala puzzlers teach us

One underscore puzzler

Source: Stack overflow

Page 19: What can scala puzzlers teach us

The meanings of underscore

Source: myself, by way of Stack Overflow

Page 20: What can scala puzzlers teach us

The underscore is Scala's wildcard; it means "something" or "anything" and even "nothing". However, it's semantics can be widely different, even in similar contexts.

Page 21: What can scala puzzlers teach us

Why?

● ???● Picking a different symbol for each case

would stretch ASCII● Picking keywords is not in the spirit of Scala● They are somewhat intuitive

○ except when they bite you

Page 22: What can scala puzzlers teach us

Advice regarding underscore

● Intuition does go a long way● But, again, learn the language● And, in particular, know the difference

between these:○ f _○ f(_, y)○ f(x + _, y)

Page 23: What can scala puzzlers teach us

Eta, partial function application and placeholders

● f _○ an eta expansion: turn method f into an anonymous function.

● f(_, y)○ a partial function application: creates an anonymous function from

method f, whose parameters are the ones wholly replaced by underscores.

● f(x + _, y)○ a placeholder: creates an anonymous function from the expression "x

+ _", whose parameters are the underscores (and that function gets passed to f).

Page 24: What can scala puzzlers teach us

_ always picks the tightest non-degenerate scope it can

Seth Tisue

Page 25: What can scala puzzlers teach us

Erasure

● Where are my types?● How do I get them back?● WTF?

Page 26: What can scala puzzlers teach us

Some things that don't work

trait X {

def overload(f: Int => Int)

def overload(f: String => String)

}

Page 27: What can scala puzzlers teach us

Some things that don't work

def f[T](list: List[T]) = list match {

case _: List[Int] => "Ints"

case _: List[String] => "Strings"

case _ => "???"

}

Page 28: What can scala puzzlers teach us

Some things that don't work

class C[T] {

def f(obj: Any) = obj match {

case _: T => "Ours"

case _ => "Not Ours"

}

}

Page 29: What can scala puzzlers teach us

Why?

● JVM does not support "type parameters"● If Scala added metadata to "eliminate"

erasure, the interaction gap between it and Java would be much greater○ Though things like implicits and default parameters

already do it, to some extent○ At least, implicits and defaults are easy to avoid

Page 30: What can scala puzzlers teach us

Some things that don't work

trait X {

def overload(f: Function1[Int, Int])

def overload(f: Function1[String, String])

}

Page 31: What can scala puzzlers teach us

Erasure at work

trait X {

def overload(f: Function1)

def overload(f: Function1)

}

Page 32: What can scala puzzlers teach us

Erasure at work

def f(list: List) = list match {

case _: List => "Ints"

case _: List => "Strings"

case _ => "???"

}

Page 33: What can scala puzzlers teach us

Erasure at work

class C {

def f(obj: Any) = obj match {

case _: Any => "Ours"

case _ => "Not Ours"

}

}

Page 34: What can scala puzzlers teach us

A partial solution

class C[T : ClassTag] {

def f(obj: Any) = obj match {

case _: T => "Ours"

case _ => "Not Ours"

}

} though it will still ignore T's type parameters

Page 35: What can scala puzzlers teach us

Initialization Ordertrait A {

val a: Int

val b = a * 2

}

class B extends A {

val a = 5

println(b)

}

new B

Page 36: What can scala puzzlers teach us

All val’s are initialized in the order they are found.

Page 37: What can scala puzzlers teach us

Initialization Ordertrait A { val foo: Int val bar = 10 println("In A: foo: " + foo + ", bar: " + bar)}

class B extends A { val foo: Int = 25 println("In B: foo: " + foo + ", bar: " + bar)}

class C extends B { override val bar = 99 println("In C: foo: " + foo + ", bar: " + bar)}

new C

Source: Paul Phillips scala-faq by way of scala puzzlers

Page 38: What can scala puzzlers teach us

Initialization OrderIn A: foo: 0, bar: 0

In B: foo: 25, bar: 0

In C: foo: 25, bar: 99

Page 39: What can scala puzzlers teach us

Initialization Ordertrait A { val foo: Int val bar = 10 println("In A: foo: " + foo + ", bar: " + bar)}

class B extends A { val foo: Int = 25 println("In B: foo: " + foo + ", bar: " + bar)}

class C extends B { override val bar = 99 println("In C: foo: " + foo + ", bar: " + bar)}

new C

Page 40: What can scala puzzlers teach us

A val is initialized only once.

Page 41: What can scala puzzlers teach us

Initialization Ordertrait A { val x = 5 }

trait B {

val x: Int

println(x * 2)

}

trait C extends A with B

trait D extends B

class E extends D with C { println(x * 2) }

class F extends C with D { println(x * 2) }

new E

new F

Page 42: What can scala puzzlers teach us

Initialization Order0

10

10

10

Page 43: What can scala puzzlers teach us

Initialization Ordertrait A { val x = 5 }

trait B {

val x: Int

println(x * 2)

}

trait C extends A with B

trait D extends B

class E extends B with D with A with B with C { println(x * 2) }

class F extends A with B with C with B with D { println(x * 2) }

new E

new F

Page 44: What can scala puzzlers teach us

Trait linearization...

Page 45: What can scala puzzlers teach us

Advice regarding initialization order

● Learn the _________

Page 46: What can scala puzzlers teach us

Other things to look out for

● Pattern matching on val's and for's● All sorts of things implicit● Syntactic sugars, auto-tupling and the like● The return keyword

Page 47: What can scala puzzlers teach us

So, what did I learn?

It seems to me that there's a wide range of Scala features that depend on the user having deep knowledge of the language when something goes wrong. "What's going on?" seems to be much more common than "How do I do this?"

Page 48: What can scala puzzlers teach us

As for real Puzzlers...● Site:

○ http://scalapuzzlers.com/● Book:

○ http://www.artima.com/shop/scala_puzzlers