SlideShare ist ein Scribd-Unternehmen logo
1 von 48
Metaprogramming, Metaclasses
&
The Metaobject Protocol
Raymond Pierre de Lacaze
rpl@lispnyc.org
LispNYC, June 11th 2013
Overview
• This talk presents material from The Art of the Metaobject Protocol
by Gregor Kiczles, Jim de Rivieres, Daniel G. Bobrow, MIT Press, 1991
• Metaprogramming
– Programming with macros
– Metaprogramming in other languages
• Metaclasses
– objects, metaobjects and metaclasses
– CLOS in a nutshell
– Use case of a metaclass: AllegroCache
• Metaobject Protocol
– motivations underlying a MOP
– Part of the implementation of Closette
– Designing and Implementing a metaobject protocol
Metaprogramming (Wikipedia)
• Metaprogramming is the writing of computer
programs that write or manipulate other
programs, or themselves, as their data.
• The language in which the metaprogram is
written is called the metalanguage
• The ability of a programming language to be its
own metalanguage is called reflextion or
reflexivity.
• Having the programming language itself as a first-
class data type is known as homoicomicity.
– Lisp, Forth, Rebol
• Homoiconicity: Code = Data
Homoiconicity Example
code.lisp: (defun add (x y)(+ x y))
USER(12): (setf code (with-open-file (file "C:code.lisp") (read file)))
(defun add (x y)(+ x y))
CL-USER(13): (type-of code)
CONS
CL-USER(14): (first code)
DEFUN
CL-USER(15): (fourth code)
(+ X Y)
CL-USER(16): (setf (second code) 'subtract)
SUBTRACT
CL-USER(19): (setf (fourth code) '(- x y))
(- X Y)
CL-USER(20): code
(DEFUN SUBTRACT (X Y) (- X Y))
CL-USER(21): (eval code)
SUBTRACT
CL-USER(22): (subtract 5 6)
-1
Approaches to Metaprogramming
(Wikipedia)
• Statically typed functional languages
– Usage of dependent types allows proving that generated code is
never invalid.
• Template metaprogramming
– C "X Macros"
– C++ Templates
• Staged meta-programming
– MetaML
– MetaOCaml
• Macro systems
– Lisp hygienic macros
– MacroML
– Template Haskell
Part I: LISP MACROS
Why Macros?
Say we want to add a new language feature:
(unless* <test> <expr>)
;; Using a function we could do:
> (defun unless* (test expr)
(if test nil expr))
UNLESS*
> (unless* nil (print "This should print."))
This should print.
nil
> (unless* t (print "This should not print"))
This should not print
nil
Uh oh! The function unless* evaluates <expr> regardless of <test>!
Macros in a Nutshell
• Macros do not evaluate their arguments
• Expanded at compile-time into another
programmatic form (AST transform) as specified
by the definition of the macro
• It is this resulting programmatic form that is
actually compiled by the compiler.
• In CL can use back-quote, comma & comma-at as
convenient list manipulators to write macros
• In Clojure can use syntax-quote, tilde & tilde-at
convenient list manipulators to write macros
My First Macro
> (defmacro unless* (test expr)
(list 'if test nil expr))
UNLESS*
;; This works as before
> (unless* nil (println "This should print."))
This should print.
nil
;; This now behaves correctly
> (unless* t (println "This should not print"))
nil
;; You can use backquote and comma instead of explicit list constructors
> (defmacro unless* (test expr)
`(if ,test nil ,expr))
UNLESS*
Debugging Macros
;; This is not correct
> (defmacro INVOKE-OP (op arg1 arg2 &rest args)
`(funcall ',op ,arg1 ,arg2 ,args))
INVOKE-OP
> (macroexpand '(invoke-op * 3 4 5 6))
(funcall '* 3 4 (5 6))
;; This is correct
> (defmacro INVOKE-OP (op arg1 arg2 &rest args)
`(funcall ',op ,arg1 ,arg2 ,@args))
> (macroexpand '(invoke-op * 3 4 5 6))
(funcall '* 3 4 5 6))
Side Effects & Variable Capture in Macros
• When you define a macro, it is unsafe to evaluate the arguments
more than once in the event that they have side effects.
• Lisp provides gensym to allow you to define local variables in safe
way and also avoid unintentionally repeating side-effects
;; This is bad: <expr> is evaluated twice!
> (defmacro unless* (test expr)
`(let ()
(format t “~%Expr: ~a” ,expr)
(if ,test nil ,expr)))
UNLESS*
> (unless* nil (print "foo"))
"foo"
Expr: foo
"foo"
"foo"
;; This is good: Use gensym to avoid variable
;; capture and avoid repeating side-effecting forms
>(defmacro unless* (test expr)
(let ((result (gensym)))
`(let ((,result ,expr))
(format t “~%Expr: ~a” ,result)
(if ,test nil ,result))
UNLESS*
> (unless* nil (print "foo"))
"foo"
Expr: foo
"foo"
Recursive Macros
> (defmacro LISP ()`(,(lisp) In Summer Projects))
LISP
> (lisp)
Error: Stack overflow (signal 1000)
[condition type: SYNCHRONOUS-OPERATING-SYSTEM-SIGNAL]
>(defmacro LISP (n)
`(if (> ,n 0) `(,(lisp (1- ,n)) In Summer Projects) 'LISP)
> (lisp 0)
LISP
> (lisp 1)
(LISP IN SUMMER PROJECTS)
> (lisp 2)
((LISP IN SUMMER PROJECTS) IN SUMMER PROJECTS)
> (lisp 3)
(((LISP IN SUMMER PROJECTS) IN SUMMER PROJECTS) IN SUMMER PROJECTS)
Macros Summary
• Don’t use macros if you can achieve the same
thing with a simple function
• Macros are useful for implementing DSLs or
adding new language features
• Use macroexpand to debug macros
• Leverage backquote, comma, comma-at for
macro readability.
• Use gensym to write hygienic macros
• Paul Graham’s “On Lisp” is the macro book
Part II: Metaclasses
What is a Metaclass?
• In an object orient system the term object refers
the domain entities that are being modeled, e.g.
a bank-account object.
• Programmers have access to these objects
• A metaobject refers to the objects the language
uses to model/implement your domain objects ,
e.g. a bank-account-class object
• Programmers do not have access to these
metaobjects (typically)
• Only Language Implementers have access to
these metaobjects (typically)
• A metaclass is the class of a metaobject
Metaobject & Metaclass Example
;; In CLOS define a bank account class
> (defclass bank-account () ((account-number)(owner)(balance)))
#<STANDARD-CLASS BANK-ACCOUNT>
;; Create a bank account object
> (make-instance 'bank-account)
#<BANK-ACCOUNT {10029ED253}>
;; The class of the bank account object is a metaobject
> (class-of *)
#<STANDARD-CLASS BANK-ACCOUNT>
;; The class of this class metaobject is a metaclass
> (class-of *)
#<STANDARD-CLASS STANDARD-CLASS>
Basic CLOS: defclass
> (defclass bank-account ()
((account-number :initarg :account-number
:accessor bank-account-number)
(account-balance :initarg :account-balance
:accessor bank-account-balance
:initform 0)))
#<STANDARD-CLASS BANK-ACCOUNT>
> (make-instance 'bank-account :account-number 123456789 :account-balance 500)
#<BANK-ACCOUNT {1002E20513}>
> (describe *)
#<BANK-ACCOUNT {1002E20513}>
[standard-object]
Slots with :INSTANCE allocation:
ACCOUNT-NUMBER = 123456789
ACCOUNT-BALANCE = 500
> (bank-account-balance **)
500
Basic CLOS: defgeneric & defmethod
> (defgeneric PLUS (arg1 arg2))
#<STANDARD-GENERIC-FUNCTION PLUS (0)>
> (defmethod PLUS ((arg1 NUMBER)(arg2 NUMBER))
(+ arg1 arg2))
#<STANDARD-METHOD PLUS (NUMBER NUMBER) {100313BFF3}>
> (defmethod PLUS ((arg1 STRING)(arg2 STRING))
(concatenate 'string arg1 arg2))
#<STANDARD-METHOD PLUS (STRING STRING) {100319C953}>
> (plus 1 2)
3
> (plus "a" ”b”)
"ab”
AllegroCache: Object Persistence in Lisp
• AllegroCache – A high-performance, dynamic
object caching database system.
• Implements full transaction model with long and
short transactions, and meets the classic ACID
compliancy and maintains referential integrity.
• 64-bit real-time data caching
• http://www.franz.com/products/allegrocache/
The Persistent-Class Metaclass
> (defclass POINT ()
((name :reader point-name :index :any-unique)
(x :initarg :x :accessor point-x :index :any)
(y :initarg :y :accessor point-x :index :any)
(rho :accessor point-rho :allocation :instance)
(theta :accessor point-theta :allocation :instance))
(:metaclass db.ac::persistent-class))
#<DB.ALLEGROCACHE:PERSISTENT-CLASS POINT>
> (setf p1 (make-instance 'point :x 20 :y 30))
Error: Attempt to do a database operation without an open database
> (db.ac::open-file-database "C:ProjectstrunkLanguagesMOPDB“
:if-does-not-exist :create)
#<AllegroCache db "C:ProjectstrunkLanguagesMOPDB" @ #x218b8942>
> (setf p1 (make-instance 'point :x 20 :y 30))
#<POINT oid: 12, ver 5, trans: NIL, modified @ #x2197943a>
Instances of a Specialized Metaclass
> (describe p1)
#<POINT oid: 14, ver 7, trans: NIL, modified @ #x21ad2aba> is an
instance of #<DB.ALLEGROCACHE:PERSISTENT-CLASS POINT>:
The following slots have :INSTANCE allocation:
OID 14
SLOTS #((:UNBOUND) (:UNBOUND) (:UNBOUND))
NEW-SLOTS #(POINT-1 20 30)
DCLASS #<DB.ALLEGROCACHE::FILE-DASH-CLASS @ #x219796a2>
VERSION 7
PREV-VERSION NIL
TRANS NIL
MODIFIED :END
RHO <unbound>
THETA <unbound>
The following slots have nonstandard allocation as shown:
NAME :PERSISTENT POINT-1
X :PERSISTENT 20
Y :PERSISTENT 30
Metaclass
• Metaclasses allow you to extend existing
language constructs. E.g. defclass
• This can be more natural than a DSL or a
separate API outside the language
• Allow you to safely change or extend the
behavior of the language
• Metaclasses are a very powerful underutilized
programming paradigm. (IMHO)
Part III: The Metaobject Protocol
Protocol Definitions
• An object protocol is a collection of methods
that operate on some collection of objects.
• A metaobject protocol is a collection of
methods that operate on some collection of
metaobjects.
• A metaclass refers to the class of a metaobject
Implementing defclass
;;; All the code on the next few slides is taken from the AMOP book.
(defmacro DEFCLASS (name direct-superclasses direct-slots &rest options)
`(ensure-class ',name
:direct-superclasses ,(canonicalize-direct-superclasses direct-superclasses)
:direct-slots ,(canonicalize-direct-slots direct-slots)
,@(canonicalize-defclass-options options)
(defun ENSURE-CLASS (name &rest all-keys)
(if (find-class name nil)
(error "Can't redefine the class named ~S in Closette." name)
(let ((class (apply #'make-instance 'standard-class :name name all-keys)))
(setf (find-class name) class)
class)))
(let ((class-table (make-hash-table :test #'eq :size 20)))
(defun (SETF FIND-CLASS) (new-value symbol)
(setf (gethash symbol class-table) new-value))
)
Implementing defclass (cont.)
(defclass STANDARD-CLASS ()
((name :initarg :name
:accessor class-name)
(direct-superclasses :initarg :direct-superclasses
:accessor class-direct-superclasses)
(direct-slots :initarg :direct-slots
:accessor class-direct-slots)
(class-precedence-list :initarg :class-precedence-list
:accessor class-precedence-list)
(effective-slots :accessor class-slots)
(direct-subclasses :initform ()
:accessor class-direct-subclasses)
(direct-methods :initform ()
:accessor class-direct-methods)))
Implementing defclass (cont.)
(defmethod INITIALIZE-INSTANCE :after ((class STANDARD-CLASS)
&key direct-superclasses direct-slots)
(let ((supers (or direct-superclasses `(,(find-class 'standard-object)))))
(setf (class-direct-superclasses class) supers)
(dolist (superclass supers)
(push class (class-direct-subclasses superclass))))
(let ((slots (mapcar #'(lambda (slot-properties)
(apply #'make-direct-slot-definition slot-properties))
direct-slots)))
(setf (class-direct-slots class) slots)
(dolist (direct-slot slots)
(dolist (reader (slot-definition-readers direct-slot))
(add-reader-method class reader (slot-definition-name direct-slot))))
(dolist (direct-slot slots)
(dolist (writer (slot-definition-writers direct-slot))
(add-writer-method class writer (slot-definition-name direct-slot)))))
(finalize-inheritance))
Implementing defclass (cont.)
(defun FINALIZE-INHERITANCE (class)
(setf (class-precedence-list class)(compute-class-precedence-list))
(setf (class-slots class) (compute-slots class)))
(defun COMPUTE-CLASS-PRECEDENCE-LIST (class)
(let ((classes-to-order (collect-superclasses* class)))
(topological-sort classes-to-order
(remove-duplicates
(mapappend #'local-precedence-ordering classes-to-order))
#'std-tie-breaker-rule)))
(defun COLLECT-SUPERCLASSES* (class)
(remove-duplicates
(cons class
(mapappend #'collect-superclasses* (class-direct-superclasses class)))))
Metaobject Protocol Definition
• A metaobject protocol is an API that allows you to
access and manipulate metaobjects.
• “A metaobject protocol is an interface to elements of a
language that are normally hidden from users of the
language. Providing such an interface allows users of
the language to tailor the language to their own needs
and in such a way provides a more powerful and
flexible language. The CLOS metaobject protocol
provides an interface to program elements such as
classes and methods, thereby allowing users to control
aspects of the language such as how instances of a
class are created or how method dispatching works”.
Raymond de Lacaze, JLUGM, 2000
Introspective vs. Intercessory
• AMOP has both introspective and intercessory
aspects.
• Introspective
– Allows programmers to see the on-backstage.
Metaobjects can be created, retrieved and examined.
• Intercessory
– Allows programmers to manipulate the on-backstage
thereby affecting the on-stage behavior
Example MOP Usage
;; Usage Example 1: An instance-counting metaclass
;; Provide a slot in the metaclass to track number of instances
(defclass COUNTED-CLASS (STANDARD-CLASS)
((counter :initform 0)))
;; Then add an :after method on make-instance that bumps count
(defmethod MAKE-INSTANCE :after ((class COUNTED-CLASS) &key)
(incf (slot-value class) ‘counter))
Example MOP Usage (cont.)
• Need to define a class with a metaclass other than
standard-class.
• We can’t use defclass, because as previously written it
always uses standard-class as the metaclass
(setf (find-class ‘counted-rectangle)
(make-instance ‘counted-class
:name ‘counted-rectangle
:direct-superclasses (list (find-class ‘rectangle))
:direct-slots nil))
Extending defclass Implementation
;;; We would like to simply write the following
(defclass COUNTED-RECTANGLE (rectangle)
()
(:meta-class counted-class))
;; Simply need to extend the definition of ensure-class
(defun ENSURE-CLASS (name &rest all-keys
&key (metaclass (find-class ‘standard-class)))
(if (find-class name nil)
(error "Can't redefine the class named ~S in Closette." name)
(let ((class (apply #'make-instance metaclass :name name all-keys)))
(setf (find-class name) class)
class)))
Understanding Method Combination
> (defclass a ()())
#<STANDARD-CLASS A>
> (defclass b (a)())
#<STANDARD-CLASS B>
> (defclass c (a b)())
#<STANDARD-CLASS C>
a b
c
• Add primary methods on a, b, c
• Add :before method on a, b, c
• Add :after method on a, b, c
• Add :around methods on a, b, c
Adding All Possible Methods
(defmethod FOO ((obj A))
(format t "~%Primary method on class A")
(call-next-method))
(defmethod FOO ((obj B))
(format t "~%Primary method on class B"))
(defmethod FOO ((obj C))
(format t "~%Primary method on class C")
(call-next-method))
(defmethod FOO :before ((obj A))
(format t "~%Before method on class A"))
(defmethod FOO :before ((obj B))
(format t "~%Before method on class B"))
(defmethod FOO :before ((obj C))
(format t "~%Before method on class C"))
(defmethod FOO :after ((obj A))
(format t "~%After method on class A"))
(defmethod FOO :after ((obj B))
(format t "~%After method on class B"))
(defmethod FOO :after ((obj C))
(format t "~%After method on class C"))
(defmethod FOO :around ((obj A))
(format t "~%Around method (before) on class A")
(call-next-method)
(format t "~%Around method (after) on class A"))
(defmethod FOO :around ((obj B))
(format t "~%Around method (before) on class B")
(call-next-method)
(format t "~%Around method (after) on class B"))
(defmethod FOO :around ((obj C))
(format t "~%Around method (before) on class C")
(call-next-method)
(format t "~%Around method (after) on class C"))
> (setf x (make-instance 'c))
#<C @ #x209681b2>
CLOS Method Combination
CL-USER(45): (foo x)
Around method (before) on class C
Around method (before) on class A
Around method (before) on class B
Before method on class C
Before method on class A
Before method on class B
Primary method on class C
Primary method on class A
Primary method on class B
After method on class B
After method on class A
After method on class C
Around method (after) on class B
Around method (after) on class A
Around method (after) on class C
NIL
Changing Method Combination
(defclass a ()())
(defclass b ()())
(defclass c ()())
(defclass s (a b)())
(defclass r (a c)())
(defclass q (r s)())
• Different Lisp object systems used different method combination
• How can we reuse code written in Flavors, in CLOS?
• We would like to be able to change method combination order
Flavors: (q s a b r c standard-object t)
Loops: (q s b r a c standard-object t)
CLOS: (q s r a b c standard-object t)
a b c
s r
q
Compute-Class-Precedence-List
• Do not allow programmers to directly set class-precedence-list slot of the class metaobject but.
• Allow them to control the computation that is used when that slot I set
• Make compute-class-precedence-list a GF and specialize the original function on standard-class
• Require that the class be the first in the list and that standard-object and t be the last two.
(defclass flavors-class (standard-class) ())
(defmethod compute-class-precedence ((class flavors-class))
(append (remove-duplicates (depth-first-preorder-superclasses* class)
:from-end t)
(list (find-class ‘standard-object)
(find-class ‘t))))
Additional AMOP Examples
• Adding slot attributes
– compute-slots (GF)
– compute-effective-slots (GF)
• Adding default-initargs
– ensure-class
– make-instance
– finalize-inheritance (GF)
• Instance Allocation
– allocate-instance (GF)
Note: In the examples we’ve seen so far we’ve had to rewrite ensure-class twice
Designing a MOP
• Design revolves around CLOS metaobjects
– Class metaobjects
– Method metaobject
– Generic function metaobjects
– Slot definition metaobjects
– Specializer metaobjects
– Method combination objects
• AMOP is designed to provide an introspective and
intercessory API for manipulating and
customizing these metaobjects
Designing a MOP
• Design: MOP should provide mechanisms to extend the syntax and
manipulate the behavior of CLOS without:
– Needing to rewrite the programmer user interface macros: defclass,
defgeneric and defmethod
– Needing to rewrite the functions that implement these macros, namely the
ensure-x functions and the compute-x functions
• Implementation
– This is mostly accomplished by making the compute-X functions (on the
various metaobjects) generic functions, thus using CLOS to implement the
implementation of CLOS.
– This approach also provides a level of safety because users of the MOP cannot
directly set the values of the slots of the metaobjects, they can only control
their computation which is only performed once and cannot subsequently
changed.
The Final defclass
(defmacro DEFCLASS (name direct-superclasses direct-slots &rest options)
(let* ((metaclass-option (find ‘:metaclass options :key #’car))
(metaclass-name (or (second metaclass-option) ‘standard-class))
(sample-class-metaobject
(allocate-instance (find-class metaclass-name)))
(canonical-supers
(canonicalize-direct-superclasses direct-superclasses))
(canonical-slots
(canonicalize-direct-slots direct-slots))
(canonical-options
(canonicalize-defclass-options sample-class-metaobject
(remove metaclass-option options))))
`(ensure-class ‘,name
:direct-superclasses ,canonical-supers
: direct-slots ,canonical-slots
:metaclass (find-class ‘,metaclass)
,@canonical-options)))
CLOS Metaclass Hierarchy
When to use a MOP
• Any time you need to alter how a metaobject behaves.
For instance, instead of doing a method lookup on a
local table, perform an RPC call.
• Memoizing method calls
• Complex inheritance (this may be of dubious value)
• Loosening or strengthening a type system
• Implementing Dynamic Dispatch (if necessary)
• Persistence
• Replication
This list is from: http://community.schemewiki.org/?meta-object-protocol
Additional Links
• http://en.wikipedia.org/wiki/Metaprogramming
• https://en.wikipedia.org/wiki/Metaclass
• http://en.wikipedia.org/wiki/Metaobject
• http://www.dreamsongs.com/CLOS.html
• http://www.franz.com/services/conferences_seminars/jlugm00/conference/Talk02_deLacaze1.pdf
• http://www.cs.cmu.edu/afs/cs/project/ai-repository/ai/lang/lisp/oop/clos/closette/0.html
• http://www.cs.cmu.edu/afs/cs/project/ai-repository/ai/lang/lisp/doc/standard/ansi/mop/
• http://community.schemewiki.org/?meta-object-protocol
• http://www.gnu.org/software/guile/manual/html_node/GOOPS.html
• http://clojure.org/multimethods
Additional Definitions
• Dependent Types (Wikipedia)
In computer science and logic, a dependent type is a type that depends on a value. Dependent types
play a central role in intuitionistic type theory and in the design of functional programming languages
like ATS, Agda and Epigram and Idris
An example is the type of n-tuples of real numbers. This is a dependent type because the type depends
on the value n.
• Staged meta-programming (Wikipedia)
Incremental compiling of new machine code during runtime. Under certain circumstances, significant
speedups are possible using multi-stage programming, because more detailed information about the
data to process is available at runtime than at the regular compile time, so the incremental compiler can
optimize away many cases of condition checking etc.
Meta Object Protocols

Weitere ähnliche Inhalte

Was ist angesagt?

導来代数幾何入門
導来代数幾何入門導来代数幾何入門
導来代数幾何入門Naoya Umezaki
 
メディア・アート II 第1回: ガイダンス openFrameworks入門
メディア・アート II 第1回: ガイダンス openFrameworks入門メディア・アート II 第1回: ガイダンス openFrameworks入門
メディア・アート II 第1回: ガイダンス openFrameworks入門Atsushi Tadokoro
 
Wikipedia 出典/参考文献の書き方
Wikipedia 出典/参考文献の書き方Wikipedia 出典/参考文献の書き方
Wikipedia 出典/参考文献の書き方Kohei Otsuka
 
よくわかるCoqプログラミング
よくわかるCoqプログラミングよくわかるCoqプログラミング
よくわかるCoqプログラミングReal_analysis
 
謎の言語Forthが謎なので実装した
謎の言語Forthが謎なので実装した謎の言語Forthが謎なので実装した
謎の言語Forthが謎なので実装したt-sin
 
Solid C++ by Example
Solid C++ by ExampleSolid C++ by Example
Solid C++ by ExampleOlve Maudal
 
Introduction to Functional Programming with Scala
Introduction to Functional Programming with ScalaIntroduction to Functional Programming with Scala
Introduction to Functional Programming with Scalapramode_ce
 
Introduction to Categorical Programming (Revised)
Introduction to Categorical Programming (Revised)Introduction to Categorical Programming (Revised)
Introduction to Categorical Programming (Revised)Masahiro Sakai
 
イマドキC++erのモテカワリソース管理術
イマドキC++erのモテカワリソース管理術イマドキC++erのモテカワリソース管理術
イマドキC++erのモテカワリソース管理術Kohsuke Yuasa
 
Kotlin Bytecode Generation and Runtime Performance
Kotlin Bytecode Generation and Runtime PerformanceKotlin Bytecode Generation and Runtime Performance
Kotlin Bytecode Generation and Runtime Performanceintelliyole
 
ナイーブベイズによる言語判定
ナイーブベイズによる言語判定ナイーブベイズによる言語判定
ナイーブベイズによる言語判定Shuyo Nakatani
 
圏論のモナドとHaskellのモナド
圏論のモナドとHaskellのモナド圏論のモナドとHaskellのモナド
圏論のモナドとHaskellのモナドYoshihiro Mizoguchi
 
BoostAsioで可読性を求めるのは間違っているだろうか
BoostAsioで可読性を求めるのは間違っているだろうかBoostAsioで可読性を求めるのは間違っているだろうか
BoostAsioで可読性を求めるのは間違っているだろうかYuki Miyatake
 
Effective modern c++ 5
Effective modern c++ 5Effective modern c++ 5
Effective modern c++ 5uchan_nos
 

Was ist angesagt? (20)

導来代数幾何入門
導来代数幾何入門導来代数幾何入門
導来代数幾何入門
 
メディア・アート II 第1回: ガイダンス openFrameworks入門
メディア・アート II 第1回: ガイダンス openFrameworks入門メディア・アート II 第1回: ガイダンス openFrameworks入門
メディア・アート II 第1回: ガイダンス openFrameworks入門
 
Wikipedia 出典/参考文献の書き方
Wikipedia 出典/参考文献の書き方Wikipedia 出典/参考文献の書き方
Wikipedia 出典/参考文献の書き方
 
C++の黒魔術
C++の黒魔術C++の黒魔術
C++の黒魔術
 
よくわかるCoqプログラミング
よくわかるCoqプログラミングよくわかるCoqプログラミング
よくわかるCoqプログラミング
 
Monad tutorial
Monad tutorialMonad tutorial
Monad tutorial
 
謎の言語Forthが謎なので実装した
謎の言語Forthが謎なので実装した謎の言語Forthが謎なので実装した
謎の言語Forthが謎なので実装した
 
Solid C++ by Example
Solid C++ by ExampleSolid C++ by Example
Solid C++ by Example
 
Introduction to Functional Programming with Scala
Introduction to Functional Programming with ScalaIntroduction to Functional Programming with Scala
Introduction to Functional Programming with Scala
 
Java Programming - 05 access control in java
Java Programming - 05 access control in javaJava Programming - 05 access control in java
Java Programming - 05 access control in java
 
Introduction to Categorical Programming (Revised)
Introduction to Categorical Programming (Revised)Introduction to Categorical Programming (Revised)
Introduction to Categorical Programming (Revised)
 
イマドキC++erのモテカワリソース管理術
イマドキC++erのモテカワリソース管理術イマドキC++erのモテカワリソース管理術
イマドキC++erのモテカワリソース管理術
 
Kotlin Bytecode Generation and Runtime Performance
Kotlin Bytecode Generation and Runtime PerformanceKotlin Bytecode Generation and Runtime Performance
Kotlin Bytecode Generation and Runtime Performance
 
ナイーブベイズによる言語判定
ナイーブベイズによる言語判定ナイーブベイズによる言語判定
ナイーブベイズによる言語判定
 
Boost.SIMD
Boost.SIMDBoost.SIMD
Boost.SIMD
 
圏論のモナドとHaskellのモナド
圏論のモナドとHaskellのモナド圏論のモナドとHaskellのモナド
圏論のモナドとHaskellのモナド
 
Deep C
Deep CDeep C
Deep C
 
BoostAsioで可読性を求めるのは間違っているだろうか
BoostAsioで可読性を求めるのは間違っているだろうかBoostAsioで可読性を求めるのは間違っているだろうか
BoostAsioで可読性を求めるのは間違っているだろうか
 
Effective modern c++ 5
Effective modern c++ 5Effective modern c++ 5
Effective modern c++ 5
 
UML入門
UML入門UML入門
UML入門
 

Andere mochten auch

Reinforcement Learning and Artificial Neural Nets
Reinforcement Learning and Artificial Neural NetsReinforcement Learning and Artificial Neural Nets
Reinforcement Learning and Artificial Neural NetsPierre de Lacaze
 
Domain Driven Design with the F# type System -- F#unctional Londoners 2014
Domain Driven Design with the F# type System -- F#unctional Londoners 2014Domain Driven Design with the F# type System -- F#unctional Londoners 2014
Domain Driven Design with the F# type System -- F#unctional Londoners 2014Scott Wlaschin
 

Andere mochten auch (6)

Knowledge Extraction
Knowledge ExtractionKnowledge Extraction
Knowledge Extraction
 
Clojure 7-Languages
Clojure 7-LanguagesClojure 7-Languages
Clojure 7-Languages
 
Reinforcement Learning and Artificial Neural Nets
Reinforcement Learning and Artificial Neural NetsReinforcement Learning and Artificial Neural Nets
Reinforcement Learning and Artificial Neural Nets
 
Logic Programming and ILP
Logic Programming and ILPLogic Programming and ILP
Logic Programming and ILP
 
Prolog 7-Languages
Prolog 7-LanguagesProlog 7-Languages
Prolog 7-Languages
 
Domain Driven Design with the F# type System -- F#unctional Londoners 2014
Domain Driven Design with the F# type System -- F#unctional Londoners 2014Domain Driven Design with the F# type System -- F#unctional Londoners 2014
Domain Driven Design with the F# type System -- F#unctional Londoners 2014
 

Ähnlich wie Meta Object Protocols

Código Saudável => Programador Feliz - Rs on Rails 2010
Código Saudável => Programador Feliz - Rs on Rails 2010Código Saudável => Programador Feliz - Rs on Rails 2010
Código Saudável => Programador Feliz - Rs on Rails 2010Plataformatec
 
Introduction to Elixir
Introduction to ElixirIntroduction to Elixir
Introduction to ElixirDiacode
 
002. Introducere in type script
002. Introducere in type script002. Introducere in type script
002. Introducere in type scriptDmitrii Stoian
 
S1 DML Syntax and Invocation
S1 DML Syntax and InvocationS1 DML Syntax and Invocation
S1 DML Syntax and InvocationArvind Surve
 
DML Syntax and Invocation process
DML Syntax and Invocation processDML Syntax and Invocation process
DML Syntax and Invocation processArvind Surve
 
Lex tool manual
Lex tool manualLex tool manual
Lex tool manualSami Said
 
Glorp Tutorial Guide
Glorp Tutorial GuideGlorp Tutorial Guide
Glorp Tutorial GuideESUG
 
C programming language tutorial
C programming language tutorial C programming language tutorial
C programming language tutorial javaTpoint s
 
Exploring Clojurescript
Exploring ClojurescriptExploring Clojurescript
Exploring ClojurescriptLuke Donnet
 
React Development with the MERN Stack
React Development with the MERN StackReact Development with the MERN Stack
React Development with the MERN StackTroy Miles
 
Metaprogramovanie #1
Metaprogramovanie #1Metaprogramovanie #1
Metaprogramovanie #1Jano Suchal
 
Big Data Day LA 2015 - Compiling DSLs for Diverse Execution Environments by Z...
Big Data Day LA 2015 - Compiling DSLs for Diverse Execution Environments by Z...Big Data Day LA 2015 - Compiling DSLs for Diverse Execution Environments by Z...
Big Data Day LA 2015 - Compiling DSLs for Diverse Execution Environments by Z...Data Con LA
 
Javascript part1
Javascript part1Javascript part1
Javascript part1Raghu nath
 

Ähnlich wie Meta Object Protocols (20)

Eclipse meets e4
Eclipse meets e4Eclipse meets e4
Eclipse meets e4
 
Código Saudável => Programador Feliz - Rs on Rails 2010
Código Saudável => Programador Feliz - Rs on Rails 2010Código Saudável => Programador Feliz - Rs on Rails 2010
Código Saudável => Programador Feliz - Rs on Rails 2010
 
Writing Macros
Writing MacrosWriting Macros
Writing Macros
 
Matlab-3.pptx
Matlab-3.pptxMatlab-3.pptx
Matlab-3.pptx
 
C notes.pdf
C notes.pdfC notes.pdf
C notes.pdf
 
Introduction to Elixir
Introduction to ElixirIntroduction to Elixir
Introduction to Elixir
 
Lobos Introduction
Lobos IntroductionLobos Introduction
Lobos Introduction
 
002. Introducere in type script
002. Introducere in type script002. Introducere in type script
002. Introducere in type script
 
S1 DML Syntax and Invocation
S1 DML Syntax and InvocationS1 DML Syntax and Invocation
S1 DML Syntax and Invocation
 
DML Syntax and Invocation process
DML Syntax and Invocation processDML Syntax and Invocation process
DML Syntax and Invocation process
 
The Style of C++ 11
The Style of C++ 11The Style of C++ 11
The Style of C++ 11
 
Lex tool manual
Lex tool manualLex tool manual
Lex tool manual
 
Glorp Tutorial Guide
Glorp Tutorial GuideGlorp Tutorial Guide
Glorp Tutorial Guide
 
C programming language tutorial
C programming language tutorial C programming language tutorial
C programming language tutorial
 
Exploring Clojurescript
Exploring ClojurescriptExploring Clojurescript
Exploring Clojurescript
 
React Development with the MERN Stack
React Development with the MERN StackReact Development with the MERN Stack
React Development with the MERN Stack
 
Metaprogramovanie #1
Metaprogramovanie #1Metaprogramovanie #1
Metaprogramovanie #1
 
Java gets a closure
Java gets a closureJava gets a closure
Java gets a closure
 
Big Data Day LA 2015 - Compiling DSLs for Diverse Execution Environments by Z...
Big Data Day LA 2015 - Compiling DSLs for Diverse Execution Environments by Z...Big Data Day LA 2015 - Compiling DSLs for Diverse Execution Environments by Z...
Big Data Day LA 2015 - Compiling DSLs for Diverse Execution Environments by Z...
 
Javascript part1
Javascript part1Javascript part1
Javascript part1
 

Kürzlich hochgeladen

New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebUiPathCommunity
 
Vector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesVector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesZilliz
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostZilliz
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embeddingZilliz
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxhariprasad279825
 
My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024The Digital Insurer
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...Fwdays
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxNavinnSomaal
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Patryk Bandurski
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLScyllaDB
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 

Kürzlich hochgeladen (20)

New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio Web
 
Vector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesVector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector Databases
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embedding
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptx
 
My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptx
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQL
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 

Meta Object Protocols

  • 1. Metaprogramming, Metaclasses & The Metaobject Protocol Raymond Pierre de Lacaze rpl@lispnyc.org LispNYC, June 11th 2013
  • 2. Overview • This talk presents material from The Art of the Metaobject Protocol by Gregor Kiczles, Jim de Rivieres, Daniel G. Bobrow, MIT Press, 1991 • Metaprogramming – Programming with macros – Metaprogramming in other languages • Metaclasses – objects, metaobjects and metaclasses – CLOS in a nutshell – Use case of a metaclass: AllegroCache • Metaobject Protocol – motivations underlying a MOP – Part of the implementation of Closette – Designing and Implementing a metaobject protocol
  • 3. Metaprogramming (Wikipedia) • Metaprogramming is the writing of computer programs that write or manipulate other programs, or themselves, as their data. • The language in which the metaprogram is written is called the metalanguage • The ability of a programming language to be its own metalanguage is called reflextion or reflexivity. • Having the programming language itself as a first- class data type is known as homoicomicity. – Lisp, Forth, Rebol • Homoiconicity: Code = Data
  • 4. Homoiconicity Example code.lisp: (defun add (x y)(+ x y)) USER(12): (setf code (with-open-file (file "C:code.lisp") (read file))) (defun add (x y)(+ x y)) CL-USER(13): (type-of code) CONS CL-USER(14): (first code) DEFUN CL-USER(15): (fourth code) (+ X Y) CL-USER(16): (setf (second code) 'subtract) SUBTRACT CL-USER(19): (setf (fourth code) '(- x y)) (- X Y) CL-USER(20): code (DEFUN SUBTRACT (X Y) (- X Y)) CL-USER(21): (eval code) SUBTRACT CL-USER(22): (subtract 5 6) -1
  • 5. Approaches to Metaprogramming (Wikipedia) • Statically typed functional languages – Usage of dependent types allows proving that generated code is never invalid. • Template metaprogramming – C "X Macros" – C++ Templates • Staged meta-programming – MetaML – MetaOCaml • Macro systems – Lisp hygienic macros – MacroML – Template Haskell
  • 6. Part I: LISP MACROS
  • 7. Why Macros? Say we want to add a new language feature: (unless* <test> <expr>) ;; Using a function we could do: > (defun unless* (test expr) (if test nil expr)) UNLESS* > (unless* nil (print "This should print.")) This should print. nil > (unless* t (print "This should not print")) This should not print nil Uh oh! The function unless* evaluates <expr> regardless of <test>!
  • 8. Macros in a Nutshell • Macros do not evaluate their arguments • Expanded at compile-time into another programmatic form (AST transform) as specified by the definition of the macro • It is this resulting programmatic form that is actually compiled by the compiler. • In CL can use back-quote, comma & comma-at as convenient list manipulators to write macros • In Clojure can use syntax-quote, tilde & tilde-at convenient list manipulators to write macros
  • 9. My First Macro > (defmacro unless* (test expr) (list 'if test nil expr)) UNLESS* ;; This works as before > (unless* nil (println "This should print.")) This should print. nil ;; This now behaves correctly > (unless* t (println "This should not print")) nil ;; You can use backquote and comma instead of explicit list constructors > (defmacro unless* (test expr) `(if ,test nil ,expr)) UNLESS*
  • 10. Debugging Macros ;; This is not correct > (defmacro INVOKE-OP (op arg1 arg2 &rest args) `(funcall ',op ,arg1 ,arg2 ,args)) INVOKE-OP > (macroexpand '(invoke-op * 3 4 5 6)) (funcall '* 3 4 (5 6)) ;; This is correct > (defmacro INVOKE-OP (op arg1 arg2 &rest args) `(funcall ',op ,arg1 ,arg2 ,@args)) > (macroexpand '(invoke-op * 3 4 5 6)) (funcall '* 3 4 5 6))
  • 11. Side Effects & Variable Capture in Macros • When you define a macro, it is unsafe to evaluate the arguments more than once in the event that they have side effects. • Lisp provides gensym to allow you to define local variables in safe way and also avoid unintentionally repeating side-effects ;; This is bad: <expr> is evaluated twice! > (defmacro unless* (test expr) `(let () (format t “~%Expr: ~a” ,expr) (if ,test nil ,expr))) UNLESS* > (unless* nil (print "foo")) "foo" Expr: foo "foo" "foo" ;; This is good: Use gensym to avoid variable ;; capture and avoid repeating side-effecting forms >(defmacro unless* (test expr) (let ((result (gensym))) `(let ((,result ,expr)) (format t “~%Expr: ~a” ,result) (if ,test nil ,result)) UNLESS* > (unless* nil (print "foo")) "foo" Expr: foo "foo"
  • 12. Recursive Macros > (defmacro LISP ()`(,(lisp) In Summer Projects)) LISP > (lisp) Error: Stack overflow (signal 1000) [condition type: SYNCHRONOUS-OPERATING-SYSTEM-SIGNAL] >(defmacro LISP (n) `(if (> ,n 0) `(,(lisp (1- ,n)) In Summer Projects) 'LISP) > (lisp 0) LISP > (lisp 1) (LISP IN SUMMER PROJECTS) > (lisp 2) ((LISP IN SUMMER PROJECTS) IN SUMMER PROJECTS) > (lisp 3) (((LISP IN SUMMER PROJECTS) IN SUMMER PROJECTS) IN SUMMER PROJECTS)
  • 13. Macros Summary • Don’t use macros if you can achieve the same thing with a simple function • Macros are useful for implementing DSLs or adding new language features • Use macroexpand to debug macros • Leverage backquote, comma, comma-at for macro readability. • Use gensym to write hygienic macros • Paul Graham’s “On Lisp” is the macro book
  • 15. What is a Metaclass? • In an object orient system the term object refers the domain entities that are being modeled, e.g. a bank-account object. • Programmers have access to these objects • A metaobject refers to the objects the language uses to model/implement your domain objects , e.g. a bank-account-class object • Programmers do not have access to these metaobjects (typically) • Only Language Implementers have access to these metaobjects (typically) • A metaclass is the class of a metaobject
  • 16. Metaobject & Metaclass Example ;; In CLOS define a bank account class > (defclass bank-account () ((account-number)(owner)(balance))) #<STANDARD-CLASS BANK-ACCOUNT> ;; Create a bank account object > (make-instance 'bank-account) #<BANK-ACCOUNT {10029ED253}> ;; The class of the bank account object is a metaobject > (class-of *) #<STANDARD-CLASS BANK-ACCOUNT> ;; The class of this class metaobject is a metaclass > (class-of *) #<STANDARD-CLASS STANDARD-CLASS>
  • 17. Basic CLOS: defclass > (defclass bank-account () ((account-number :initarg :account-number :accessor bank-account-number) (account-balance :initarg :account-balance :accessor bank-account-balance :initform 0))) #<STANDARD-CLASS BANK-ACCOUNT> > (make-instance 'bank-account :account-number 123456789 :account-balance 500) #<BANK-ACCOUNT {1002E20513}> > (describe *) #<BANK-ACCOUNT {1002E20513}> [standard-object] Slots with :INSTANCE allocation: ACCOUNT-NUMBER = 123456789 ACCOUNT-BALANCE = 500 > (bank-account-balance **) 500
  • 18. Basic CLOS: defgeneric & defmethod > (defgeneric PLUS (arg1 arg2)) #<STANDARD-GENERIC-FUNCTION PLUS (0)> > (defmethod PLUS ((arg1 NUMBER)(arg2 NUMBER)) (+ arg1 arg2)) #<STANDARD-METHOD PLUS (NUMBER NUMBER) {100313BFF3}> > (defmethod PLUS ((arg1 STRING)(arg2 STRING)) (concatenate 'string arg1 arg2)) #<STANDARD-METHOD PLUS (STRING STRING) {100319C953}> > (plus 1 2) 3 > (plus "a" ”b”) "ab”
  • 19. AllegroCache: Object Persistence in Lisp • AllegroCache – A high-performance, dynamic object caching database system. • Implements full transaction model with long and short transactions, and meets the classic ACID compliancy and maintains referential integrity. • 64-bit real-time data caching • http://www.franz.com/products/allegrocache/
  • 20. The Persistent-Class Metaclass > (defclass POINT () ((name :reader point-name :index :any-unique) (x :initarg :x :accessor point-x :index :any) (y :initarg :y :accessor point-x :index :any) (rho :accessor point-rho :allocation :instance) (theta :accessor point-theta :allocation :instance)) (:metaclass db.ac::persistent-class)) #<DB.ALLEGROCACHE:PERSISTENT-CLASS POINT> > (setf p1 (make-instance 'point :x 20 :y 30)) Error: Attempt to do a database operation without an open database > (db.ac::open-file-database "C:ProjectstrunkLanguagesMOPDB“ :if-does-not-exist :create) #<AllegroCache db "C:ProjectstrunkLanguagesMOPDB" @ #x218b8942> > (setf p1 (make-instance 'point :x 20 :y 30)) #<POINT oid: 12, ver 5, trans: NIL, modified @ #x2197943a>
  • 21. Instances of a Specialized Metaclass > (describe p1) #<POINT oid: 14, ver 7, trans: NIL, modified @ #x21ad2aba> is an instance of #<DB.ALLEGROCACHE:PERSISTENT-CLASS POINT>: The following slots have :INSTANCE allocation: OID 14 SLOTS #((:UNBOUND) (:UNBOUND) (:UNBOUND)) NEW-SLOTS #(POINT-1 20 30) DCLASS #<DB.ALLEGROCACHE::FILE-DASH-CLASS @ #x219796a2> VERSION 7 PREV-VERSION NIL TRANS NIL MODIFIED :END RHO <unbound> THETA <unbound> The following slots have nonstandard allocation as shown: NAME :PERSISTENT POINT-1 X :PERSISTENT 20 Y :PERSISTENT 30
  • 22. Metaclass • Metaclasses allow you to extend existing language constructs. E.g. defclass • This can be more natural than a DSL or a separate API outside the language • Allow you to safely change or extend the behavior of the language • Metaclasses are a very powerful underutilized programming paradigm. (IMHO)
  • 23. Part III: The Metaobject Protocol
  • 24. Protocol Definitions • An object protocol is a collection of methods that operate on some collection of objects. • A metaobject protocol is a collection of methods that operate on some collection of metaobjects. • A metaclass refers to the class of a metaobject
  • 25. Implementing defclass ;;; All the code on the next few slides is taken from the AMOP book. (defmacro DEFCLASS (name direct-superclasses direct-slots &rest options) `(ensure-class ',name :direct-superclasses ,(canonicalize-direct-superclasses direct-superclasses) :direct-slots ,(canonicalize-direct-slots direct-slots) ,@(canonicalize-defclass-options options) (defun ENSURE-CLASS (name &rest all-keys) (if (find-class name nil) (error "Can't redefine the class named ~S in Closette." name) (let ((class (apply #'make-instance 'standard-class :name name all-keys))) (setf (find-class name) class) class))) (let ((class-table (make-hash-table :test #'eq :size 20))) (defun (SETF FIND-CLASS) (new-value symbol) (setf (gethash symbol class-table) new-value)) )
  • 26. Implementing defclass (cont.) (defclass STANDARD-CLASS () ((name :initarg :name :accessor class-name) (direct-superclasses :initarg :direct-superclasses :accessor class-direct-superclasses) (direct-slots :initarg :direct-slots :accessor class-direct-slots) (class-precedence-list :initarg :class-precedence-list :accessor class-precedence-list) (effective-slots :accessor class-slots) (direct-subclasses :initform () :accessor class-direct-subclasses) (direct-methods :initform () :accessor class-direct-methods)))
  • 27. Implementing defclass (cont.) (defmethod INITIALIZE-INSTANCE :after ((class STANDARD-CLASS) &key direct-superclasses direct-slots) (let ((supers (or direct-superclasses `(,(find-class 'standard-object))))) (setf (class-direct-superclasses class) supers) (dolist (superclass supers) (push class (class-direct-subclasses superclass)))) (let ((slots (mapcar #'(lambda (slot-properties) (apply #'make-direct-slot-definition slot-properties)) direct-slots))) (setf (class-direct-slots class) slots) (dolist (direct-slot slots) (dolist (reader (slot-definition-readers direct-slot)) (add-reader-method class reader (slot-definition-name direct-slot)))) (dolist (direct-slot slots) (dolist (writer (slot-definition-writers direct-slot)) (add-writer-method class writer (slot-definition-name direct-slot))))) (finalize-inheritance))
  • 28. Implementing defclass (cont.) (defun FINALIZE-INHERITANCE (class) (setf (class-precedence-list class)(compute-class-precedence-list)) (setf (class-slots class) (compute-slots class))) (defun COMPUTE-CLASS-PRECEDENCE-LIST (class) (let ((classes-to-order (collect-superclasses* class))) (topological-sort classes-to-order (remove-duplicates (mapappend #'local-precedence-ordering classes-to-order)) #'std-tie-breaker-rule))) (defun COLLECT-SUPERCLASSES* (class) (remove-duplicates (cons class (mapappend #'collect-superclasses* (class-direct-superclasses class)))))
  • 29. Metaobject Protocol Definition • A metaobject protocol is an API that allows you to access and manipulate metaobjects. • “A metaobject protocol is an interface to elements of a language that are normally hidden from users of the language. Providing such an interface allows users of the language to tailor the language to their own needs and in such a way provides a more powerful and flexible language. The CLOS metaobject protocol provides an interface to program elements such as classes and methods, thereby allowing users to control aspects of the language such as how instances of a class are created or how method dispatching works”. Raymond de Lacaze, JLUGM, 2000
  • 30. Introspective vs. Intercessory • AMOP has both introspective and intercessory aspects. • Introspective – Allows programmers to see the on-backstage. Metaobjects can be created, retrieved and examined. • Intercessory – Allows programmers to manipulate the on-backstage thereby affecting the on-stage behavior
  • 31.
  • 32. Example MOP Usage ;; Usage Example 1: An instance-counting metaclass ;; Provide a slot in the metaclass to track number of instances (defclass COUNTED-CLASS (STANDARD-CLASS) ((counter :initform 0))) ;; Then add an :after method on make-instance that bumps count (defmethod MAKE-INSTANCE :after ((class COUNTED-CLASS) &key) (incf (slot-value class) ‘counter))
  • 33. Example MOP Usage (cont.) • Need to define a class with a metaclass other than standard-class. • We can’t use defclass, because as previously written it always uses standard-class as the metaclass (setf (find-class ‘counted-rectangle) (make-instance ‘counted-class :name ‘counted-rectangle :direct-superclasses (list (find-class ‘rectangle)) :direct-slots nil))
  • 34. Extending defclass Implementation ;;; We would like to simply write the following (defclass COUNTED-RECTANGLE (rectangle) () (:meta-class counted-class)) ;; Simply need to extend the definition of ensure-class (defun ENSURE-CLASS (name &rest all-keys &key (metaclass (find-class ‘standard-class))) (if (find-class name nil) (error "Can't redefine the class named ~S in Closette." name) (let ((class (apply #'make-instance metaclass :name name all-keys))) (setf (find-class name) class) class)))
  • 35. Understanding Method Combination > (defclass a ()()) #<STANDARD-CLASS A> > (defclass b (a)()) #<STANDARD-CLASS B> > (defclass c (a b)()) #<STANDARD-CLASS C> a b c • Add primary methods on a, b, c • Add :before method on a, b, c • Add :after method on a, b, c • Add :around methods on a, b, c
  • 36. Adding All Possible Methods (defmethod FOO ((obj A)) (format t "~%Primary method on class A") (call-next-method)) (defmethod FOO ((obj B)) (format t "~%Primary method on class B")) (defmethod FOO ((obj C)) (format t "~%Primary method on class C") (call-next-method)) (defmethod FOO :before ((obj A)) (format t "~%Before method on class A")) (defmethod FOO :before ((obj B)) (format t "~%Before method on class B")) (defmethod FOO :before ((obj C)) (format t "~%Before method on class C")) (defmethod FOO :after ((obj A)) (format t "~%After method on class A")) (defmethod FOO :after ((obj B)) (format t "~%After method on class B")) (defmethod FOO :after ((obj C)) (format t "~%After method on class C")) (defmethod FOO :around ((obj A)) (format t "~%Around method (before) on class A") (call-next-method) (format t "~%Around method (after) on class A")) (defmethod FOO :around ((obj B)) (format t "~%Around method (before) on class B") (call-next-method) (format t "~%Around method (after) on class B")) (defmethod FOO :around ((obj C)) (format t "~%Around method (before) on class C") (call-next-method) (format t "~%Around method (after) on class C")) > (setf x (make-instance 'c)) #<C @ #x209681b2>
  • 37. CLOS Method Combination CL-USER(45): (foo x) Around method (before) on class C Around method (before) on class A Around method (before) on class B Before method on class C Before method on class A Before method on class B Primary method on class C Primary method on class A Primary method on class B After method on class B After method on class A After method on class C Around method (after) on class B Around method (after) on class A Around method (after) on class C NIL
  • 38. Changing Method Combination (defclass a ()()) (defclass b ()()) (defclass c ()()) (defclass s (a b)()) (defclass r (a c)()) (defclass q (r s)()) • Different Lisp object systems used different method combination • How can we reuse code written in Flavors, in CLOS? • We would like to be able to change method combination order Flavors: (q s a b r c standard-object t) Loops: (q s b r a c standard-object t) CLOS: (q s r a b c standard-object t) a b c s r q
  • 39. Compute-Class-Precedence-List • Do not allow programmers to directly set class-precedence-list slot of the class metaobject but. • Allow them to control the computation that is used when that slot I set • Make compute-class-precedence-list a GF and specialize the original function on standard-class • Require that the class be the first in the list and that standard-object and t be the last two. (defclass flavors-class (standard-class) ()) (defmethod compute-class-precedence ((class flavors-class)) (append (remove-duplicates (depth-first-preorder-superclasses* class) :from-end t) (list (find-class ‘standard-object) (find-class ‘t))))
  • 40. Additional AMOP Examples • Adding slot attributes – compute-slots (GF) – compute-effective-slots (GF) • Adding default-initargs – ensure-class – make-instance – finalize-inheritance (GF) • Instance Allocation – allocate-instance (GF) Note: In the examples we’ve seen so far we’ve had to rewrite ensure-class twice
  • 41. Designing a MOP • Design revolves around CLOS metaobjects – Class metaobjects – Method metaobject – Generic function metaobjects – Slot definition metaobjects – Specializer metaobjects – Method combination objects • AMOP is designed to provide an introspective and intercessory API for manipulating and customizing these metaobjects
  • 42. Designing a MOP • Design: MOP should provide mechanisms to extend the syntax and manipulate the behavior of CLOS without: – Needing to rewrite the programmer user interface macros: defclass, defgeneric and defmethod – Needing to rewrite the functions that implement these macros, namely the ensure-x functions and the compute-x functions • Implementation – This is mostly accomplished by making the compute-X functions (on the various metaobjects) generic functions, thus using CLOS to implement the implementation of CLOS. – This approach also provides a level of safety because users of the MOP cannot directly set the values of the slots of the metaobjects, they can only control their computation which is only performed once and cannot subsequently changed.
  • 43. The Final defclass (defmacro DEFCLASS (name direct-superclasses direct-slots &rest options) (let* ((metaclass-option (find ‘:metaclass options :key #’car)) (metaclass-name (or (second metaclass-option) ‘standard-class)) (sample-class-metaobject (allocate-instance (find-class metaclass-name))) (canonical-supers (canonicalize-direct-superclasses direct-superclasses)) (canonical-slots (canonicalize-direct-slots direct-slots)) (canonical-options (canonicalize-defclass-options sample-class-metaobject (remove metaclass-option options)))) `(ensure-class ‘,name :direct-superclasses ,canonical-supers : direct-slots ,canonical-slots :metaclass (find-class ‘,metaclass) ,@canonical-options)))
  • 45. When to use a MOP • Any time you need to alter how a metaobject behaves. For instance, instead of doing a method lookup on a local table, perform an RPC call. • Memoizing method calls • Complex inheritance (this may be of dubious value) • Loosening or strengthening a type system • Implementing Dynamic Dispatch (if necessary) • Persistence • Replication This list is from: http://community.schemewiki.org/?meta-object-protocol
  • 46. Additional Links • http://en.wikipedia.org/wiki/Metaprogramming • https://en.wikipedia.org/wiki/Metaclass • http://en.wikipedia.org/wiki/Metaobject • http://www.dreamsongs.com/CLOS.html • http://www.franz.com/services/conferences_seminars/jlugm00/conference/Talk02_deLacaze1.pdf • http://www.cs.cmu.edu/afs/cs/project/ai-repository/ai/lang/lisp/oop/clos/closette/0.html • http://www.cs.cmu.edu/afs/cs/project/ai-repository/ai/lang/lisp/doc/standard/ansi/mop/ • http://community.schemewiki.org/?meta-object-protocol • http://www.gnu.org/software/guile/manual/html_node/GOOPS.html • http://clojure.org/multimethods
  • 47. Additional Definitions • Dependent Types (Wikipedia) In computer science and logic, a dependent type is a type that depends on a value. Dependent types play a central role in intuitionistic type theory and in the design of functional programming languages like ATS, Agda and Epigram and Idris An example is the type of n-tuples of real numbers. This is a dependent type because the type depends on the value n. • Staged meta-programming (Wikipedia) Incremental compiling of new machine code during runtime. Under certain circumstances, significant speedups are possible using multi-stage programming, because more detailed information about the data to process is available at runtime than at the regular compile time, so the incremental compiler can optimize away many cases of condition checking etc.