Solid Type System vs

Runtime Checks and Unit Tests Vladimir Pavkin

Plan Fail Fast concept Type Safe Patterns

Fail Fast

Immediate and visible failure

Where can it fail? Handled runtime exceptions & assertions Unhandled runtime failure

Handling runtime exceptions assert(!list.isEmpty, "List must be empty")

try {   str.toInt } catch {   case _:Throwable => 0 }

Where can it fail? Runtime checks Handled runtime exceptions & assertions Unhandled runtime failure

Runtime checks if(container == null)

if(container.isInstanceOf[ContainerA])

Where can it fail? Unit tests Runtime checks Handled runtime exceptions & assertions Unhandled runtime failure

Unit tests it should "throw NoSuchElementException for empty stack" in {   val emptyStack = new Stack[Int]   a [NoSuchElementException] should be thrownBy {     emptyStack.pop()   } }

it should "not throw for empty stack" in {   val stackWrapper = StackWrapper(new Stack[Int])   noException should be thrownBy stackWrapper.pop() }

Where can it fail? Linters Unit tests Runtime checks Handled runtime exceptions & assertions Unhandled runtime failure

Linters scalacOptions ++= Seq(   "­Xlint",   "­deprecation",   "­Xfatal­warnings" )

// Wrong number of args to format() logger.error(   "Failed to open %s. Error: %d"   .format(file) )

Where can it fail? Compiler Linters Unit tests Runtime checks Handled runtime exceptions & assertions Unhandled runtime failure

The goal To move as much as possible to the Compiler

How? Just give it enough type information. Type system to the rescue!

Before we start...

Examples domain?

Beefcakes!

No offense intended :)

Ok? def becomeAMan(douchebag: Person): Man =   if(douchebag.weight > 70)     new Man(douchebag.renameTo("Arny"))   else     null

No! Unhandled runtime failure! becomeAMan(vpavkin).name  //vpavkin.weight < 70

NULL

Can we handle this? var man = becomeAMan(person) if(man != null)   name else   //...

Still not nice. code client has to clutter code with runtime checks (or fail) compiler won't complain if you forget to check

If you control the source code, don't ever use null as a return result. It's like farting in an elevator. Some random guy at a random Scala forum

The problem is

insufficient type information! Return type should be something like ManOrNull

Option

Option sealed trait Option[T] case class Some[T](x: T) extends Option[T] case object None extends Option[Nothing]

Better API def becomeAMan(douchebag: Person): Option[Man] =   if(douchebag.weight > 70)     Some(new Man(douchebag.renameTo("Arny")))   else     None code is documentation client has to deal with None result at compile time.

Use wrapped value? def firstWorkout(douchebag: Person): Option[WorkoutResult] =   becomeAMan(douchebag).map(man => man.workout())

Unwrap? def willHaveASexyGirlfriend(douchebag: Person): Boolean =   becomeAMan(douchebag) match {     case Some(man) => true     case None => false   }

Exceptions

Classic def workout(man: Man): WorkoutResult =   if(!man.hasShaker)     throw new Error("Not enough protein!!!!111")   else     // do some squats or stare in the mirror for 1h

Again! Client either uses try/catch or fails at runtime! Return type doesn't tell anything about possible failure

Let's add some types!

scala.Either or

scalaz.\/

Declare possible failure

Better API def workout(man:Man): ProteinFail \/ WorkoutResult =   if(!man.hasShaker)     ProteinFail("Not enough protein!!!!111").left   else     someWorkoutResult.right code is documentation client has to deal with errors at compile time.

scalaz.\/ sealed trait \/[E, R] case class ­\/[E](a: E) extends (E \/ Nothing) case class \/­[R](a: R) extends (Nothing \/ R)

Use wrapped value? workout(man).map(result => submitToFacebook(result)) // type is // ProteinFail \/ Future[List[FacebookLike]]

Unwrap? def tellAboutTheWorkout(w: ProteinFail \/ WorkoutResult): String =   w match {     case ­\/(fail) => "F**k your proteins, I can do without it"     case \/­(result) =>       s"Dude, eat proteins, or you won't do like me: $result"   }

isInstanceOf[Man]

isInstanceOf[T] trait GymClient case class Man(name: String) extends GymClient case class Douchebag(name: String) extends GymClient

def gymPrice(h: GymClient): Int =   if(h.isInstanceOf[Man]){     val man = h.asInstanceOf[Man]     if(man.name == "Arny") 0 else 100   } else {     200   }

So runtime. // Add another client type case class PrettyGirl(name:String) extends GymClient

It still compiles. And we charge girls as much as douchebags! It's an unhandled runtime failure!

