views:

125

answers:

2

I will use a simple example to illustrate my question. In Java, C, or any other OOP language, I could create a pie class in a way similar to this:

class Apple{
    public String flavor;
    public int pieces;
    private int tastiness;
    public goodness(){
        return tastiness*pieces;
    }
}

What's the best way to do that with Scheme? I suppose I could do with something like this:

(define make-pie
  (lambda (flavor pieces tastiness)
    (list flavor pieces tastiness)))

(define pie-goodness
  (lambda (pie)
    (* (list-ref pie 1) (list-ref pie 2))))

(pie-goodness (make-pie 'cherry 2 5))

;output: 10

...where cherry is the flavor, 2 is the pieces, and 5 is the tastiness. However then there's no type-safety or visibility, and everything's just shoved in an unlabeled list. How can I improve that?

Sidenote: The make-pie procedure expects 3 arguments. If I want to make some of them optional (like I'd be able to in curly-brace languages like Java or C), is it good practice to just take the arguments in as a list (that is treat the arguments as a list - not require one argument which is a list) and deal with them that way?


Update:

I've received a couple answers with links to various extensions/libraries that can satisfy my hunger for OOP in scheme. That is helpful, so thank you.

However although I may not have communicated it well, I'm also wondering what the best way is to implement the pie object above without such classes or libraries, so I can gain a better understanding of scheme best practices.

+5  A: 

In some sense, closures and objects are equivalent, so it's certainly possible. There are a heaping helping of different OO systems for Scheme -- a better question might be which one to use!

On the other hand, if this is an educational exercise, you could even roll your own using the closure-object equivalency. (Please forgive any errors, my Scheme is rather rusty.)

(define (make-pie flavor pieces tastiness)
        (lambda (selector)
                (cond ((eqv? selector 'flavor) flavor)
                      ((eqv? selector 'pieces) pieces)
                      ((eqv? selector 'tastiness) tastiness)
                      ((eqv? selector 'goodness) (* pieces tastiness))
                      (else '()))))

This is a simple constructor for a pie object. The parameter variables flavor, pieces and tastiness are closed over by the lambda expression, becoming fields of the object, and the first (and for simplicity's sake here, only) argument to the closure is the method selector.

That done, you can instantiate and poke at some:

> (define pie1 (make-pie "rhubarb" 8 4))
> (define pie2 (make-pie "pumpkin" 6 7))
> (pie1 'flavor)
"rhubarb"
> (pie1 'goodness)
32
> (pie2 'flavor)
"pumpkin"
Jeffrey Hantin
Alright. Which one do I use? :)
Cam
Aack! The C#/Java oriented syntax highlighting makes a royal hash of Scheme code.I've put together an example of a simple way to do it yourself here; which OO system you should be using will be primarily driven by either your requirements or, more likely, what is available for your chosen Scheme implementation.
Jeffrey Hantin
@Jerffrey's edit: Nice! Is it considered good practice to use that technique (especially for methods)? And yeah the syntax highlighting is pretty brutal for scheme - it would probably help to use `quote` instead of `'`, but I suppose that's a bit verbose.
Cam
+2  A: 

Many Schemes allow you to define classes that contain fields and methods. For example, see:

Justin Ethier
Thanks. I've updated my question to further specify what it is I'm looking for. Those links (the second one in particular) look interesting, but I'm also wondering how `pie` would be implemented without those things - I'm new to scheme and would like to learn some of the best practices early on. For example would I just keep the values in a list like that?
Cam