uncover and score the usages of the underscore

19
Score the Usages of the Underscore Rhein-Main Scala Meetup 02/02/16 Franck Valentin

Upload: franck-valentin

Post on 12-Feb-2017

131 views

Category:

Software


0 download

TRANSCRIPT

Page 1: Uncover and score the usages of the underscore

Uncover and Score

the Usagesof the

UnderscoreRhein-Main Scala Meetup 02/02/16

Franck Valentin

Page 2: Uncover and score the usages of the underscore

var initialization to default value = _class Fooclass DefaultValue[T] { // 1. Declare instance vars with default values: // ----------------------------------------------------------- var int:Int = _ // 0 var double: Double = _ // 0.0 var boolean: Boolean = _ // false var foo: Foo = _ // null

// 2. It works also for type parameters: // ----------------------------------------------------------- var t:T = _ // new DefaultValue[String].t == null // new DefaultValue[Long].t == 0

// 3. Not allowed in methods // ----------------------------------------------------------- def f() { // Doesn't compile. "Local variables must be initialized" // var x:Int = _ e }...

Page 3: Uncover and score the usages of the underscore

var initialization to default value = _...

// 4. Note also: // ----------------------------------------------------------- var any:Any = _ // null var anyRef:AnyRef = _ // null var anyVal:AnyVal = _ // null var n:Null = _ // null // Should the following compile as ‘Nothing’ doesn’t have any value? // Instead, there is a java.lang.NullPointerException at runtime // when trying to use it. var nothing:Nothing = _}

Page 4: Uncover and score the usages of the underscore

Tuples ._1case class Bar(v:Int)

class Tuples {

// _ is a part of the name of tuple getters (_1, _2, ...) // -----------------------------------------------------------

val myTuple = ("a", 3.141, Bar(0)) // An instance of Tuple3[String, Double, Foo] val anotherTuple = Tuple2("b", 2.718)}

// new Tuples().myTuple._1 == "a"// new Tuples().myTuple._2 == 3.141// new Tuples().myTuple._3 == Foo(0)

- _ can be part of a method name (more about that later)

- _1, _2, … _22 for Tuple

Page 5: Uncover and score the usages of the underscore

Unused variables _ =case class Bar(par1: Int, par2: Int, par3: Int)

class UnusedVariables(bar: Bar) {

// 1. Unused variable (no real practical usage here!) // ----------------------------------------------------- var _ = "whatever"

// 2. Unused variables in extractors // ----------------------------------------------------- val myTuple = ("a", 3.141, "b") val (_, pi, myString) = myTuple

// Not only for tuples: val Bar(barP1, _, barP3) = bar

}val uv = new UnusedVariables(Bar(10, 20, 30))// uv.pi == 3.14// uv.myString == "b"// uv.barP1 == 10// uv.barP3 30

Page 6: Uncover and score the usages of the underscore

Unused variables _ =object UnusedVariables2 extends App { val prefixes = List("p1", "p2") val strings = List("aa", "bb", "cc") val suffixes = List("s1", "s2")

// 3. Unused variables can be useful to debug for comprehensions. // ----------------------------------------------------------------

val stringsWithPrefixesAndSuffixes = for { prefix <- prefixes string <- strings stringWithPrefix = prefix + ">" + string //println(stringWithPrefix) // This doesn't compile! _ = println(stringWithPrefix) suffix <- suffixes stringWithPrefixAndsuffix= stringWithPrefix + "<" + suffix } yield stringWithPrefixAndsuffix

// Because of the way Scala translates for comprehensions to foreach/map/flatMap/filter/withFilter // http://docs.scala-lang.org/tutorials/FAQ/yield.html // scalac -Xprint:parser UnusedVariables2.scala}

Page 7: Uncover and score the usages of the underscore

Unused Parameters _ =>object UnusedParameters extends App {

// 1. For anonymous functions: // -------------------------------------------- List(1, 2, 3) map { _ => 0 } // == List(0, 0, 0)

}

...

Page 8: Uncover and score the usages of the underscore

Imports: wildcards and Hiding => _object Imports1 { // 1. _ Similar to * in Java // ------------------------------------------------------------------

import java.util._

val uuid = UUID.randomUUID() val date = new Date()}

object Imports2 { // 2. Add an exception (everything from java.util but Date and Calendar) // ------------------------------------------------------------------

import java.util.{Date => _, Calendar => _, _}

val uuid = UUID.randomUUID() // val date = new Date() // Doesn't compile.}

...

...

Page 9: Uncover and score the usages of the underscore

Imports: wildcards and Hiding => _...

object Imports3 { // 3. Import all the members of an object (works with exceptions too) // ------------------------------------------------------------------

object MyObj { val m1: Int = 1 val m2: String = "a" val m3: Double = 1.0 }

import MyObj.{m3 => _, _}

println(m1) // Instead of MyObj.m1 println(m2) // Instead of MyObj.m2 // println(MyObj.m3) // Doesn't compile.

}

...

Page 10: Uncover and score the usages of the underscore

Varargs (splat operator) _*// 1. _* passes a sequence as multiple parameters// -------------------------------------------------------------

def processParams(params: String*) = params.mkString(",")

processParams("p1", "p2") // == "p1,p2"

val parameters = List("param1", "param2", "param3")//processParams(parameters) // Error: Type mismatch. expected:String, actual:Seq[String]processParams(parameters: _*) // == param1,param2,param3

// 2. _* works in pattern matching too// -------------------------------------------------------------val res = parameters match { case Seq(p1) => s"Only one element $p1" case Seq(p1, seqOfStrings @ _*) => s"First elt is '$p1' and the rest is the sequence '${seqOfStrings}'"}

println(res) // == First elt is 'param1' and the rest is the sequence List(param2, param3)'

Page 11: Uncover and score the usages of the underscore

Anonymous Function Placeholder _ + _// 1. A placeholder for the parameters in an anonymous function// -------------------------------------------------------------

val list = List(1, 2, 3, 4)

val by2 = list map (x => x * 2)val alsoBy2 = list map (_ * 2)

// 2. It works for several parameters as well// -------------------------------------------------------------

val sum = list reduceLeft ((a, b) => a + b)val alsoSum = list reduceLeft (_ + _)

def printFctResult(tuple:(Int, String, Double), fct:(Int, String, Double) => String) = { println(fct(tuple._1, tuple._2, tuple._3))}

printFctResult((2, "a", 3.0), (i,s,d) => i + s + d) // == "2a3.0"printFctResult((2, "a", 3.0), _ + _ + _) // It begins to be obscure!

def fct(i: Int, s: String, d: Double): String = s"${i * d} $s"printFctResult((2, "a", 3.0), (i,s,d) => fct(i,s,d)) // == "6.0 a"printFctResult((2, "a", 3.0), fct(_,_,_))

Page 12: Uncover and score the usages of the underscore

Pattern Matching case _case class MyClass(nameOpt: Option[String], ints: List[Int])

def showMatch(c: Any) { c match { // Wilcard in a class parameter case MyClass(None, _) => println("MyClass without any name.") // Wilcard in a nested class case MyClass(_, List(_)) => println("MyClass with only one element.") // Wilcard in a nested class and splat operator case MyClass(_, List(_, _*)) => println("MyClass with more than one element.") // Wildcard on the type case l:List[_] => println("It's a list !") // Matches everything else case _ => println("Matches everything else.") }}

showMatch(MyClass(None, List(1,2))) // == "MyClass without any name."showMatch(MyClass(Some("c1"), List(1))) // == "MyClass with only one element."showMatch(MyClass(Some("c2"), List(1,2,3))) // == "MyClass with more than one element."showMatch(List("a", "b", "c")) // == "It's a list !"showMatch(Set("a", "b", "c")) // == "Matches everything else."

...

Page 13: Uncover and score the usages of the underscore

Partially Applied Functions g = f(_,_)// Partially applied function: function where only a few // arguments are set during its invocation.

def sendMessage(priority: Int, recipient: String, msg: String) { println(s"$priority: send '$recipient' the message $msg.'")}

// sendMessageToFred == (Int, String) => Unitdef sendMessageToFred = sendMessage(_: Int, "Fred", _: String)sendMessageToFred(1, "Hi Bro!")

// sendImportantMsgToFred == (String) => Unitdef sendImportantMsgToFred = sendMessage(0, "Fred", _: String)sendImportantMsgToFred("An important message.")

Page 14: Uncover and score the usages of the underscore

Eta Expansion v = f _// "Eta-expansion converts an expression of method type to an equivalent expression// of function type."// method: a member of the type the class represents.// function: value of a Function[] type.

// Assign a method to a variable:// ----------------------------------------------------------------------------

case class MyClass() { def f1(int: Int):Unit = println(int)

val constant = 35 def f2(int1: Int, int2: Int):String = (int1 + int2 + constant).toString}

// valF1: Int => Unit = <function1> (Function1[Int, Unit])val valF1 = MyClass().f1 _valF1(1)// valF2: (Int, Int) => String = <function2> (Function2[Int, Int, String)val valF2 = MyClass().f2 _valF2(5, 2)...

Page 15: Uncover and score the usages of the underscore

Eta Expansion v = f _…

case class MyOtherClass() {

def f(g: () => Int):Int = 1 def f(i:Int):Int = 2

}

def g() = 3

MyOtherClass().f(g) // == 2

// You have to write the _ whenever the compiler is not explicitly expecting// a Function object.MyOtherClass().f(g _) // == 1. _ 'asks' the compiler to treat g a a Function object.

Page 16: Uncover and score the usages of the underscore

Existential Types// Existential type: express that you have a type (e.g. List, Array) with an unknown// element type (an unknown "type parameter") : List[<I don't know>].// "List[<I don't know>]" could be rephrased as "List[T] forSome {type T}"//def count1(l: List[T] forSome {type T}) = l.sizecount1(List(1, 2, 3))count1(List("a", "b"))

// Equivalent to:def count2(l: List[_]) = l.sizecount2(List(1, 2, 3))count2(List("a", "b"))

// It works for higher kinded types as well.// Higher kinded type : A type constructor that takes type constructor(s)

// Higher kinded type 'Iterable' has the type constructor 'Container'.trait Iterable[A, Container[_]] { def map[B](f: A => B): Container[B]

def filter(p: A => Boolean): Container[A]}

Page 17: Uncover and score the usages of the underscore

Identifier Names Ending with an operator _!// 1. alphanumeric + _ + operator identifier (+, ++, :, ?, ~, # :> ...)// ----------------------------------------------------------------------------

trait WhatATrait_! {

def isItUsefult_?() // 2. _ followed by a letter(s), digit(s), or underscore(s). // -------------------------------------------------------------------------- def _abc() def _123() def __()

}

Page 18: Uncover and score the usages of the underscore

Assignment Operator def f_=( )// Special case for an identifier name ending with _=// A way to define getters and setters.// ------------------------------------------------------------------

class MyClass { private var myInt0:Int = _

// Getter: def myInt:Int = myInt0

// Setter: def myInt_=(i:Int) { require(i>0) println(s"I'm setting myInt = $i") myInt0 = i }}

val myClass = new MyClassmyClass.myInt = 5 // Setter: Desugared into myClass.myInt_=(5)println(myClass.myInt) // GettermyClass.myInt = -1 // java.lang.IllegalArgumentException: requirement failed

Page 19: Uncover and score the usages of the underscore