isInstanceOf[T] trait GymClient case class Man(name: String) extends GymClient case class Douchebag(name: String) extends GymClient case class PrettyGirl(name:String) extends GymClient

def gymPrice(h: GymClient): Int =   if(h.isInstanceOf[Man]){     val man = h.asInstanceOf[Man]     if(man.name == "Arny") 0 else 100   } else {     200   }

sealed ADT +

pattern matching

sealed = can't be extended in other files

Algebraic Data Type 1) Product types 2) Sum types

Compiler knows all the possible class/trait children.

Sealed ADT + pattern matching sealed trait GymClient case class Man(name: String) extends GymClient case class Douchebag(name: String) extends GymClient

def gymPrice(h: GymClient): Int = h match {   case Man("Arny") => 0   case _: Man => 100   case _: Douchebag => 200 } // compiler checks, that match is exhaustive

What if we add girls now? sealed trait GymClient case class Man(name: String) extends GymClient case class Douchebag(name: String) extends GymClient case class PrettyGirl(name:String) extends GymClient

def gymPrice(h: GymClient): Int = h match {   case Man("Arny") => 0   case _: Man => 100   case _: Douchebag => 200 } // COMPILE ERROR! Match fails for PrettyGirl.

Compiler saved us again!

Tagging

Gym DB case class Beefcake(id: String,                     name: String) case class GymPass(id: String,                    ownerId: String)

Safer: Tags trait JustTag def onlyTagged(value: String @@ JustTag): String   = s"Tagged string: $value"   // can use as plain String

onlyTagged("plain string") // Compiler error val tagged = tag[JustTag]("tagged") onlyTagged(tagged) // OK

Gym DB: safer keys case class Beefcake(id: String @@ Beefcake,                     name: String) case class GymPass(id: String @@ GymPass,                    ownerId: String @@ Beefcake)

Phantom Types

PullUp sealed trait PullUpState final class Up extends PullUpState final class Down extends PullUpState

PullUp class Beefcake[S <: PullUpState] private () {   def pullUp[T >: S <: Down]() =       this.asInstanceOf[Beefcake[Up]]   def pullDown[T >: S <: Up]() =       this.asInstanceOf[Beefcake[Down]] } object Beefcake {   def create() = new Beefcake[Down] }

PullUp val fresh = Beefcake.create() //Beefcake[Down] val heDidIt = fresh.pullUp() //Beefcake[Up] val notAgainPlease = heDidIt.pullUp() // CompileError: // inferred type arguments [Up] do not conform // to method pullUp's type parameter bounds

Path Dependent Types

The Two Gyms class Gym(val name: String) class Beefcake(val gym: Gym){   def talkTo(other: Beefcake): Unit =     println("Wazzup, Hetch!") }

val normalGym = new Gym("nicefitness") val swagGym = new Gym("kimberly") val normalGuy = new Beefcake(normalGym) val swagGuy = new Beefcake(swagGym) normalGuy.talkTo(swagGuy) // we don't want that

The Two Gyms Runtime solution class Beefcake(val gym: Gym){   def talkTo(other: Beefcake): Unit = {     // throws IllegalArgumentException if false     require(this.gym == other.gym)     println("Wazzup, Hetch!")   } }

Path Dependent Types class A {   class B } val a1 = new A val a2 = new A var b = new a1.B // type is a1.B b = new a2.B // Compile Error: types don't match

Type depends on the value it belongs to.

Type safe solution class Gym(val name: String){   class Beefcake(val gym: Gym){     def talkTo(other: Beefcake): Unit =     println("Wazzup, Hetch!")   } }

val normalGym = new Gym("nicefitness") val swagGym = new Gym("kimberly") val normalGuy = new normalGym.Beefcake(normalGym) val swagGuy = new swagGym.Beefcake(swagGym) normalGuy.talkTo(swagGuy) // doesn't compile, Yay!

This is not a talk about Scala type system. Not covered: Trait composition Existential types Macros Type Classes Shapeless ...

Q&A

Thank you!

goo.gl/U0WYAB PDF

Solid Type System Runtime Checks and Unit Tests - GitHub

insufficient type information! Return type should be something like ... type is. // ProteinFail \/ Future[List[FacebookLike]]. Unwrap? ... case \/(result) => s"Dude, eat proteins, or you won't do like me: $result" .... Thank you! goo.gl/U0WYAB · PDF.

5MB Sizes 5 Downloads 235 Views

Recommend Documents

Unit Type Unit Charter Organization Unit Leader Unit Leader Phone ...
Unit Leader E-mail. Boy Scout Troop. 152. First United Methodist Church, ... Keith Hanselman. 330-929-6679 [email protected]. Boy Scout Troop.

Runtime Array Fusion for Data Parallelism - GitHub
School of Computer Science and Engineering ... collective operations are implemented efficiently and provide a high degree of parallelism, the result of each ...

Distributed Application Runtime Environment (DARE): A ... - GitHub
tive of their potential of supporting existing and novel scientific computing practices and ... in a consistent way as the total number of cycles available year-to-year varies ... Table 1 Life-Science usage of the TG/XSEDE over the recent quarters. .

BDE Type Taxonomy - GitHub
Dec 4, 2015 - bslmf::IsFundamental baltzo::Loader bslma::DeallocatorGuard bslma::DestructorProctor utility meta- function protocol bdlt::Date bslstl::StringRef.

Open putty and type remote hostname - GitHub
(here I put simply hostname ) and then click Save button. From now on your connection to remote host with tunnel is saved and can be reused anytime you open ...

Perl Post Install Tests - GitHub
Apr 10, 2013 - CPAN/Perl community has usually been good at preserving backwards compatibility ... and installed. ▻ Writing a best practices guide for tests ...

OPTIMAL SYSTEM OPERATION AND UNIT COMMITMENT ...
There was a problem previewing this document. Retrying... Download. Connect more apps... Try one of the apps below to open or edit this item. OPTIMAL ...

Stubs Speed up Your Unit Tests
Apr 4, 2007 - Michael Feathers defines the qualities of a good unit test as: “they run fast, they help us localize problems.” This can be hard to accomplish when your code accesses a database, hits another server, is time-dependent, etc. By subst

Stubs Speed up Your Unit Tests
Apr 4, 2007 - Stubs Speed up. Your Unit Tests. Michael Feathers defines the qualities of a good unit test as: “they run fast, they help us localize problems.

Naming Unit Tests Responsibly Code
Jan 30, 2007 - For example, when it's hard to construct a sentence where the first word is the class under test, it suggests the test may be in the wrong place. And classes that are hard to describe in general often need to be broken down into smalle

Type of article: Research Paper DiffusionKit - GitHub
website of DiffusionKit includes test data, a complete tutorial and a series of tutorial ..... The 3D show panel supports only one active image at a ..... Illustrations of how to extract a specific fiber bundles from entire brain tractography, ... As

routine management system - GitHub
10. Figure 4 - Sample Data Set of Routine Management System . .... platform apps, conventional software architectural design patterns may be adopted and ...

System Requirements Specification - GitHub
This section describes the scope of Project Odin, as well as an overview of the contents of the SRS doc- ument. ... .1 Purpose. The purpose of this document is to provide a thorough description of the requirements for Project Odin. .... Variables. â€

System Requirements Specification - GitHub
System Requirements Specification. Project Odin. Kyle Erwin. Joshua Cilliers. Jason van Hattum. Dimpho Mahoko. Keegan Ferrett. Note: This document is constantly under revision due to our chosen methodology, ... This section describes the scope of Pro

Applying Type-Level and Generic Programming in Haskell - GitHub
Feb 10, 2018 - (Haskell allows to say deriving Eq on a datatype declaration, invoking compiler magic that conjures up a .... Since type-level programming is a bit peculiar in Haskell, we'll move step by step: from normal lists over .... Before we mov

FreeBSD ports system - GitHub
Search - make search (cont'd). Port: rsync-3.0.9_3. Path: /usr/ports/net/rsync. Info: Network file distribution/synchronization utility. Maint: [email protected].

Practical Type Inference for the GADT Type System
Portland State University ... opportunity to develop my interests in computer science and to pursue graduate ..... 7.13 Type inference for reified state monad (1).

Buddy system Swimming testing Buddy Boards Buddy Checks
and another to perform a Buddy Count. Staff must begin an immediate search if a buddy is unaccounted for. When the water is clear and all Buddies are accounted for, the swimmers may reenter the water and resume activities. Using this system does not

Macro-based type providers in Scala - GitHub
Apr 5, 2014 - dc.title ->- "Frankenstein Draft Notebook B" ... We'll be using the W3C's Banana RDF library throughout: . 9 ...

Practical Type Inference for the GADT Type System
opportunity to develop my interests in computer science and to pursue graduate ...... algebraic data types that I made in the course of this dissertation research. Here ..... APP This rule types a function application by typing the function (f) and i

CodaLab Worker System - GitHub
The worker system consists of 3 components: • REST server: ... a ”check out” call which is used to tell the server that a worker is shutting down and prevent it from.

CBIR System - GitHub
Final result was a Matlab built software application, with an image database, that utilized ... The main idea is to integrate the strengths of content- and keyword-based image ..... In the following we present some of the best search results.

Type-Directed TDD in Rust - GitHub
Jul 21, 2014 - Give a taste of a practical software development process that is: ▻ test-driven ... Recently, Apple ditched Objective C for its new language Swift!