I'm trying to find a good OO system for Scheme some days ago. But now
I've thinked the problem over.
Do I really need OOP in Scheme? SICP showed me powerful styles such as
data directed programming and message passing. If I use someone else's
OOP package, I find it hard to fullfill the absolute power of Scheme.
Do people usually use an OOP package to do programming? Which system
allow me to conveniently use data directed programming and has a
flexable type system?
If it does not exist, I don't need it. I'm trying to do it myself :)
--
Wang Yin
Deparment of Computer Science and Technology,
Tsinghua University,
100084
Beijing China
> Hi,
>
> I'm trying to find a good OO system for Scheme some days ago. But now
> I've thinked the problem over.
>
> Do I really need OOP in Scheme?
That's for you to decide.
> SICP showed me powerful styles such as data directed programming and
> message passing. If I use someone else's OOP package, I find it
> hard to fullfill the absolute power of Scheme.
Remember that SICP is a pedagogic book. It shows the concepts behind
many useful paradigms by demonstrating how they work in terms of a
simple underlying model. However, it doesn't suggest that you *use*
the simple model!
The idea behind the SICP section on data directed programming and
message passing is to show the fundamental concept behind
`object-oriented' programming: the idea that you can use the data
itself to tell you how to manipulate the data. The implementation
calls for two elements --- an abstract `generic' interface that can
handle many different types of data and `concrete' implementations of
the various handlers. In addition, there must be a way to determine
which concrete implementation to use on the particular data at the
time.
SICP does this by using lexical closures to capture the data and a
conditional clause to dispatch. This is very easy and elegant and
doesn't require additional language constructs. On the other hand, it
has many drawbacks: there is no way to install the abstract data type
such that the rest of Scheme recognizes it, there is only single
dispatch, there is no reflection mechanism, etc. Adding an
`industrial strength' object system to Scheme would give you those
features. It would presumably offer better performance than the
simply `closure and cond' style object system. (But, as SICP
demonstrates, there will be *somewhere* a mechanism to capture the
data and a mechanism to dispatch.)
> Do people usually use an OOP package to do programming? Which system
> allow me to conveniently use data directed programming and has a
> flexable type system?
I use Swindle in MzScheme.
I believe the CLOS model of generic function calls matches the
functional model of programming the closest. An industrial strength
object system has to have a lot more than abstract datatypes. Besides
integration with the system, need the ability to dynamically change
the type hierarchy, the inheritance, and to dynamically replace
methods (because when you start programming, you don't know what you
are doing and you'll want to change it without recompling the world
each time). CLOS offers these features.
> If it does not exist, I don't need it. I'm trying to do it myself :)
Er, if the code you are writing already exists, you need not write it,
and if it does not exist....
http://www.paulgraham.com/noop.html
and the links on the page.
Regards
Michael Burschik
I thought so when I started programming in Scheme and built an even
cheaper version of YASOS to do it. NNo I'm pretty sure the answer is
no, but I also have embraced a different re-use paradigm (functors).
I'll spare the religious argument about objects, types and re-use to say
that not everyone feels the way I do on this topic. You'll have to
make your own decisions.
david rush
--
He who would make his own liberty secure, must guard even his enemy
from repression
-- Thomas Paine
it is probably approaching a point where I would want to see if I could get
others to work on my project/write "glue" for theirs/... but I don't think
this is going to happen. likely I would have to go and write glue code for
various systems myself, and maybe see if anyone cares...
for mine most of the basic stuff is "in place", so here is the point where
it may start being helpful to include others...
I'm very interested in this paradigm. Would you mind providing a
practical example of reuse by functor in Scheme?
J.E.
You can try the following article from groups.google.com
http://groups.google.com/groups?selm=okf4rdw713f.fsf_-_%40bellsouth.net&output=gplain
which presents the basic idea without any macrology, or the thread
where I attempted to work out the syntactic sugar to make this model
"nicer". Mind you, having worked out the macrology, I've never bothered
to use it because the no-macro implementation just isn't that hard to
use.
Anyway, I'm attaching my implementation of
define-functor/instantiate-functor. Here is a trivial example of their
use.
(define-functor fib (fib0 fib1 fib<= fib+ pred) => (fib)
(define (fib n)
(cond ((fib<= n fib0) fib0)
((fib<= n fib1) fib1)
(else
(let* ((n-1 (pred n))
(n-2 (pred n-1)))
(fib+ (fib n-1) (fib n-2))
)))))
This allows you to compute the fibonacci series with any kind of
bizarre abstract number representation you want. e.g.
(define scheme-integer-fib
(with-functor fib (1 1 <= + (lambda (x) (- x 1))) => (fib)
(lambda (n) (fib n))))
(scheme-integer-fib 5)
returns 8. But you can also do more wild things like:
(define scheme-cons-fib
(with-functor
fib ('(a) '(a)
(lambda (l r) (<= (length l) (length r)))
append
cdr)
=> (fib)
(lambda (n) (fib n))))
(scheme-cons-fib '(a a a a a))
which returns a list whose length is 8. Generalizing this to real
software re-use is an exercise for the reader. I'll just say that I
use this paradigm (although not these macros) on an industrial scale
and I have found that it works pretty well.
david rush
--
He who would make his own liberty secure, must guard even his enemy
from repression
-- Thomas Paine
;;due to Al* Petrofsky
;; (make-setter ((var temp) ...) (var+ ...))
;; expands to: (lambda (temp ... temp+ ...)
;; 'dummy (set! var temp) ... (set! var+ temp+) ...)
;; (The dummy expression is to make the body legal in case there are
;; no vars.) - eliminated because I think that should be an error...
(define-syntax make-setter
(syntax-rules ()
((make-setter ((var temp) ...) (var+ . vars+))
(make-setter ((var temp) ... (var+ temp+)) vars+))
((make-setter ((var temp) ...) ())
(lambda (temp ...) (set! var temp) ...))))
(define-syntax define-functor
(syntax-rules (=>)
((define-functor name (import ...) => (export ...) body ...)
(define (name import ... scope)
body ...
(scope export ...)))
))
(define-syntax instantiate-functor
(syntax-rules (=>)
((instantiate-functor name (import ...) => ((local global) ...))
(begin
(define global '()) ...
(name import ...
(make-setter () (global ...)))))
))
(define-syntax with-functor
(syntax-rules (=>)
((with-functor name (import ...) => (local ...) body ...)
(name import ...
(lambda (local ...)
body ...
)))
))
For anyone looking at this stuff from an OO perspective, it might help to
think about these functors as being similar to a parent or base class in a
class-based OO language. A base class can be thought of as being
parameterized by its subclasses, i.e. the subclasses provide method
implementations which change or extend the behavior of the base class.
From that perspective, the signature of the example David gave:
(define-functor fib (fib0 fib1 fib<= fib+ pred) ...
...indicates that the fib functor is parameterized by 5 values, the latter
three of which must be functions (at least). If you think of 'fib' as a
class, then in this example, these three functions are analogous to abstract
methods for 'fib', for which an implementation must be provided in the
"subclass".
In languages with explicit support for functors, like ML, functors are
actually parameterized by other modules. This is analogous to the use of
multiple interfaces on a class, in languages like Java or C++ (in C++,
interfaces like this can be implemented with multiple inheritance of
abstract classes).
The functor approach has a lot to recommend it, not least of which is a more
straightforward model which doesn't impose as much of a prefabricated world
view on a program's design. The traditional OO view of most
parameterization of behavior as a subclass relationship is kinda weird, once
you notice it. It tends to force all modelling decisions into a choice
between inheritance and composition (is-a vs. has-a), even when neither one
is fully appropriate or relevant.
The above criticism is a little less true of languages that support a
multiple-interface model. On balance, though, it's reasonable to conclude
that most OO languages require inheritance to make up for their lack of
higher-order functions.
Anton