) ; (eat man dog)
(Slide :content "Lisp just places the parentheses in different places:")
(Code :code "
;
; ( )
;
(eat man dog)")
(Slide :content "
Although the difference between subject and objects isn't as clear cut as in
curly braces languages, and you're really better off writing:
")
(Code :code "
;
; ( ...)
;
(eat dog cat spam eggs)")
; A better representation would be
; ( ...) ; (eat dog cat spam eggs)
; This is a **good** thing. So little syntax makes reading code much easier.
(Slide :content "
This syntax is a good thing !
We'll see why that is at the end when we write our first macro
")
(Slide :title "First Class Functions" :content "
In Lisp, functions can be values too.
For example, in curly braces languages you might have:
")
(Code :code "
o.f(g); //-> h")
(Slide :content "
In this case, only f is a function.
In Lisp, where you might have:
")
; ## First class functions
; Functions can be values.
; For example, in curly braces, if you have a
; o.f(g)-> h
; Only `f` is code. `o`, is an object (namespace for code and holder of data), `g` and `h` are data.
; In Lisp
; (f o g) -> h
(Code :code "
(f o g) ;-> h")
(Slide :content "
All of f , o , g and h can be functions!
Let's take a look at an example.
")
; All `f`, `o`, `g` and `h` can be functions.
(Code :code "
(defun say-something ()
\"Something\") ; Note how we don't need 'return'
(defun say-nothing ()
\"Nothing\")
(defun say-maybe (sayingA sayingB)
(lambda (dosay?)
(if dosay? (sayingB)
(sayingA))))
")
(Slide :content "
And the result of say-maybe can be used as a function :)
Now you basically know lisp! Let's go for Pizza.
")
; Trippy. Or is that foggy?
; ## Quoting and unquoting
; The forms
; `a
; and
; (quote a)
; are equivalent. They mean "The quoted thing as is".
; You know lisp now. My work here is done, let's grab some beers.
(Heading
:title "Assumptions"
:desc "The base of our pyramid")
(Quote
:said "Entities must not be multiplied beyond necessity"
:by "William of Ockham")
; > "When you assume, you're making an ass out of U and me." - Anonymous
(Slide :title "What can we rely on"
:content "
It turns out, very little.
Here is the list of all primitives we'll be using in the talk:
first or car
rest or cdr
list
equal
cond
cons
or
and
not
setq
defun
defmacro
")
; Lists, first, rest, cond, eq?, empty? (in scheme)
(Heading
:title "Destination"
:desc "Beginning with the end in mind")
; ## The Core
; The concept of "objects",
; Objects contain data (fields / attributes)
; Objects contain code code (procedures / methods)
; Methods can access and modify the data of the object with which they are associated ("this").
; Objects interact with one another
; Popular languages are class-based
; Objects are instances of classes
; Class == Type
; Instances are individual objects
; Instances choose what code and data to use when called
; Late binding 'this'
; ## Nice to have
; Class-level data (class variables)
; Class-level methods
; Encapsulation (private members)
; Inheritance? -> Composition better in my book, but ok.
; ## Nuttier than squirrel poop
; Garbage collection
; Compile time type checking -> Issue with Compilation! Let's make a type checker.
(Slide
:title "Minimum viable Object Orientation (MVOOL?)"
:content "
Objects have properties
Objects respond to messages
Objects Inherit properties from their parents
Ugliness is permitted for the sake of time if we know how we could improve it in the future.
")
(Heading
:title "Departing"
:desc "Building a purely functional associative array")
; # The path we must take (Journey)
; > "sooner or later you're going to realize just as I did that there's a difference between knowing the path and walking the path." - Morpheus
; Associative arrays?
; Garbage collection?
(Slide
:title "Picking a place to start"
:content "
We'll build our objects from associative lists.
Most languages have a similar datastructure. You might know it by the following names:
Maps
Dictonaries
Hashtables
Associative Arrays
Naturally, because we're building things from scratch, we don't have this.
All modern lisps have such a datastructure, for what it's worth.
We're building it here because it's instructive
This isn't going to be efficient!
")
(Slide
:title "A Basic API"
:content "
Let's take a look at what our API might look like
")
(Code :code "
; Creation
(Hash)
; Associate a value to a key
(assoc Hash :key value) ;-> new hash
; Getting a value out
(get-in myHash :key) ;-> value
; Removing a value
(dissoc myHash :key) ;-> New Hash
")
(Slide
:title "Our implementation"
:content "
We'll use a list of key-value pairs.
The final structure will look something like this:
")
(Code :code "
(
(:a 1)
(:b 2)
)")
(Slide :content "
Let's get started with some simple utility functions
")
(Code :code "
(defun Hash () `())
(defun second (l)
(first (rest l)))
(defun third (l)
(first (rest (rest l))))
(defun get-key (kv)
(first kv))
(defun get-val (kv)
(second kv))
(defun empty? (xs)
(equal `() xs))
")
(Slide
:title "Implementing the API"
:content "
Let's start Implementing the API
We'll begin by accessing the values:
")
(Code :code "
(defun get-in (m k)
(cond
((empty? m)
nil)
((equal (get-key (first m)) k)
(get-val (first m)))
(:else
(get-in (rest m) k))))")
(Slide :content "We can continue by adding a new element
")
(Code :code "
(defun assoc (m k v)
\"Associates value 'v' to key 'k' in map 'm'\"
(cond
((or (is-null m) (empty? m))
(list (list k v)))
((equal (get-key (first m)) k)
(cons (list k v) (rest m)))
(:else
(cons (first m) (assoc (rest m) k v)))))")
(Slide :content "And finally by disassociating the values
")
(Code :code "
(defun dissoc (m k)
(cond
((or (is-null m) (empty? m)) nil)
((equal (get-key (first m)) k) (rest m))
(:else (cons (first m) (dissoc (rest m) k)))))")
(Slide :title "Let's test!"
:content "
Well, that wasn't so bad!
Now we have our associative lists what does that give us?
")
(Heading :title "Moving to objects")
(Slide
:title "How far can we go with just the Hash"
:content "
It turns out, some way!
We can use the hash and first class function to build a good approximation
")
(Code :code "
; We can now associate attributes to objects!
(setq shape (Hash))
(setq shape (assoc shape :height 4))
(setq shape (assoc shape :width 3))
; We can also add functions as values into
; our objects, because we have first
; class functions
(setq shape
(assoc shape :area
(lambda (this)
(* (get-in this :height)
(get-in this :width)))))
; And use these functions by extracting
; them manually
((get-in shape :area) shape) ;-> 12
")
(Slide :title "So how far to go?"
:content "
Well, we could start by improving the syntax of calling methods
")
(Code :code "
(defun tell (obj message &opt args)
((get-in obj message) obj args))")
(Slide :content "
And for defining properties:
")
(Code :code "
; we can also use a macro to make
; property assignment nicer
(defmacro defprop (class name function)
`(setq ,class
(assoc ,class
,(to-keyword name)
,function)))")
(Slide :title "Now, for Inheritance"
:content "
Now we've satisfied our first two points. Let's move on to Inheritance.
We get this by adding a parent attribute and looking recursively up the parent
hierarchy for a definition.
Let's start with our old definition of get-in...
")
(Code :code "
; This is the definition of get-in we used.
(defun get-in (m k)
(cond
((empty? m) nil)
((equal (get-key (first m)) k) (get-val (first m)))
(:else (get-in (rest m) k))))
")
(Slide :content "And we can use it in our recursive definition
")
(Code :code "
(defun rget-in (m k)
(let
((parent (get-in m :parent))
(v? (get-in m k)))
(cond
((not (is-null v?)) v?)
((not (is-null parent)) (rget-in parent k))
(:else nil))))")
(Slide :content " We'll need to redefine tell to use our new function
")
(Code :code "
(defun tell (obj message &opt args)
((rget-in obj message) obj args))")
(Slide :title "What does this allow us to do?"
:content "Let's take a look
")
(Code :code "
(setq Mammal (Hash))
(setq Mammal
(assoc Mammal :pet
(lambda (this) (tell this :speak)) ))
(setq Dog (Hash))
(setq Dog (assoc Dog :speak (lambda (this) \"Woof\")))
(setq Dog (assoc Dog :parent Mammal))
(setq Cat (Hash))
(setq Cat (assoc Cat :speak (lambda (this) \"Meow\")))
(setq Cat (assoc Cat :parent Mammal))
(tell Cat :pet) ;->\"Meow\"
(tell Dog :pet) ;-> \"Woof\"")
(Heading
:title "Arriving")
(Slide :title "Taking a step back"
:content "Let's review how far we've got so far.
")
(Quote
:said "The truth is of course is that there is no journey. We are arriving and departing all at the same time."
:by "David Bowie")
(Heading :title "Why do we care?")
(Image :src "img/hoc.jpg")
; # Why does this matter? why do we care?
; Power! I'm a power hungry maniac.
; Expressive power in particular.
; Let's just review:
; we built an object system (the foundational paradigm for most people in this room) in a single talk.
; It's clear, concise, elegant, and readable code.
; # Review of the entire code.
; Image of final environment with breakdown of section in colour coded
(Slide :content "
Note that much is missing here! We've got quite a long way to get to the complete object system used by other languages
Hopefully you can see the bones of the system starting to come out.
")
; -----
; [---]-> State handling
; [---]-> Blah blah
; [---]-> Table implementation
; [---]-> GC
; -----
; That's it. You've seen every line.
; # Pedantic corner. "Ummm actually."
; State management as pure fn isn't shown.
; Yes, that's right. There's a lack of purity! OMG.
; Two options:
; - Manual state management (let form on the state data structure)
; - Monads come in - that's the topic for another talk.
; There are more exotic options out there.
(Heading
:title "What this is really about")
(Slide
:title "Not really about Objects"
:content "
No , this is not a sales pitch. Honest!
This is about and alternative way of developing software
What we've done here differs from conventional development in two major ways
Firstly, we have a radically different result and outcome by using a Domain Specific Language to represent Object Orientation
Secondly, we used a different process for getting to our result
")
(Quote
:said "Lisp isn't a language, it's a building material."
:by "Alan Kay")
(Slide
:title "A different result by using a DSL"
:content "
DSLs are Domain Specific Languages
They are a scalable way of abstracting complexity . Functional languages are well suited for building DSLs, and Lisp is particularly well suited to this way of develping.
What we've done so far is build a DSL for manipulating objects and recreate an OO language.
You could build a DSL for logical, declarative programming too.
Examples of exactly this can be found in Minikanren or core.logic . SICP also shows how to do this in details.
DSLs crop up everywhere.
For example, these slides are build using a DSL:
")
(Code
:disableEditor t
:code "(Heading
:title \"Lisp Primer\"
:desc \"Getting started with Lisp\")")
(Slide
:content "
In practice, you will rarely want to recreate an OO language inside a functional one.
The construct you have available in Lisp tend to be more expressive anyway.
We only used this as a usecase because everyone is very familiar with the domain.
")
(Slide
:title "A different process by using interactive development"
:content "
We haven't fully explored this aspect. Development can become
even more interactive. For example, because code is data, the environment
can be serialised to disk as lisp code any time.
There are some more sophisticated tools to do this.
For example, Light Table allows you to reload code
in the browser at the function level, to replace individual functions while
they're being called in an update loop.
")
(Slide
:title "Artefact vs Side Effect"
:content "
This way of develping software is different to the approach you usually take.
Traditionally, the program is an artefact that you create .
We perform discovery to figure out what the problem is and what the solution could be.
By using the repl to explore the problem, we're working in a different paradigm.
The program is the result of the conversation we've had with the system.
It becomes a side effect of the discovery . The feedback loop is much shorter.
")
(Quote
:said "That language is an instrument of human reason, and not merely a medium for the expression of thought, is a truth generally admitted."
:by "George Boole")
(Slide
:content "The difference is qualitative, and experiencing the second mode
of development will spoil you.
You'll never want to go back to Program as Artefact .
")
(Slide
:title "Try this yourself!"
:content "
This talk is hosted online so you can try it out yourself at:
fractallambda.com/building-objects-with-functions/ .
")
(Heading :title "Thank you for your time")
(Slide
:title "Please stay in touch"
:content "
I hope this will be the beginning of a bigger journey
There is still much to learn and to improve.
Please stay in touch by tweeting to @fractallambda
or emailing brice@fractallambda.com if you take this any further or take any actions as a result of this evening.
And share where you take these ideas!
")
(Slide
:title "References"
:content "
")
(Slide
:title "Interesting links"
:content "
")
(funcall ($ ".slide-editor") each
(lambda (index)
(let (
(editor window.editor)
(snippet (ace.edit this))
(button (funcall (funcall ($ this) parent) find "button"))
)
(button.click (lambda (e)
(progn
(console.log editor)
(editor.navigateFileEnd)
(editor.insert (+ "\n" (snippet.getValue))))))
(snippet.renderer.setPadding 20)
(snippet.setOptions
(object
:maxLines 10000
:readOnly t
:highlightActiveLine f
:showGutter f
:fontSize 20
:mode "ace/mode/lisp"
:theme "ace/theme/tomorrow_night_blue")))))