Skip to content

Instantly share code, notes, and snippets.

@acominotto
Last active August 29, 2015 13:57
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save acominotto/9506045 to your computer and use it in GitHub Desktop.
Save acominotto/9506045 to your computer and use it in GitHub Desktop.

What is Scala?


Créé par Martin en 2003 -- Son nom vient de l'anglais Scalable language Scala intègre les paradigmes de programmation orientée objet et de programmation fonctionnelle, avec un typage statique


  1. Fonctionnel basique

a) Immutability

avantages: thread-safe et referential transparancy inconvénients: pas simple à mettre en place dans un environnement où les objets contiennent des états

une fonction f(a) est dite référentiellement transparante si à tout instant t, pour un élément a donné, le résultat est le même.

b) Les fonctions sont des objets?!

Tous les éléments du scala sont des objets, même les fonctions. Cela implique que l'on peut les passer en paramètre d'une autre fonction que l'on appelera alors Higher Order Fonction (Fonction de rang supérieur).

 def profile(a: Int, f : Int => Int) = {
      val r = f(a)
      println(s"value = $r")
      r
 }
 val f = {i: Int => i + 42}
 profile(3, f)

c) Pattern Matching

sert à décomposer et récupérer des éléments à l'intérieur d'une structure de données

case class MyClass(a: Int)

MyClass(scala.util.Random.nextInt(100)) match {
 case MyClass(42) => println("Bravo, tu as trouvé la réponse universelle!")
 case MyClass(n) => println(s"$n n'est pas la réponse universelle...")
}

d) Monads

Une monade est une fonction qui encapsule un élément. Le contrat d'une monade spécifie que deux méthodes pourront être effectuées sur celle-ci: unit et bind. unit consiste à encapsuler une valeur dans une monade. bind permet d'effectuer une opération sur celle-ci.

trait Monad[T] {
  def flatMap[U](f: T => Monad[U]): Monad[U] //bind
}
def unit[T](x: T): Monad[T]

Voyez-vous ce qui pourrait être, en java, une monade? (Collections, try-catch)


e) Example Option[T]

Option possède deux sous classes: Some et None. Cette monade peut donc posséder une valeur ou aucune et a pour intérêt d'éviter les NPE. Exemple:

val foo = Some(42).flatMap(i => if(i == 42) Some(s"La réponse universelle est $i") else None)
foo match {
     case Some(v) => println(v)
     case None => println("Whoops, nothing...")
}
  1. Les traits

Les traits c'est entre les classes abstraites et les interfaces. Un trait c'est une class abstraite avec l'avec l'avantage qu'une classe peut hériter de plusieurs traits. On parlera alors de composition ou "mixin"

class Animal {
     override def toString = "I'm an animal"
}

trait Flying extends Animal {
     override def toString = s"${super.toString} and I fly"
}

trait Swimming extends Animal {
     override def toString = s"${super.toString} and I swim"
}

val swimmingBird = new Animal with Flying with Swimming
val flyingFish = new Animal with Swimming with Flying
  1. Les collections

Toute personne qui a programmé un jour ou l'autre connait la notion de collection.

Scala nous fournit sa propre implémentation qui utilise les fonctions ainsi que deux types distincts de collection: les collections mutable et immutable.

Les collections mutables sont semblables à celles de Java à ceci prêt que leurs API fournit des méthodes telles que filter, map, folds, reduce, ...

Les collections immutables fournissent les même fonctionnalités et ne sont plus modifiées après leur création, ce qui les rend thread safe. Nous allons vous décrire quelques méthodes non présentes en Java (1.7) de l'API de collection.

a) filter

Signature: List[T]# filter(f: T => Boolean): List[T]

Comme le décrit sa signature, filter va prendre une fonction qui, pour un objet de type T donné, renverra un Boolean.

Exemple:

persons.filter(p => p.age <= 25) //Renvoie toutes les personnes dont l'âge est inférieur à 25 ans

b) map

Signature List[T]# map[U](f: T => U): List[U]

map va transformer tous les éléments de la liste suivant la fonction f.

Exemple:

persons.map(p => p.name + " " + p.firstName) // renverra une liste de tous les noms et prénoms des personnes.

c) flatMap

Signature: List[T]# flatMap[U](f: T => List[U]): List[U]

flatMap va transformer chacun de ses éléments en liste puis concaténer ces listes (Héritage monadique!)

Exemple:

persons.flatMap(p => p :: friends.filter(f => f.age == p.age))

d) fold (Left or Right)

Signature: List[T]# foldLeft[U](acc: U)(f: (U, T) => U)

foldLeft va parcourir la liste de gauche à droite et effectuer un traitement à l'aide d'un accumulateur

Exemple:

persons.foldLeft((0,0)) { (acc, p) => p.sex match {
         case Female => (acc._1 + 1, acc._2)
         case Male => (acc._1, acc._2 + 1)
         case _ => acc
     }

}

e) for comprehension loop

La boucle for en scala est une manière simplifiée d'utiliser les filter, map et flatMap sur les monades.

Exemple:

for{
    p <- persons
    f <- friends if(f.age == p.age)
} yield (p, f) // renvoie la liste des personnes ainsi que leurs amis associés (ceux qui ont le même âge, le monde est beau)

revient à écrire

persons.flatMap{p =>
    friends
          .filter(_.age == p.age)
          .map(f => (p, f)) 
}
  1. Les implicits

