1
votes

Say, I want to implement "declarative" object system in Scheme by defining object symbol and then appending methods and fields to that object. While doing so, I want to exploit the local environment of this object to properly bind it's fields in methods (which are added later), for instance (a very "hacked-together" example):

(define myobj 
(begin
    (define x 5) ; some local field (hard-coded for example)
    (define (dispatch m d)
        (cond ((eq? m 'add-meth) (define localmethod1 d))
              ((eq? m 'inv-meth) (localmethod1 d))))
    dispatch
))
(myobj 'add-meth (lambda (y) (+ y x)) ;want this to bind to x of myobj
(myobj 'inv-meth 3) ;8

Don't mind silly dispatching mechanism and hard-coded "localmethod1" :) Also do mind, that x may not be available during definition of dispatcher. First of all, I get problems with using define in define (Bad define placement).
Then: how to make sure that x in lambda binds to the right one (inside of myobj) and not to some x in global environment?
Last: Is there a way to mutate such local enivornments (closures, right?) at all?

EDIT2: I know that you can make this with local lists like "fields" and "methods" and then mutate those by a dispatcher. I wanted to know if there is a possibility of mutating local environment (produced by a dispatch lambda).

2

2 Answers

3
votes

begin in Scheme does not produce local environment. To introduce local variables use let. Or, alternatively define an object, or rather a class to construct the object, as lambda-procedure, that will act as a constructor. This will solve your first two problems.

To mutate: you can mutate by having a right dispatch method. For example,

(define (make-object init-val)
  (define x init-val)
  (define (dispatch msg)
    (cond ((eq? msg 'inc)
           (lambda (y)
             (set! x (+ x y))))
          ((eq? msg 'x)
           x)
          (else
           (error "Unknown msg"))))
  dispatch)

> (define obj (make-object 10))
> (obj 'x)
10
> ((obj 'inc) 20)
> (obj 'x)
30

SICP, Chapter 3 provides good examples of how to make objects with local state.

1
votes

You are saying:

x may not be available during definition of dispatcher

and then you are asking:

Then: how to make sure that x in lambda binds to the right one (inside of myobj) and not to some x in global environment?

The short answer is: you can't.

The reason is that (see for instance the Mit-Scheme manual):

Scheme is a statically scoped language with block structure. In this respect, it is like Algol and Pascal, and unlike most other dialects of Lisp except for Common Lisp.

The fact that Scheme is statically scoped (rather than dynamically bound) means that the environment that is extended (and becomes current) when a procedure is called is the environment in which the procedure was created (i.e. in which the procedure's defining lambda expression was evaluated), not the environment in which the procedure is called. Because all the other Scheme binding expressions can be expressed in terms of procedures, this determines how all bindings behave.

(emphasis mine)