ITT 2015 - Saul Mora - Object Oriented Function Programming

Post on 13-Jan-2017

110 views 1 download

Transcript of ITT 2015 - Saul Mora - Object Oriented Function Programming

Object Oriented Functional Programming

Saul Mora smora@coursera.org

@casademora

Functional Object Oriented Programming

Saul Mora smora@coursera.org

@casademora

Programming Oriented Functional Object

Saul Mora smora@coursera.org

@casademora

Objects

C++

Objective C

C#

Java

RubyPython

Javascript PHP

Scala!

Clojure!

Swift

Will it blend

What a Functional Language is NOT

Statically Typed

Generic

Overloaded Operators

Optionals

A language where functions are value types

F(x) = y

f(x: Int) -> Int

let numbers = [1, 2, 3, 4, 5]var calculatedNumbers: [Int] = []for value in numbers { calculatedNumbers.append(value * 2)}

map

let numbers = [1, 2, 3, 4, 5]let calculatedNumbers = map(numbers) { $0 * 2 }

Declarative vs. Imperative

What vs. How

Deep Dive

func old_and_busted_expired(fileURL: NSURL) -> Bool

func old_and_busted_expired(fileURL: NSURL) -> Bool { let fileManager = NSFileManager() if let filePath = fileURL.path { if fileManager.fileExistsAtPath(filePath) { var error: NSError? let fileAttributes =

fileManager.attributesOfItemAtPath(filePath, error: &error)

if let fileAttributes = fileAttributes { if let creationDate =

fileAttributes[NSFileModificationDate] as? NSDate {

return creationDate.isBefore(NSDate.oneDayAgo())

} } else { NSLog("No file attributes \(filePath)") } } } return false}

!let fileManager = NSFileManager()if let filePath = fileURL.path { if fileManager.fileExistsAtPath(filePath) { var error: NSError? let fileAttributes =

fileManager.attributesOfItemAtPath(filePath, error: &error)

if let fileAttributes = fileAttributes { if let creationDate =

fileAttributes[NSFileModificationDate] as? NSDate {

return creationDate .isBefore(NSDate.oneDayAgo())

} } else { NSLog("No file attributes \(filePath)") } }}

return creationDate.isBefore(NSDate.oneDayAgo())

!let fileManager = NSFileManager()if let filePath = fileURL.path { if fileManager.fileExistsAtPath(filePath) { var error: NSError? let fileAttributes =

fileManager.attributesOfItemAtPath(filePath, error: &error)

if let fileAttributes = fileAttributes { if let creationDate =

fileAttributes[NSFileModificationDate] as? NSDate {

return creationDate .isBefore(NSDate.oneDayAgo())

} } else { NSLog("No file attributes \(filePath)") } }}

unwrapping the file path!

check if the file exists!

extract and unwrap the file attributes!

extract, unwrap and cast the NSModifiedDateAttribute!

compute one day ago!

return comparison to file last modified date

let filePath = fileURL.path

let fileExists : (_) -> (_)

let fileExists : (String) -> (String?)

let fileExists : (String) -> (String?) ={ path in

fileManager.fileExistsAtPath(path) ? path : nil

}

let retrieveFileAttributes : (_) -> (_)

let retrieveFileAttributes : (String) -> ([NSObject: AnyObject]?)

let retrieveFileAttributes : (String) -> ([NSObject: AnyObject]?) = { path invar error : NSError?let attributes = fileManager.attributesOfItemAtPath(path, error: &error)

!if attributes == nil {NSLog("Unable to check \(filePath): \(error)")

}return attributes

}

let extractCreationDate : (_) -> (_)

let extractCreationDate : ([NSObject:AnyObject]) -> (NSDate?)

let extractCreationDate : [NSObject:AnyObject] -> NSDate? = { $0[NSFileModificationDate] as? NSDate }

filePath: String?

fileExists: String -> String?

extractFileAttributes: String -> [NSObject:AnyObject]?

extractCreationDate: [NSObject:AnyObject] -> NSDate?

let filePath: String?

let fileExists: String -> String?

let extractFileAttributes: String -> [NSObject:AnyObject]?

let extractCreationDate: [NSObject:AnyObject] -> NSDate?

bind

bind(A?, f(A,B?)) -> B?

func bind<A, B>(a: A?, f: A -> B?) -> B? { if let x = a { return f(x) } else { return .None }}

bind(filePath, fileExists)

bind(bind(filePath, fileExists), retrieveFileAttributes)

bind(bind(bind(filePath, fileExists), retrieveFileAttributes), extractCreationDate)

