views:

169

answers:

4

Now I research OOP-part of Scheme. I can define class in Scheme like this:

(define (create-queue)
  (let ((mpty #t) 
        (the-list '()))

    (define (enque value)
      (set! the-list (append the-list (list value)))
      (set! mpty #f)
      the-list)

    (define (deque)
      (set! the-list (cdr the-list))
      (if (= (length the-list) 0) 
      (set! mpty #t))
      the-list)

    (define (isEmpty)
      mpty)

    (define (ptl)
      the-list)

    (define (dispatch method)
      (cond ((eq? method 'enque) enque)
        ((eq? method 'deque) deque)
        ((eq? method 'isEmpty) isEmpty)
        ((eq? method 'print) ptl)))

    dispatch))

(Example from css.freetonik.com)

Can I implement class inheritance in Scheme?

+6  A: 

Well, I wouldn't call that a class, but that's just me. That's simply closures and raw scheme.

Scheme itself does not have an object system. However, Scheme is capable of implementing a class system.

If you would like to use an oop system, there are several written for Scheme that you can try.

Here is a link that lists several, there are certainly others.

Will Hartung
+1 I wouldn't call that a class, either.
anthares
Those "OOP" systems are implemented with closures, raw Scheme and macros for readability. CLOS is implemented this way too. They are no less "a class" because of it. That's the beauty of the Lisp family.Of course, you could always argue that his implementation is incomplete and that he's lacking <insert your favourite OO feature here>.
Stephen Eilert
+2  A: 

You certainly can implement inheritance in Scheme, if you decide that you do want to roll your own OOP system. One way of doing so is to close over an instance of the desired superclass which is "constructed" when you make the instance of the derived class, and have an extra clause in the dispatch procedure, something like

(define (make-superclass-instance) 
  (define (method-a)
    (display "a!"))

  (define (method-b)
    (display "b!"))

  (define (dispatch message)
    (case message
      ((a) (method-a))
      ((b) (method-b))
      (else (error "nonexistent method"))))

  dispatch)

  (define (make-class-instance)
    (let ((super (make-superclass-instance)))
      (define (method-c)
        (display "c!"))

      (define (method-a)
        (display "overridden a!"))

      (define (dispatch message)
        (case message
          ((c) (method-c))
          ((a) (method-a))
          (else (super message))))

      dispatch))

This also allows easy overriding of methods, as shown in the example.

Of course, this is pretty tedious, and involves plenty of boilerplate. You could make it more pleasant with macros, but if you're interested in actually doing OOP in Scheme instead of experimenting as a learning exercise, I second Will Hartung's suggestion to use one of the many existing object systems for Scheme.

Pillsy
+1  A: 

OOP languages use inheritance to simulate polymorphism, i.e to create a class of objects that can respond to a published list of messages. You can have polymorphism in Scheme without explicit inheritance because it is a dynamically typed language. Compare the implementation of an "Animal" class in Java and its corresponding implementation in Scheme:

// Animal interface and implementations in Java

interface Animal {
    void cry (); // The only message to which an Animal object will respond.
}

class Cat implements Animal {
    void cry () {
        System.out.println ("meow!");
    }
}

class Cow implements Animal {
    void cry () {
        System.out.println ("baee!");
    }
}

// Usage

Animal a = new Cat ();
Animal b = new Cow ();
a.cry (); => "meow!"
b.cry (); => "baee!"

Now the corresponding implementation in Scheme using closures:

;; A factory of Animals.
(define (animal type)
  (case type
    ((cat) (cat))
    ((cow) (cow))))

;; Corresponds to class Cat in Java.
(define (cat)
  (lambda (msg)
    (case msg
      ((cry) "meow!"))))

;; Corresponds to class Cow in Java.
(define (cow)
  (lambda (msg)
    (case msg
      ((cry) "baee!"))))

;; Sample usage

(define a (animal 'cat))
(define b (animal 'cow))
(a 'cry) => "meow!"
(b 'cry) => "baee!"

In fact we need closures only if we have to deal with too much private state. Scheme provide many ways to simulate simple "class hierarchies" like the above. Here is one method in which we develop a tiny "message dispatching" facility which we can use on a list of objects:

;; Generic message dispatch.
(define (send type message objects)
    ((cdr (assq message (cdr (assq type objects))))))

;; A list of animals.
(define animals (list (cons 'cat (list (cons 'cry (lambda () "meow!"))))
                   (cons 'cow (list (cons 'cry (lambda () "blaee!"))))))

;; Send a specific message to a specific animal:
(send 'cat 'cry animals) => "meow!"
(send 'cow 'cry animals) => "blaee!"

The functional abstraction mechanisms provided by Scheme is powerful enough to make us not worry about a full object system. Still, there are some object systems for Scheme. Have a look at Tiny-CLOS (based on CLOS). The book Lisp in Small Pieces discuss an implementation of an Object System for Scheme (based on Meroon).

Vijay Mathew
A: 

There's a pretty fully-developed class system in PLT Scheme:

http://docs.plt-scheme.org/guide/classes.html

David Brooks