On distingue 2 types d’implicit : Les conversions implicites : implicit def Le passage de paramètres/valeur : implicit val, implicit var // Note : Il existe aussi des objets implicites


implicit val x = 5
def inc(implicit i: Int) = i + 1

case class Person(age: Int, name: String) { def tellAge = println(s"$name >> $age")}
implicit def tupleToPerson(t: (Int, String)): Person = Person(t._1, t._2)
(28, "Alexis").tellAge

def sorted[B >: A](implicit ord: math.Ordering[B]): List[A]
object AgeOrdering extends Ordering[Person] {
     def compare(a: Person, b: Person) = a.age compare b.age
}
person.sorted
  1. Asynchrone (La promesse d'un futur)

Pourquoi en avons-nous besoin?

val socket = Socket()
val paquet = socket.readFromMemory()
socket.sendToUSA(paquet)

[Tableau -- http://norvig.com/21-days.html#Answers]

val socket = Socket()
val paquet = socket.readFromMemory() //50 000 ns
socket.sendToUSA(paquet) // 150 000 000 ns

[Tableau converti 1sec = 1 nanosec]

val socket = Socket()
val paquet = socket.readFromMemory() // 3 jours
socket.sendToUSA(paquet) // 5 ans

Nous bloquerions donc l'accès à l'application pendant plus de 5 ans !!

INTRODUCING: Les Futures.

Future[T] est une monade qui permet d'allouer un thread qui va effectuer l'action demandée. Celle-ci, à sa complétion, lancera les callbacks qui lui étaient assignées.

/!\ Pittfalls, La programmation asynchrone ne fonctionne pas comme la programmation séquentielle /!\


    import scala.concurrent.ExecutionContext.Implicits.global
    import scala.concurrent.Future
    val socket = Socket()
    val paquet = Future { socket.readFromMemory()  }// paquet est maintenant une future...
    socket.sendToUSA(paquet) // FAUX: paquet est une future !!!
    
    val futurAck = paquet.flatMap { p =>
      Future { socket.sendToUSA(p) }
    }

Aux futures s'ajoutent les Promise[T]. Une promesse est une future sur laquelle on a entièrement la main: on décide quand elle se termine et avec quelle valeur elle se termine. Dès lors, si on souhaite qu'une future ne se termine jamais (tests...), on peut utiliser:

Promise[T]().future

Si on veut que lorsque l'on recoit le paquet, on l'envoie en parallèle aux USA et en Chine et vérifier laquelle se termine la première:

import scala.concurrent._
import ExecutionContext.Implicits.global

val promise = Promise[String]()

promise.future.map(w => println(s"$w FIRST!"))

def sendToUsa(message: String) = Future {Thread.sleep(scala.util.Random.nextInt(5000)); message}.map(m => promise.success(s"USA received $m"))
def sendToChina(message: String) = Future {Thread.sleep(scala.util.Random.nextInt(5000)); message}.map(m => promise.success(s"China received $m"))


sendToUsa("Hello!"); sendToChina("Ni hao!")
@andypetrella
Copy link

z'en avez pour combien d'heures de talk les gats ;-). N'oubliez pas que ce n'est pas une démonstration mais il faut que l'audience suive ^^.
Dans le lineup actuel vous en perdez une bone partie au Monade et une autre au flatMap ^^.
D'autant plus ce serait dommage de ne pas montrer la puissance, et de la noyer dans les fonctionnalités. Par exemple le Pattern Matching est une killer feature et sera noyée. A côté de ça vous parler de Monade pour parler d'Option? QUel est le motif.

Je vous conseille de vous concentrer sur un ou deux messages que vous voulez faire passer, et qui vont marquer les esprits, voire de les inciter à passer à Scala :-P.

Mes ce ne sont que mes 0.2 cents :-)

@acominotto
Copy link
Author

L'idée serait de ne pas parler des monades donc (l'idée était justement de faire comprendre que c'était easy...) mais mettre plus l'accent sur le pattern matching me parait une excellente idée!

Les exemples seront que l'on fera un copy paste de la prez vers la console pour montrer qu'on raconte pas de connerie...

Donc, on laisse tomber les monades et on accentue le pattern matching! C'est pas facile de savoir ce qui est accessible et ce qui l'est pas quand on en a compris les concepts.

EDIT: On veut essayer de tenir 45 minutes -> 1 heure

@andypetrella
Copy link

Comme vous le sentez, mais ca me semble une bonne idée.
Ce qu'il faut vous poser comme question est: qu'est ce que je veux qu'il se rappelle après le talk.

Dans mon cas, si ça tient c'est : "L'ecosysteme est riche, etendu et efficace". Donc je montre simplement que les tools s'imbriquent pour former un use case E2E. Sans vraiment avoir besoin d'expliquer le comment ca marche à l'intérieur, mais donner une intuition de savoir comment ca marche de l'exterieur

45 minutes c'est super short, je vous le dit ;-)

@avandendaele
Copy link

Ca me va aussi de laisser de côté les monades. Car je ne l'ai pas compris du premier coup non plus.
Comme le dis Andy, ce qui est important est de savoir ce qu'on veux que les gens se rappelle après le talk.
C'est autant plus vrai que l'introduction de nouvelles techno par chez nous, c'est pas ce qu'il y a de plus rapide.
Je trouve que l'objectif devrait être que c'est fun, concis, rapide et sans devoir fait un reset de leur projets.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment