OOP and classes, Was: OOP & Functional Languages 
Author Message
 OOP and classes, Was: OOP & Functional Languages

Quote:


> > Calling run-time assignment of function values 'just linking' is
> > rather odd.  The languages I mentioned allow the bindings to vary,
> > so not only may different _objects_ have different values for the
> > same function slots, _one_ object may have different values at
> > different times.

> I still don't think this qualifies as "dispatch".  It's just
> a data structure some of whose members are functions.  To find
> the function you read a known offset in the data structure.
> If you're going to write a routine that operates on multiple
> data structures they've all got to have the same offset.

But you could easily implement a message-passing, class-based object
system by making every instance of a class a structure containing the
instance variables and a field for every member function of the class.
Here is some code in Scheme:

The method `class' defines a new class with superclasses from the
given list, and additional slots and methods.

(define (class name superclasses slots methods)
  (if (null? superclasses)
      (make-class-constructor name slots (remove-duplicates methods))
      (class name
             (cdr superclasses)
             (append slots (get-all-slots (car superclasses)))
             (append methods (get-all-methods (car superclasses))))))

Here come some utility functions:

(define (remove-duplicates methods)
  (letrec ((delete-proc (delete-member-procedure
                         list-deletor
                         (lambda (lhs rhs)
                           (eqv? (car lhs) (car rhs)))))
           (rem-dup (lambda (meth acc)
                      (if (null? meth)
                          acc
                          (rem-dup (delete-proc (car meth)
                                                (cdr meth))
                                   (cons (car meth) acc))))))
    (rem-dup methods ())))

(define (make-class-constructor name slots methods)
  (let* ((method-field-names (map car methods))
         (all-fields (append slots method-field-names))
         (class-type (make-record-type name all-fields))
         (tmp-constructor (record-constructor class-type slots)))
    (list (lambda (args)
            (let ((instance (apply tmp-constructor args)))
              (set-methods instance class-type methods)
              (list instance class-type)))
          slots methods)))

(define (get-all-slots class) (second class))
(define (get-all-methods class) (third class))

(define (set-methods class-instance class-type methods)
  (map (lambda (method)
         (let ((set-meth (record-modifier class-type (car method))))
           (set-meth class-instance (cadr method))))
       methods))

The function `make-instance' creates an instance of a class, that is,
an object.

(define (make-instance class . args)
  (apply (car class) args))

`get-slot' retrieves the value stored in a slot, `set-slot' writes
it.

(define (get-slot object slot-name)
  ((record-accessor (cadr object) slot-name) (car object)))

(define (set-slot object slot-name value)
  ((record-modifier (cadr object) slot-name) (car object) value))

`call' is the function to send messages to an object.

(define (call object method . args)
  (let ((self-method (get-slot object method)))
    (apply self-method object args)))

;; An example

(define foo (class "foo" () '(s1 s2)
                   (list (list 'm1 (lambda (self)
                                     (+ (get-slot self 's1)
                                        (get-slot self 's2))))
                         (list 'm2 (lambda (self) "foo")))))

(define bar (class "bar" (list foo) '(s3)
                   (list (list 'm2 (lambda (self) "bar"))
                         (list 'm3 (lambda (self)
                                     (+ (get-slot self 's1)
                                        (get-slot self 's2)
                                        (get-slot self 's3)))))))
(define test (class "test!" () '(t1)
                    (list (list 'n1 (lambda (self n)
                                      (list "arg: " n)))
                          (list 'm2 (lambda (self) "test")))))

(define test-bar (class "test-bar" (list test bar) () ()))

(define foo-inst-1 (make-instance foo '(1 2)))
(define foo-inst-2 (make-instance foo '(7 9)))
(define bar-inst-1 (make-instance bar '(10 11 12)))
(define test-bar-inst-1 (make-instance test-bar '(99 10 11 12)))

(newline)
(display (list (call foo-inst-1 'm1)
               (call foo-inst-1 'm2)))
(newline)
(display (list (call foo-inst-2 'm1)
               (call foo-inst-2 'm2)))
(newline)
(display (list (call bar-inst-1 'm1)
               (call bar-inst-1 'm2)
               (call bar-inst-1 'm3)))
(newline)
(display (list (call test-bar-inst-1 'm1)
               (call test-bar-inst-1 'm2)
               (call test-bar-inst-1 'm3)
               (call test-bar-inst-1 'n1 5)))

Here is the output from MIT Scheme:

1 ]=> (load "/home/tc/prog/scheme/tests/object.scm")

;Loading "/home/tc/prog/scheme/tests/object.scm"
(3 foo)
(16 foo)
(23 bar 33)
(23 test 33 (arg:  5)) -- done
;Unspecified return value

This looks pretty much like the result you'd expect from an object
oriented language.  But still, if you kept track of the order in which
you inherit fields and methods and implemented the functions to
construct and access records accordingly, all sends invoking the same
message would access the same offset.  Of course this is no longer
possible if you use multiple superclasses.

Quote:
> > >Surely as a piece of modern terminology, OOP implies classes,
> > >inheritance and subsumption?

What exactly is non-OOP about the following code?

concrete object foo;


concrete object bar isa foo;

foo.print;
bar.print;
foo.value := 4;
bar.value := 5;
foo.print;
bar.print;

Here's the output:

foo 1                  
bar 1
foo 4
bar 5

The type `bar' is a subtype of the type `foo', the representation
`bar' inherits its methods and fields from `foo', but methods can be
specialized on `bar', etc.  In other words: Inheritance, subtype
polymorphism, but no classes.

  Matthias

P.S. I've set followups to comp.lang.misc since the topic is
     no longer relevant to comp.functional.



Tue, 29 Feb 2000 03:00:00 GMT  
 
 [ 1 post ] 

 Relevant Pages 

1. OOP & Functional Languages

2. DBC in functional languages [Was: comparison OOP and FP]

3. OOP in functional languages

4. Functional Language Vs OOP

5. OOP Methodology and OOP Tools

6. OOP - Class(y) - Table and Record classes

7. Clarion 100% OOP? 70% OOP? 37.9% OOP?

8. OOP question: how to call a method from a specific record of a QUEUE with CLASSes

9. Better OOP, Part 6 -- Using ABC (and Legacy) file access in classes

10. oop deriving control class

11. CLASS,EXP and OOP

12. Intro class in oop...

 

 
Powered by phpBB® Forum Software