On Github alexbergeron / scala4py-slides
Alexandre Bergeron Backend Developer @ Wajam @AlexBergeron2
Montreal Python 43 - Artistic Baboon February 10, 2014
Values and variables - strong focus on immutability
// Mutable var mutableVariable = "Test" // Type String infered mutableVariable = "SomethingElse" // Immutable val immutableValue = 42 // Type Int infered //immutableValue = 0 // error: reassignment to val // We've got Java Arays - we just don't use them a lot val someArray = Array("Hello", "World") someArray(1) = "Scala" // They're mutable println(someAray.mkString(" "))
Control statements
val meetup = "Montreal Python" if (meetup.contains("Python")) { println("You can see me") } else { // Dead code here } // if can also return a value, or be a one-liner val foo = if (presenterRunningOutOfImagination) bar else baz try { // Something that might throw an exception } catch { case e => // Handle that exception }
More control statements
// Scala also has while and do...while loops // But they're seen as bad practice and used mostly for optimizations while (someCondition) { executeSomeOtherTasks() } for (i <- 1 to 5) println(i) // Syntactic sugar for (1 to 5).foreach(i => println(i))
Function declaration
// Our first function def multiply(x: Int, y: Int): Int = x * y multiply(2, 3) // Unit-returning function def show(i: Int): Unit = { println("show(" + i + ")") } // Or, as an anonymous function def anon = (x: Int, y, Int) => x * y // Type Infered anon(2, 3) // Functions can take functions as a parameter def applyOperation(value: Int, oper: Int => Int): Int = oper(value)
Object-oriented - class, object, extends
abstract class Foo { def a: String } // Classes can only inherit from one other class class Bar extends Foo { def a = "Bar" } // Singleton objects - can behave like a class object Baz extends Foo { def a = "Baz" } println(baz.a) // Companion objects can also be created for existing classes
Python
# Lists - Ordered, duplicates allowed a_list = [1, 2, 3, 4] # Tuples - Ordered, fixed a_tuple = (1, 2, 3) a, b, c = a_tuple # Sets - Unordered, duplicates not allowed a_set = {1, 2, 3, 3} # {1, 2, 3} # Dicts - Binds keys to values a_dict = {"one": 1, "two": 2}
Scala
// Collections are immutable by default // Mutable versions available // Seqs - Ordered, duplicates allowed val seq = Seq(1, 2, 3, 4) val list = List(1, 2, 3, 4) // 1 :: 2 :: 3 :: 4 :: Nil // Tuples - Ordered, fixed val tuple = (1, 2, 3) val (a, b, c) = tuple // Sets - Unordered, duplicates not allowed val set = Set(1, 2, 3, 3) // Set(1, 2, 3) // Map - Binds keys to values val map = Map("one" -> 1, "two" -> 2)
Python
[x * x for x in range(1, 4)] # [1, 4, 9] [x for x in range(1, 10) if x % 3 == 0] # [3, 6, 9] [(x, y) for x in range(1,5) for y in range(x, 5) if x + y == 5] # [(1, 4), (2, 3)]
Scala
for (x <- 1 to 3) yield x * x // Vector(1, 4, 9) for (x <- 1 to 10 if x % 3 == 0) yield x // Vector(3, 6, 9) for { x <- 1 until 5 y <- x until 5 if x + y == 5 } yield (x, y) // Vector((1,4), (2,3))
Python
map(lambda x: x * x, range(1, 4)) # [1, 4, 9] filter(lambda x: x % 3 == 0, range(1,10)) # [3, 6, 9] from itertools import combinations def sum_is_five(tuple): x, y = tuple return x < y and x + y == 5 filter(sum_is_five, combinations(range(1, 5), 2)) # [(1, 4), (2, 3)]
Scala
(1 to 3).map(x => x * x) // Vector(1, 4, 9) (1 to 10).filter(_ % 3 == 0) // Implicit parameter // Vector(3, 6, 9) (1 until 5).combinations(2).filter(_.sum == 5).toList // List(Vector(1, 4), Vector(2, 3)) // Or, closer to what the for-comprehension executes def sumIsFive(t: (Int, Int)) = { val (x, y) = t x + y == 5 } (1 to 5).flatMap(x => (x to 5).map((x, _))).filter(sumIsFive) // Vector((1,4), (2,3))
Pattern matching
// Looks like switch from Java def sign(n: Int) = n match { case 0 => "zero" // Supports guards case n if < 0 => "negative" case _ => "positive }
Pattern matching
// Gets even better with extractors // Like when pattern matching with lists def sum(lst: List[Int]): Int = lst match { case head :: tail => head + sum(tail) case Nil => 0 }
Option - Avoiding nulls
// Option[A] type has two possible values // Some(value: A) // None // This allows to avoid nulls and NullPointerException def greet(name: Option[String]): Unit = { println("Hello " + name.getOrElse("world")) } greet(Some("Python")) greet(None)
Option - Avoiding nulls
// Option also fits into pattern matching def respond(result: Option[String]): Unit = result match { case Some(r) => println("Response sent: " + r) case None => println("No response sent") }
Try - Avoiding calls to try
// Like Option, Try[A] has two possible values // Success(value: A) // Failure(t: Throwable) // And it can be used with pattern matching Try(4 / 2) // Success(2) Try(1 / 0) // Failure(java.lang.ArithmeticException: / by zero)
case class - Easy way to create class that integrates with Pattern Matching
case class Person(name: String, city: String, job: Option[String]) // Every parameters in that constructor is now an immutable field def makeStringForPerson(p: Person) = { println(p.name + " - " p.job,getOrElse("unemployed") + " in " + p.city) } // You can also easily clone a case class def moveTo(p: Person, c: String) = p.copy(city = c) // As you'll see, you can also have case objects
Traits - Allows to inherit from multiple traits with implementations
trait A { def toImplement(): Int } trait B { val value = 42 def implemented() = value } class C extends A with B { def toImplement() = implemented() }
Traits - Allows to inherit from multiple traits with implementations
// sealed = you can't implement this trait outside of this file // The + in front of means it's covariant. sealed trait Option[+A] { def getOrElse(value: A) = this match { case Some(v) => v case None => value } } case class Some[+A](value: A) extends Option[A] case object None extends Option[Nothing] // Nothing = Bottom type
Made with reveal.js