a type is worth a thousand tests - sydspace · generics & protocols with associated types type...

165
Manuel M T Chakravarty Applicative & Tweag I/O A Type is Worth a Thousand Tests mchakravarty TacticalGrace justtesting.org haskellformac.com

Upload: others

Post on 20-Jul-2020

2 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Manuel M T ChakravartyApplicative & Tweag I/O

A Type is Worth a Thousand Tests

mchakravartyTacticalGracejusttesting.orghaskellformac.com

Page 2: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Let’s talk about…

Page 3: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Swift

Let’s talk about…

Page 4: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Swift

Let’s talk about…

Language Design

Page 5: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Swift

Let’s talk about…

Language Design Ecosystem

Page 6: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Swift

Let’s talk about…

Language Design Ecosystem

Why is it extraordinary

?

Page 7: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Unique Event

Page 8: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Java

Objective-C

C#

Page 9: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Java

Objective-C

C#

ScalaKotlin

Page 10: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Java

Objective-C

C#

Scala

F#

Kotlin

Page 11: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Swift

Java

Objective-C

C#

Scala

F#

Kotlin

Page 12: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Why do languages become popular?

Page 13: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Why do languages become popular?

Platforms

Page 14: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Why do languages become popular?

Platforms

UnixC/C++ .NET

C#JVMJava

WebJavaScript

CloudPython/RubyCocoa

Objective-C

Page 15: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Why do languages become popular?

Platforms

UnixC/C++ .NET

C#JVMJava

WebJavaScript

CloudPython/RubyCocoa

Swift

Page 16: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Why will Swift be popular?

Page 17: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Why will Swift be popular?

Page 18: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Why will Swift be popular?

Page 19: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Why will Swift be popular?

Why is it extraordinary

?

Page 20: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Functional Programming

Page 21: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

From Objective-C to Swift

Page 22: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

From Objective-C to Swift

Higher-order functions

& closures

Value types (products & sums)

Advanced type system

Explicit control of mutability

Explicit optionals

Generics & protocols with

associated types

Type inferenceREPL

Pattern matching

Page 23: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

From Objective-C to Swift

Higher-order functions

& closures

Value types (products & sums)

Advanced type system

Explicit control of mutability

Explicit optionals

Generics & protocols with

associated types

Type inferenceREPL

Pattern matchingλ

Page 24: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

From Objective-C to Swift

Higher-order functions

& closures

Value types (products & sums)

Advanced type system

Explicit control of mutability

Explicit optionals

Generics & protocols with

associated types

Type inferenceREPL

Pattern matchingλτ

Page 25: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

“Swift encourages typed functional programming in a

mainstream language.”

Page 26: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Haskell for Mac

Adopting Swift right out of the gate

Page 27: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Haskell for Mac

Adopting Swift right out of the gate

Page 28: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

“Swift encourages typed functional programming in a

mainstream language.”

Page 29: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Why Type Systems?

Page 30: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Catch bugs & prevent crashes

Page 31: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Less testing!

Page 32: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

“What if you could gain the same confidence in correctness

with fewer or simpler tests?”

Page 33: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Possible states of your application

Page 34: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Possible states of your application

Error states

Page 35: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Possible states of your application

Error states

Tested states

Page 36: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Possible states of your application

Error states

Tested states

with types

Page 37: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Possible states of your application

Error states

Tested states

eliminate bugs

with types

Page 38: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Possible states of your application

Error states

Tested states

eliminate bugs

eliminate tests

with types

Page 39: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Are types restraints?

Page 40: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Types are a design tool!

Page 41: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Type Systems

Lang

uage

s Programs

Page 42: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Type Systems

Lang

uage

s Programs

“Make undesirable states unrepresentable.”

Page 43: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

“Swift encourages typed functional programming in a

mainstream language.”

Page 44: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

“Swift encourages typed functional programming in a

mainstream language.”

Page 45: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

“Swift encourages typed functional programming in a

mainstream language.”

Value typesImmutable model & UI state machines

Page 46: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

“Swift encourages typed functional programming in a

mainstream language.”

Value typesImmutable model & UI state machines

Protocols with associated typesGeneric change propagation

