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