let creationDate: NSDate? = bind(bind(bind(filePath, fileExists), retrieveFileAttributes), extractCreationDate)

>>= operator

func >>=<A, B>(a: A?, f: A -> B?) -> B? { return bind(a, f)}

bind(filePath, fileExists)

filePath >>= fileExists

if let creationDate = filePath >>= fileExists >>= retrieveFileAttributes >>= extractCreationDate { return creationDate.isBefore(NSDate.oneDayAgo())}

let checkExpired: NSDate -> Bool? = { $0.isBefore(NSDate.oneDayAgo()) }

return filePath >>= fileExists >>= retrieveFileAttributes >>= extractCreationDate >>= checkExpired ?? false

func expired(fileURL: NSURL) -> Bool { let fileManager = NSFileManager() var error : NSError? let filePath = fileURL.path let fileExists : (String) -> (String?) =

{ path in fileManager.fileExistsAtPath(path) ? path : nil } let retrieveFileAttributes : (String) -> ([NSObject: AnyObject]?) =

{ path in var error : NSError? return fileManager.attributesOfItemAtPath(path, error: &error) } let extractCreationDate : ([NSObject:AnyObject]) -> NSDate? =

{ $0[NSFileModificationDate] as? NSDate } let checkExpired: NSDate -> Bool? =

{ $0.isBefore(NSDate.oneDayAgo()) } return filePath >>= fileExists >>= retrieveFileAttributes >>=

extractCreationDate >>= checkExpired ?? false}

Readability

bind!

flatMap (fmap)!

apply

>>= (>>-)!

<^> (<$>)!

<*>

func <^><A, B>(f: A -> B, a: A?) -> B? { return fmap(f, a)}!func fmap<A, B>(f: A -> B, a: A?) -> B? { if let x = a { return f(x) } else { return .None }}

func <*><A, B>(f: (A -> B)?, a: A?) -> B? { return apply(f, a)}!func apply<A, B>(f: (A -> B)?, a: A?) -> B? { if let x = a, let fx = f { return fx(x) } return .None}

Argohttp://github.com/thoughtbot/Argo

What about objects?

Caching

retrieve

protocol DataSource { func fetchItem() -> Int?}!func retrieve<S: DataSource, T>(from: S, or: S) -> T? { return from.fetchItem() ?? or.fetchItem()}

protocol DataSource { func fetchItem() -> Int?}!func retrieveItem<S: DataSource, T>(from: S, or: S) -> T? { return from.fetchItem() ?? or.fetchItem()}

return <DataSource>!.functionCall()! -> Int?

!func retrieve<S: DataSource, T>

(from: S, or: S, using: S -> T?) -> T?{ return using(from) ?? using(or)}

let localDataSource: DataSourcelet remoteDataSource: DataSourcereturn retrieve(from: localDataSource, or: remoteDataSource) { $0.fetchItem() }

Data Client

RemoteDataSource

LocalDataSource

Data Client

RemoteDataSource

LocalDataSource

Data Client

RemoteDataSource

LocalDataSource

DataSourceCache

Data Client RemoteDataSource

LocalDataSource

DataSourceCache

Cache Strategy

protocol DataSourceCacheStrategy { func retrieve<T>(from: [DataSource], using: DataSource -> T?) -> T? } !struct DataSourceCache { let strategy: DataSourceCacheStrategy let localDataSource: DataSource let remoteDataSource: DataSource func fetch<T>(applyFunction: DataSource -> T?) -> T? { let sources = [localDataSource, remoteDataSource] return strategy.retrieve(sources, using: applyFunction) } }

struct BasicDataSourceCacheStrategy: DataSourceCacheStrategy { func retrieve<T>(from: [DataSource], using: DataSource -> T?) -> T? { for dataSource in from { if let result = using(dataSource) { return result } } return nil } }

struct MoreFancyDataSourceCacheStrategy: DataSourceCacheStrategy { ! func retrieve<T>(from: [DataSource], using: DataSource -> T?) -> T? { let cacheValidation: T? -> Bool = { $0 != nil } for dataSource in from { let result = using(dataSource) if cacheValidation(result) { return result } } return nil } }

https://gist.github.com/casademora/

3b784e57bd09c0bc9147

Encapsulation

Abstraction

SOLID

Object Oriented in the Large, Functional in the

Small

- Alan Kay, The Early History of Smalltalk

I was less interested in programs as algebraic patterns than I was in a clear scheme that could

handle a variety of styles of programming.

Programming

–Alan Kay

Programming is at heart a practical art in which real things are built, and a real implementation

thus has to exist.

Object Oriented Functional Programming

Saul Mora smora@coursera.org

@casademora