Page 47: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Goals.app

Page 48: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Goals.app

Page 49: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Goals.app

Page 50: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Goals.app

Page 51: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Goals.app

Page 52: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Value Types Localise & structure change

Page 53: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Value types in Swift

Page 54: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Value types in Swift

struct Point { var x: Double var y: Double }

struct

Page 55: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Value types in Swift

struct Point { var x: Double var y: Double }

struct

enum Result<ResultType> { case result(value: ResultType) case error(err: NSError) }

enum with associated values

Page 56: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Value types in Swift

struct Point { var x: Double var y: Double }

struct

enum Result<ResultType> { case result(value: ResultType) case error(err: NSError) }

enum with associated values

generic type parameter

Page 57: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

// Data class (similar to struct) data class Point(var x: Double, var y: Double)

// Sealed class (similar to enum) sealed class Result { data class Success<T>(val value: T) : Result() data class Error(val err: Exception) : Result() }

Kolin Edition

Page 58: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Reference types versus value types

var v: RefPnt

class RefPnt { var x, y: Double … }

var w: RefPnt

Page 59: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Reference types versus value types

var v: RefPnt

class RefPnt { var x, y: Double … }

v = RefPnt(x: 0, y: 0)

x: 0, y: 0var w: RefPnt

Page 60: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Reference types versus value types

var v: RefPnt

class RefPnt { var x, y: Double … }

v = RefPnt(x: 0, y: 0)w = v

x: 0, y: 0var w: RefPnt

Page 61: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Reference types versus value types

var v: RefPnt

class RefPnt { var x, y: Double … }

v = RefPnt(x: 0, y: 0)w = vw.x = 10

x: 0, y: 0var w: RefPnt

x: 10, y: 0

Page 62: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Reference types versus value types

var v: Point

struct Point { var x, y: Double }

var w: Point

Page 63: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Reference types versus value types

var v: Point

struct Point { var x, y: Double }

v = Point(x: 0, y: 0)

x: 0, y: 0

var w: Point

Page 64: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Reference types versus value types

var v: Point

struct Point { var x, y: Double }

v = Point(x: 0, y: 0)w = v

x: 0, y: 0

var w: Point x: 0, y: 0

Page 65: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Reference types versus value types

var v: Point

struct Point { var x, y: Double }

v = Point(x: 0, y: 0)w = vw.x = 10

x: 0, y: 0

var w: Point x: 0, y: 0x: 10, y: 0

Page 66: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

var v: Point x: 0, y: 0

var w: Point x: 0, y: 0x: 10, y: 0

Value types

Page 67: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

var v: Point x: 0, y: 0

var w: Point x: 0, y: 0x: 10, y: 0

Localise change

Value types

Page 68: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

var v: Point x: 0, y: 0

var w: Point x: 0, y: 0x: 10, y: 0

Localise change

Facilitate local reasoning

Value types

Page 69: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Value Types Immutable Model

Page 70: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

MVC & MVVM Architectures

Controller

View Model

Page 71: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

MVC & MVVM Architectures

View C ModelView Model

Page 72: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

MVC & MVVM Architectures

View C ModelView Model

passed around as reference type

Page 73: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

MVC & MVVM Architectures

View C ModelView Model

passed around as reference type

╳ Accidental changes

Page 74: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

MVC & MVVM Architectures

View C ModelView Model

passed around as reference type

╳ Accidental changes

╳ Changes in wrong order

Page 75: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Immutable Goals

