While a function is a splendid thing, it suffers from excessive terseness. Sometimes we might want multiple functions to all close over to the same shared data; the sharing especially matters if some of the functions mutate it and expect the others to see the result of those mutations. In such cases, it becomes unwieldly to send just a single function as a parameter; it is more useful to send a group of functions. The recipient then needs a way to choose between the different functions in the group. This grouping of functions, and the means to select one from the group, is the essence of an object.
ALERT!
All the code that follows will be in #lang plai, not in the typed language.
10.1.3 Objects as Named Collections
An object is just a value that dispatches on a given name.
(define o-1
(lambda (m)
(case m
[(add1) (lambda (x) (+ x 1))]
[(sub1) (lambda (x) (- x 1))])))
help function
(define (msg o m . a)
(apply (o m) a))
用法:
(msg (lambda () 213))
(msg (lambda (x) x) 1)
(msg (lambda (x y) (+ x y)) 1 2)
后面随意
This enables us to rewrite our test:
(test (msg o-1 'add1 5) 6)
10.1.4 Constructors
A constructor is simply a function that is invoked at object construction time. We currently lack such a function. by turning an object from a literal into a function that takes constructor parameters, we achieve this effect
(define (o-constr-1 x)
(lambda (m)
(case m
[(addX) (lambda (y) (+ x y))])))
(test (msg (o-constr-1 5) 'addX 3) 8)
(test (msg (o-constr-1 2) 'addX 3) 5)
10.1.5 State
Many people believe that objects primarily exist to encapsulate state.
(Alan Kay, who won a Turing Award for inventing Smalltalk and modern object technology, disagrees. In The Early History of Smalltalk, he says, “the small scale [motivation for OOP] was to find a more flexible version of assignment, and then to try to eliminate it altogether”. He adds, “It is unfortunate that much of what is called ‘object-oriented programming’ today is simply old style programming with fancier constructs. Many programs are loaded with ‘assignment-style’ operations now done by more expensive attached procedures.”)
就是说smalltalk发明者说最早整出OOP就是希望能更灵活的进行赋值。从而试图整体上消除它们?个人猜测就是the seasoned schemer 里头 set!只在let里面出现那种感觉么?欢迎评论讨论啊 :D
(define (o-state-1 count)
(lambda (m)
(case m
[(inc) (lambda () (set! count (+ count 1)))]
[(dec) (lambda () (set! count (- count 1)))]
[(get) (lambda () count)])))
(test (let ([o (o-state-1 5)])
(begin (msg o 'inc)
(msg o 'dec)
(msg o 'get)))
5)
(test (let ([o1 (o-state-1 3)]
[o2 (o-state-1 3)])
(begin (msg o1 'inc)
(msg o1 'inc)
(+ (msg o1 'get)
(msg o2 'get))))
(+ 5 3))
10.1.6 Private Members
Another common object language feature is private members: ones that are visible only inside the object, not outside it.we already have the necessary mechanism in the form of locally-scoped, lexically-bound variables:
(define (o-state-2 init)
(let ([count init])
(lambda (m)
(case m
[(inc) (lambda () (set! count (+ count 1)))]
[(dec) (lambda () (set! count (- count 1)))]
[(get) (lambda () count)]))))
The desugaring above provides no means for accessing count, and lexical scoping ensures that it remains hidden to the world.
10.1.7 Static Members
Another feature often valuable to users of objects is static members: those that are
common to all instances of the “same” type of object. This, however, is merely a lexically-scoped identifier (making it private) that lives outside the constructor (making it common to all uses of the constructor):
(define o-static-1
(let ([counter 0])
(lambda (amount)
(begin
(set! counter (+ 1 counter))
(lambda (m)
(case m
[(inc) (lambda (n) (set! amount (+ amount n)))]
[(dec) (lambda (n) (set! amount (- amount n)))]
[(get) (lambda () amount)]
[(count) (lambda () counter)]))))))
(test (let ([o (o-static-1 1000)])
(msg o 'count))
1)
(test (let ([o (o-static-1 0)])
(msg o 'count))
2)
10.1.8 Objects with Self-Reference
Until now, our objects have simply been packages of named functions: functions with multiple named entry-points, if you will. We’ve seen that many of the features considered important in object systems are actually simple patterns over functions and scope, and have indeed been used—without names assigned to them—for decades by programmers armed with lambda.
One characteristic that actually distinguishes object systems is that each object is automatically equipped with a reference to the same object, often called self or this.
Self-Reference Using Mutation
(define o-self!
(let ([self 'dummy])
(begin
(set! self
(lambda (m)
(case m
[(first) (lambda (x) (msg self 'second (+ x 1)))]
[(second) (lambda (x) (+ x 1))])))
self)))
(test (msg o-self! 'first 5) 7)
Observe that this is precisely the recursion pattern(section9.2), adapted slightly. We’ve tested it having first send a method to its own second.
10.1.9 Dynamic Dispatch
The ability to invoke a method without the caller having to know or decide which object will handle the invocation.
Suppose we have a binary tree data structure, where a tree consists of either empty nodes or leaves that hold a value.
In traditional functions, we are forced to implement the equivalent some
form of conditional—either a cond or a type-case or pattern-match or other moral equivalent—that exhaustively lists and selects between the different kinds of trees.If the definition of a tree grows to include new kinds of trees, each of these code fragments must be modified.
Dynamic dispatch solves this problem by making that conditional branch disappear from the user’s program and instead be handled by the method selection code built into the language. The key feature that this provides is an extensible conditional. This is one dimension of the extensibility that objects provide.
(然后作者在边注里又展开了一下。While this is indeed an advantage objects have over functions, there is a dual advantage that functions have over objects, and indeed many object programmers end up contorting their code—using the Visitor pattern—to make it look more like a function-based organization. )
还给了两篇论文当引申阅读。。。这个我还没看。只能说这章坑好大 = =!
http://www.cs.rochester.edu/~cding/Teaching/254Fall2001/Assignments/tr98-299.pdf
http://www.cs.utah.edu/plt/publications/icfp98-ff/paper.shtml
(define (mt)
(let ([self 'dummy])
(begin
(set! self
(lambda (m)
(case m
[(add) (lambda () 0)])))
self)))
(define (node v l r)
(let ([self 'dummy])
(begin
(set! self
(lambda (m)
(case m
[(add) (lambda () (+ v
(msg l 'add)
(msg r 'add)))])))
self)))
(define a-tree
(node 10
(node 5 (mt) (mt))
(node 15 (node 6 (mt) (mt)) (mt))))
(test (msg a-tree 'add) (+ 10 5 15 6))
网友评论