“Insulin” for Scala’s
Syntactic Diabetes
Tzach Zohar // Kenshoo // Scalapeño 2016
OR:
How to adopt Scala and
survive
source
source
Who am I
NOT Chuck Norris!
Scala “Advanced Beginner” / “Competent”
System Architect @ Kenshoo
Who’s Kenshoo
10-year Tel-Aviv based startup
Industry Leader in Digital Marketing
Java + JavaScript shop
http://kenshoo.com/
Scala @ Kenshoo
5 services written in Scala
More to come...
Internal Scala course on the go
What’s so scary?
trait GeneralizedCategory {
type U <: Hom
type =>:[A >: U#L <: U#H, B >: U#L <: U#H] = U#C[A, B]
def id[A >: U#L <: U#H]: A =>: A
def compose[A >: U#L <: U#H, B >: U#L <: U#H, C >: U#L <: U#H](
f: B =>: C, g: A =>: B): A =>: C
def *[UY<:Hom](that : GeneralizedCategory {type U=UY}) =
Category.ProductCategory[U,UY](this,that)
}
source
source
source
def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That
Now for some sane examples
source
val tuples = List((1, 374), (3, 42), (5, 693))
val ids = tuples.map(_._1)
val ids = tuples.map(tuple => tuple._1)
val ids = tuples.map { tuple => tuple._1 }
val tuples = List((1, 374), (3, 42), (5, 693))
val ids = tuples.map(_._1)
val ids = tuples.map(tuple => tuple._1)
val ids = tuples.map { tuple => tuple._1 }
val ids = tuples.map(t => t match { case (id, value)=> id })
val ids = tuples.map(_ match { case (id, value) => id })
val ids = tuples.map({ case (id, value) => id })
val ids = tuples.map { case (id, value) => id }
val ids = tuples.map { case (id, _) => id }
case class Profile() { … }
case class ProfileId(id: Int)
def loadProfile(profileId: ProfileId): Profile = ???
case class Profile() { … }
case class ProfileId(id: Int)
def loadProfile(profileId: ProfileId): Profile = ???
loadProfile(ProfileId(3))
loadProfile(new ProfileId(3))
loadProfile(profileId = ProfileId(3))
loadProfile(profileId = new ProfileId(3))
case class Profile() { … }
case class ProfileId(id: Int)
implicit def toId(i :Int): ProfileId = ProfileId(i)
def loadProfile(profileId: ProfileId): Profile = ???
loadProfile(ProfileId(3))
loadProfile(new ProfileId(3))
loadProfile(profileId = ProfileId(3))
loadProfile(profileId = new ProfileId(3))
loadProfile(3)
loadProfile(profileId = 3)
def loadInt(): Int = { … }
def f(value: () => Int) = { … }
f(() => 2 + loadInt())
def loadInt(): Int = { … }
def f(value: () => Int) = { … }
f(() => 2 + loadInt())
def f(value: => Int) = { … }
f(2 + loadInt())
Too Much Sugar?
source
Issues so far
Too many ways to write the same thing
Tradeoff between short and readable
Advanced features getting in the way
Insulin to the rescue
1. Style Guides
source
Style Guides
1. The basic: Official Scala-Lang Style Guide
2. The conservative: Databricks' Scala Style Guide
3. The exhaustive: Twitter's Effective Scala
4. Your own!
Style Guides
implicit def toId(i :Int): ProfileId = ProfileId(i)
loadProfile(ProfileId(3))
loadProfile(3)
“Do not use implicits to do automatic
conversions between similar datatypes”
Style Guides
“Avoid infix notation for methods
that aren't symbolic methods”
list map func
string contains "foo"
list.map(func)
string.contains("foo")
val x = y + 2
Style Guides
val ids = tuples.map(t => t match { case (id, value)=> id })
val ids = tuples.map(_ match { case (id, value) => id })
val ids = tuples.map { case (id, value) => id }
val ids = tuples.map { case (id, _) => id }
“Use pattern matching directly in function
definitions whenever applicable”
Style Guides
def f(value: => Int) = ???
f(2 + 3)
def f(value: () => Int) = ???
f(() => 2 + 3)
“Avoid using call by name.
Use () => T explicitly”
@throws[IOException]
def mightThrowException(): Int
def neverThrowsException(): Option[Int]
def neverThrowsException(): Try[Int]
def neverThrowsException(): Either[Int, String]
def neverThrowsException(): MyResult
Style Guides
“Scala provides an exception facility, but do not
use it for commonplace errors”
val ids = tuples.map(_._1)
val ids = tuples.map(tuple => tuple._1)
val ids = tuples.map { case (id, value) => id }
val ids = tuples.map { case (id, _) => id }
Style Guides
“Avoid using tuple field names
like _1, prefer pattern matching or
a dedicated case class”
2. Code Reviews
source
Code Reviews
Refer author to Style Guides
Mix “Scala Levels” - juniors should review seniors’ code
Code Reviews
Code Reviews
Code Reviews
[Only] methods which act as
accessors [...] should be declared
without parentheses, except if they
have side effects
3. Style Checkers
source
Style Checkers
Automate some of the (simpler) rules
1. Scalastyle (SBT/Gradle/Maven/Eclipse/IntelliJ)
2. Scalafmt (SBT/Vim/CLI/IntelliJ) [NEW]
⌚ 18:45:25 ➜ sbt scalastyle
[info] Loading project definition from /.../project
[info] Set current project to myProject (in build file:/.../)
[warn] MyJob.scala:31:6: parameter.number.message
[error]MyService.scala:42:6: public.methods.have.type.message
[info] Processed 42 file(s)
[info] Found 1 errors
[info] Found 2 warnings
[info] Found 0 infos
[info] Finished in 39 ms
Style Checkers
4. Scala Levels
source
Scala Levels
Application Programmer Library Designer
A1: Beginner L1: Junior
A2: Intermediate L2: Senior
A3: Expert L3: Expert
Defined by Martin Odersky in a 2011 post
Scala Levels
Application Includes
A1: Beginner Basic syntax; Simple Closures;
Collections; For-expressions; …
A2: Intermediate Pattern matching; Trait composition;
(Tail) Recursion; …
A3: Expert Folds; Streams + other lazy data
structures; Actors; …
Scala Levels
Library Includes
L1: Junior Type parameters; Traits; Lazy vals;
Currying; By-name parameters
L2: Senior Variance; Existential types; Cake Pattern;
Structural types; Extractors; …
L3: Expert Early initializers; Abstract types; Implicit
definitions; Higher-kinded types; …
source
def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That
source
Conclusions
1. Intermediate Scala works
(might be better than Expert Java!)
2. Style and Feature-set can
be controlled
3. No Chuck-Norrisness Required
source
Thank You

“Insulin” for Scala’s Syntactic Diabetes

  • 1.
    “Insulin” for Scala’s SyntacticDiabetes Tzach Zohar // Kenshoo // Scalapeño 2016
  • 2.
    OR: How to adoptScala and survive source
  • 4.
  • 5.
    Who am I NOTChuck Norris! Scala “Advanced Beginner” / “Competent” System Architect @ Kenshoo
  • 6.
    Who’s Kenshoo 10-year Tel-Avivbased startup Industry Leader in Digital Marketing Java + JavaScript shop http://kenshoo.com/
  • 7.
    Scala @ Kenshoo 5services written in Scala More to come... Internal Scala course on the go
  • 8.
  • 9.
    trait GeneralizedCategory { typeU <: Hom type =>:[A >: U#L <: U#H, B >: U#L <: U#H] = U#C[A, B] def id[A >: U#L <: U#H]: A =>: A def compose[A >: U#L <: U#H, B >: U#L <: U#H, C >: U#L <: U#H]( f: B =>: C, g: A =>: B): A =>: C def *[UY<:Hom](that : GeneralizedCategory {type U=UY}) = Category.ProductCategory[U,UY](this,that) } source
  • 10.
  • 11.
    source def map[B, That](f:A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That
  • 12.
    Now for somesane examples source
  • 13.
    val tuples =List((1, 374), (3, 42), (5, 693)) val ids = tuples.map(_._1) val ids = tuples.map(tuple => tuple._1) val ids = tuples.map { tuple => tuple._1 }
  • 14.
    val tuples =List((1, 374), (3, 42), (5, 693)) val ids = tuples.map(_._1) val ids = tuples.map(tuple => tuple._1) val ids = tuples.map { tuple => tuple._1 } val ids = tuples.map(t => t match { case (id, value)=> id }) val ids = tuples.map(_ match { case (id, value) => id }) val ids = tuples.map({ case (id, value) => id }) val ids = tuples.map { case (id, value) => id } val ids = tuples.map { case (id, _) => id }
  • 15.
    case class Profile(){ … } case class ProfileId(id: Int) def loadProfile(profileId: ProfileId): Profile = ???
  • 16.
    case class Profile(){ … } case class ProfileId(id: Int) def loadProfile(profileId: ProfileId): Profile = ??? loadProfile(ProfileId(3)) loadProfile(new ProfileId(3)) loadProfile(profileId = ProfileId(3)) loadProfile(profileId = new ProfileId(3))
  • 17.
    case class Profile(){ … } case class ProfileId(id: Int) implicit def toId(i :Int): ProfileId = ProfileId(i) def loadProfile(profileId: ProfileId): Profile = ??? loadProfile(ProfileId(3)) loadProfile(new ProfileId(3)) loadProfile(profileId = ProfileId(3)) loadProfile(profileId = new ProfileId(3)) loadProfile(3) loadProfile(profileId = 3)
  • 18.
    def loadInt(): Int= { … } def f(value: () => Int) = { … } f(() => 2 + loadInt())
  • 19.
    def loadInt(): Int= { … } def f(value: () => Int) = { … } f(() => 2 + loadInt()) def f(value: => Int) = { … } f(2 + loadInt())
  • 20.
  • 21.
    Issues so far Toomany ways to write the same thing Tradeoff between short and readable Advanced features getting in the way
  • 22.
  • 23.
  • 24.
    Style Guides 1. Thebasic: Official Scala-Lang Style Guide 2. The conservative: Databricks' Scala Style Guide 3. The exhaustive: Twitter's Effective Scala 4. Your own!
  • 25.
    Style Guides implicit deftoId(i :Int): ProfileId = ProfileId(i) loadProfile(ProfileId(3)) loadProfile(3) “Do not use implicits to do automatic conversions between similar datatypes”
  • 26.
    Style Guides “Avoid infixnotation for methods that aren't symbolic methods” list map func string contains "foo" list.map(func) string.contains("foo") val x = y + 2
  • 27.
    Style Guides val ids= tuples.map(t => t match { case (id, value)=> id }) val ids = tuples.map(_ match { case (id, value) => id }) val ids = tuples.map { case (id, value) => id } val ids = tuples.map { case (id, _) => id } “Use pattern matching directly in function definitions whenever applicable”
  • 28.
    Style Guides def f(value:=> Int) = ??? f(2 + 3) def f(value: () => Int) = ??? f(() => 2 + 3) “Avoid using call by name. Use () => T explicitly”
  • 29.
    @throws[IOException] def mightThrowException(): Int defneverThrowsException(): Option[Int] def neverThrowsException(): Try[Int] def neverThrowsException(): Either[Int, String] def neverThrowsException(): MyResult Style Guides “Scala provides an exception facility, but do not use it for commonplace errors”
  • 30.
    val ids =tuples.map(_._1) val ids = tuples.map(tuple => tuple._1) val ids = tuples.map { case (id, value) => id } val ids = tuples.map { case (id, _) => id } Style Guides “Avoid using tuple field names like _1, prefer pattern matching or a dedicated case class”
  • 31.
  • 32.
    Code Reviews Refer authorto Style Guides Mix “Scala Levels” - juniors should review seniors’ code
  • 33.
  • 34.
  • 35.
    Code Reviews [Only] methodswhich act as accessors [...] should be declared without parentheses, except if they have side effects
  • 36.
  • 37.
    Style Checkers Automate someof the (simpler) rules 1. Scalastyle (SBT/Gradle/Maven/Eclipse/IntelliJ) 2. Scalafmt (SBT/Vim/CLI/IntelliJ) [NEW]
  • 38.
    ⌚ 18:45:25 ➜sbt scalastyle [info] Loading project definition from /.../project [info] Set current project to myProject (in build file:/.../) [warn] MyJob.scala:31:6: parameter.number.message [error]MyService.scala:42:6: public.methods.have.type.message [info] Processed 42 file(s) [info] Found 1 errors [info] Found 2 warnings [info] Found 0 infos [info] Finished in 39 ms Style Checkers
  • 39.
  • 40.
    Scala Levels Application ProgrammerLibrary Designer A1: Beginner L1: Junior A2: Intermediate L2: Senior A3: Expert L3: Expert Defined by Martin Odersky in a 2011 post
  • 41.
    Scala Levels Application Includes A1:Beginner Basic syntax; Simple Closures; Collections; For-expressions; … A2: Intermediate Pattern matching; Trait composition; (Tail) Recursion; … A3: Expert Folds; Streams + other lazy data structures; Actors; …
  • 42.
    Scala Levels Library Includes L1:Junior Type parameters; Traits; Lazy vals; Currying; By-name parameters L2: Senior Variance; Existential types; Cake Pattern; Structural types; Extractors; … L3: Expert Early initializers; Abstract types; Implicit definitions; Higher-kinded types; …
  • 43.
    source def map[B, That](f:A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That
  • 44.
  • 45.
  • 46.
    1. Intermediate Scalaworks (might be better than Expert Java!) 2. Style and Feature-set can be controlled 3. No Chuck-Norrisness Required source
  • 47.