struct Goal { let uuid: UUID // fast equality var colour: UIColor var title: String var interval: GoalInterval var frequency: Int}

Page 76: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Immutable Goals

struct Goal { let uuid: UUID // fast equality var colour: UIColor var title: String var interval: GoalInterval var frequency: Int}

typealias GoalProgress = (goal: Goal, count: Int?)

Page 77: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Immutable Goals

struct Goal { let uuid: UUID // fast equality var colour: UIColor var title: String var interval: GoalInterval var frequency: Int}

typealias GoalProgress = (goal: Goal, count: Int?)

typealias Goals = [GoalProgress] // array

Page 78: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

data class Goal( val uuid: UUID, var colour: Color, var title: String, var interval: GoalInterval, var frequency: Int)

typealias GoalProgress = Pair<Goal, Int?>

typealias Goals = Array<GoalProgress>

Kolin Edition

Page 79: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Immutable Models Do Scale!

Page 80: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Immutable Models Do Scale!

Haskell for MacUses an immutable model

Adopts Cocoa Document Architecture

Page 81: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Immutable Models Do Scale!

Haskell for MacUses an immutable model

Adopts Cocoa Document Architecture

“Functional Programming in a Stateful World” YOW! Lambda Jam 2015

(on speakerdeck.com)

Page 82: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

But what if…

Page 83: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

But what if…

“Use an immutable wrapper API to wrap mutable structures.”

Page 84: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

But what if…

“Use an immutable wrapper API to wrap mutable structures.”

✓ React (Native)Virtual DOM wraps DOM

Page 85: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

But what if…

“Use an immutable wrapper API to wrap mutable structures.”

✓ React (Native)Virtual DOM wraps DOM

✓ Haskell SpriteKit — Haskell library bindingAlgebraic data type wraps SpriteKit’s mutable object graph

Page 86: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Replacing Tests

Page 87: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Replacing Tests

✓ Avoid accidental changes of model stateReplaces integration tests

Page 88: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Replacing Tests

✓ Avoid accidental changes of model stateReplaces integration tests

✓ Avoid races on concurrent threadsOften not properly tested

Page 89: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Enums with Associated Values UI State Machines

Page 90: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for
Page 91: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Is goal active?

Page 92: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Is goal active?

typealias GoalProgress = (goal: Goal, count: Int?) typealias Goals = [GoalProgress]

Page 93: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Is goal active?

typealias GoalProgress = (goal: Goal, count: Int?) typealias Goals = [GoalProgress]

Need to be careful not to lose progress info

Page 94: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

var goalsActivity: [Bool]

Page 95: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

var goalsActivity: [Bool]

Not valid outside of editing mode

Page 96: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

enum GoalsEditState { case displaying case editing(goalsActivity: [Bool]) }

var goalsActivity: [Bool]

Page 97: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

enum GoalsEditState { case displaying case editing(goalsActivity: [Bool]) }

Page 98: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

enum GoalsEditState { case displaying case editing(goalsActivity: [Bool]) }

var editState: GoalsEditState = .displaying…

GoalsController: UITableViewController

Page 99: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

enum GoalsEditState { case displaying case editing(goalsActivity: [Bool]) }

var editState: GoalsEditState = .displaying…switch editState { // change mode

GoalsController: UITableViewController

Page 100: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

enum GoalsEditState { case displaying case editing(goalsActivity: [Bool]) }

var editState: GoalsEditState = .displaying…switch editState { // change mode case .displaying: navigationItem.setLeftBarButton(nil, …) editState = .editing(goalsActivity: dataSource.goalsActivity)

GoalsController: UITableViewController

alter UI state

Page 101: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

enum GoalsEditState { case displaying case editing(goalsActivity: [Bool]) }

var editState: GoalsEditState = .displaying…switch editState { // change mode case .displaying: navigationItem.setLeftBarButton(nil, …) editState = .editing(goalsActivity: dataSource.goalsActivity)

case .editing(let goalsActivity): navigationItem.setLeftBarButton(addButton, …) dataSource.commitGoalsActivity(goalsActivity) editState = .displaying }

GoalsController: UITableViewController

alter UI state

Page 102: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

guard case .editing(var goalsActivity) = editState else { return }

enum GoalsEditState { case displaying case editing(goalsActivity: [Bool]) }

GoalsController

Page 103: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

guard case .editing(var goalsActivity) = editState else { return }

access to mode-specific state is guarded

enum GoalsEditState { case displaying case editing(goalsActivity: [Bool]) }

GoalsController

Page 104: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

guard case .editing(var goalsActivity) = editState else { return }

let newIsActive = !goalsActivity[indexPath.item] cell.editingAccessoryType = newIsActive ? .checkmark : .none

access to mode-specific state is guarded

enum GoalsEditState { case displaying case editing(goalsActivity: [Bool]) }

GoalsController

Page 105: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

sealed class GoalsEditState { data class Displaying : GoalsEditState() data class Editing(val goalsActivity: Array<Boolean>)

: GoalsEditState() }

Kolin Edition

Page 106: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

var editState: GoalsEditState = GoalsEditState.Displaying() ... when(editState) { is GoalsEditState.Displaying -> { navigationItem.setLeftBarButton(null, ...) editState = GoalsEditState.Editing( goalsActivity = dataSource.goalsActivity) } is GoalsEditState.Editing -> { navigationItem.setLeftBarButton(addButton, ...) dataSource.commitGoalsActivity(goalsActivity) editState = GoalsEditState.Displaying() } }

sealed class GoalsEditState { data class Displaying : GoalsEditState() data class Editing(val goalsActivity: Array<Boolean>)

: GoalsEditState() }

Page 107: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Replacing Tests

Page 108: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Replacing Tests

✓ Avoid inconsistent state changesReplaces UI tests

Page 109: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Replacing Tests

✓ Avoid inconsistent state changesReplaces UI tests

✓ Avoid non-exhaustive transitionsReplaces exhaustiveness tests

Page 110: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Protocols with associated types Structured change propagation

Page 111: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

“Now that the model layer is immutable, how do we change

anything?”

Page 112: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

25Δt: 0sMutable Variable

Page 113: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

7Δt: 1sMutable Variable

Page 114: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

11Δt: 2sMutable Variable

Page 115: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

73Δt: 3sMutable Variable

Page 116: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

42Δt: 4sMutable Variable

Page 117: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Δt0 1 2 3 4

427311725

Page 118: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Δt0 1 2 3 4

427311725

✓ Flow of changes explicit in code

Page 119: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Δt0 1 2 3 4

427311725

✓ Flow of changes explicit in code

✓Changes can be processed with combinators (map, fold, accumulate, and so on)

Page 120: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Changes API

protocol Observable: class { associatedtype ObservedValue

Page 121: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Changes API

protocol Observable: class { associatedtype ObservedValue

func observe<Context: AnyObject>( withContext context: Context, observer: (Context, ObservedValue) -> ()) -> ()

}

registered observer call back

Page 122: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

interface Observable<ObservedValue> { fun <Context : Any> observe( context: Context, observer: (Context, ObservedValue) -> Unit) }

Kolin Edition

Page 123: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Changes API

protocol Observable: class { associatedtype ObservedValue

func observe<Context: AnyObject>( withContext context: Context, observer: (Context, ObservedValue) -> ()) -> ()

}

registered observer call back

Page 124: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

protocol Observable: class { associatedtype ObservedValue

func observe<Context: AnyObject>( withContext context: Context, observer: (Context, ObservedValue) -> ()) -> ()

}

Page 125: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

class Changing<Value>: Observable { typealias ObservedValue = Value func announce(change: Value) { … } func observe … { … } }

Ephemeral stream of changes

protocol Observable: class { associatedtype ObservedValue

func observe<Context: AnyObject>( withContext context: Context, observer: (Context, ObservedValue) -> ()) -> ()

}

Page 126: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

class Changing<Value>: Observable { typealias ObservedValue = Value func announce(change: Value) { … } func observe … { … } }

Ephemeral stream of changes

protocol Observable: class { associatedtype ObservedValue

func observe<Context: AnyObject>( withContext context: Context, observer: (Context, ObservedValue) -> ()) -> ()

}

Add another change value into the stream

Page 127: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

interface Observable<ObservedValue> { fun <Context : Any> observe( context: Context, observer: (Context, ObservedValue) -> Unit) }

class Changing<ObservedValue> : Observable<ObservedValue> { fun announce(change: ObservedValue) { ... } fun observe ... { ... } }

Page 128: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

class Changing<Value>: Observable { typealias ObservedValue = Value func announce(change: Value) { … } func observe … { … } }

Ephemeral stream of changes

protocol Observable: class { associatedtype ObservedValue

func observe<Context: AnyObject>( withContext context: Context, observer: (Context, ObservedValue) -> ()) -> ()

}

Add another change value into the stream

Page 129: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

protocol Observable: class { associatedtype ObservedValue

func observe<Context: AnyObject>( withContext context: Context, observer: (Context, ObservedValue) -> ()) -> ()

}

class Accumulating<Value, Accumulator>: Observable { typealias ObservedValue = Accumulator init <Observed: Observable where …> ( observing observed: Observed, startingFrom initial: Accumulator, accumulate: (Value, Accumulator) -> Accumulator) func observe … { … } }

Accumulating value

Page 130: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

protocol Observable: class { associatedtype ObservedValue

func observe<Context: AnyObject>( withContext context: Context, observer: (Context, ObservedValue) -> ()) -> ()

}

class Accumulating<Value, Accumulator>: Observable { typealias ObservedValue = Accumulator init <Observed: Observable where …> ( observing observed: Observed, startingFrom initial: Accumulator, accumulate: (Value, Accumulator) -> Accumulator) func observe … { … } }

Accumulating value

Accumulating change

Page 131: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

interface Observable<ObservedValue> { fun <Context : Any> observe( context: Context, observer: (Context, ObservedValue) -> Unit) }

class Accumulating<Value, Acc>( val observed: Observed, val initial: Acc, val accumulate: (Value, Acc) -> Acc) : Observable<Acc> { fun observe ... { ... } }

Page 132: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

extension Observable {

}

Page 133: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

extension Observable {

}

map apply function to each observed value

Page 134: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

extension Observable {

}

map apply function to each observed value

merge combine two streams of observations

Page 135: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

extension Observable {

}

map apply function to each observed value

merge combine two streams of observations

accumulatecombine the values of a stream ofobservations using an accumulationfunction

Page 136: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Change Propagation in Goals

G0 3

G1 nil

G2 1

ModelViews

Page 137: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Change Propagation in Goals

G0 3

G1 nil

G2 1

observe

ModelViewsobserve

Page 138: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Change Propagation in Goals

G0 3

G1 nil

G2 1

observe

ModelViews

merge

observe

Page 139: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Change Propagation in Goals

G0 3

G1 nil

G2 1

observe

ModelViews

ProgressEdits

merge

GoalEdits

observe

Page 140: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Change Propagation in Goals

G0 3

G1 nil

G2 1

observe

ModelViews

Edits

accumulate

ProgressEdits

merge

GoalEdits

observe

Page 141: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Change Propagation in Goals

G0 3

G1 nil

G2 1

observe

ModelViews

Accumulating<Edit, Goals>

Edits

accumulate

ProgressEdits

merge

GoalEdits

observe

Page 142: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Accumulating<Edit, Goals>

Edits

ProgressEdits

GoalEdits

Page 143: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

typealias GoalEdits = Changing<GoalEdit>

Accumulating<Edit, Goals>

Edits

ProgressEdits

GoalEdits

Page 144: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

typealias GoalEdits = Changing<GoalEdit>

Accumulating<Edit, Goals>

Edits

ProgressEdits

Page 145: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

typealias GoalEdits = Changing<GoalEdit>

enum GoalEdit { case add(goal: Goal) case delete(goal: Goal) case update(goal: Goal) case setActivity(activity: [Bool])}

Accumulating<Edit, Goals>

Edits

ProgressEdits

Page 146: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

typealias GoalEdits = Changing<GoalEdit>

enum GoalEdit { case add(goal: Goal) case delete(goal: Goal) case update(goal: Goal) case setActivity(activity: [Bool])}

extension GoalEdit { func transform(_ goals: Goals) -> Goals { switch self { case .add(let newGoal): …

Accumulating<Edit, Goals>

Edits

ProgressEdits

Page 147: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

typealias GoalEdits = Changing<GoalEdit> sealed class GoalEdit { data class Add(val goal: Goal) : GoalEdit() data class Delete(val goal: Goal) : GoalEdit() data class Update(val goal: Goal) : GoalEdit() data class SetActivity(val activity: Array<Boolean>) : GoalEdit() }

fun GoalEdit.transform(goals: Goals): Goals { when(this) { is GoalEdit.Add -> { … } … }

Kolin Edition

Page 148: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

typealias GoalEdits = Changing<GoalEdit>

enum GoalEdit { case add(goal: Goal) case delete(goal: Goal) case update(goal: Goal) case setActivity(activity: [Bool]) }

extension GoalEdit { func transform(_ goals: Goals) -> Goals { switch self { case .add(let newGoal): …

Accumulating<Edit, Goals>

Edits

ProgressEdits

GoalEdits

Page 149: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

typealias ProgressEdits = Changing<ProgressEdit>

Accumulating<Edit, Goals>

Edits

ProgressEdits

GoalEdits

Page 150: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

typealias ProgressEdits = Changing<ProgressEdit>

Accumulating<Edit, Goals>

Edits

GoalEdits

Page 151: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

typealias ProgressEdits = Changing<ProgressEdit>

enum ProgressEdit { case bump(goal: Goal)}

Accumulating<Edit, Goals>

Edits

GoalEdits

Page 152: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

typealias ProgressEdits = Changing<ProgressEdit>

enum ProgressEdit { case bump(goal: Goal)}

extension ProgressEdit { func transform(_ goals: Goals) -> Goals { … }}

Accumulating<Edit, Goals>

Edits

GoalEdits

Page 153: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

typealias ProgressEdits = Changing<ProgressEdit>

enum ProgressEdit { case bump(goal: Goal)}

extension ProgressEdit { func transform(_ goals: Goals) -> Goals { … }}

typealias Edits = Changing<Edit>

Accumulating<Edit, Goals>

GoalEdits

Page 154: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

typealias ProgressEdits = Changing<ProgressEdit>

enum ProgressEdit { case bump(goal: Goal)}

extension ProgressEdit { func transform(_ goals: Goals) -> Goals { … }}

typealias Edits = Changing<Edit>

enum Edit { case goalEdit(edit: GoalEdit) case progressEdit(edit: ProgressEdit)}

Accumulating<Edit, Goals>

GoalEdits

Page 155: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

let model: Accumulating<Edit, Goals>Accumulating<Edit, Goals>

Edits

ProgressEdits

GoalEdits

Page 156: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

let model: Accumulating<Edit, Goals>

Edits

ProgressEdits

GoalEdits

Page 157: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

let model: Accumulating<Edit, Goals> = edits.accumulate(startingFrom: initialGoals) { edit, currentGoals in return edit.transform(currentGoals) }

Edits

ProgressEdits

GoalEdits

Page 158: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

val model: Accumulating<Edit, Goals> = edits.accumulate(initial = initialGoals) { edit, currentGoals -> return edit.transform(currentGoals) }

Kolin Edition

Page 159: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Replacing Tests

Page 160: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Replacing Tests

✓ Avoid changes from unexpected placesReplaces integration tests

Page 161: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Replacing Tests

✓ Avoid changes from unexpected placesReplaces integration tests

✓ Avoid conflicting state changesReplaces integration tests

Page 162: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

mchakravartyTacticalGracejusttesting.org

haskellformac.com

Check out the source code of Goals.app!https://github.com/mchakravarty/goalsapp

types >< state

Page 163: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

mchakravartyTacticalGracejusttesting.org

haskellformac.com

Type systems are a design tool

Swift encourages typed functional programming

Types replace entire categories of tests

Check out the source code of Goals.app!https://github.com/mchakravarty/goalsapp

types >< state

Page 164: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Thank you!

Page 165: A Type is Worth a Thousand Tests - SYDspace · Generics & protocols with associated types Type REPL inference Pattern matching ... Adopting Swift right out of the gate. Haskell for

Wikimedia

https://www.flickr.com/photos/30998987@N03/5408763997

Image Attribution

https://commons.wikimedia.org/wiki/File:Nile_blue_05.jpg

https://dribbble.com/shots/1667698-Free-vector-Macbook-Ipad-and-Iphone

https://www.flickr.com/photos/provisions/7986149891/

https://commons.wikimedia.org/wiki/File:Handcuffs01_2008-07-27.jpghttps://commons.wikimedia.org/wiki/File:Set_square_Geodreieck.svg

https://www.flickr.com/photos/digitalcurrency/2438119267https://www.flickr.com/photos/pviojoenchile/2760021279/

https://openclipart.org/detail/463/heart