[comp.lang.scheme] modularization & large scheme programs

alex@umbc4.umbc.edu (Alex S. Crain) (03/04/91)

Newsgroups: comp.lang.scheme
Subject: modularization of scheme code
Summary: 
Expires: 
Sender: 
Reply-To: alex@umbc4.umbc.edu.UUCP (Alex S. Crain)
Followup-To: 
Distribution: world
Organization: University of Maryland Baltimore County
Keywords: 

	I'm laying out a rather large project (an operation system) in
scheme and I'm looking for a way to restrict the scope of some objects.
In C++ or CLOS, I would use objects and methods, in vinnilla CL I would
use packages. I can't find a good way to do this in scheme.

	For example: suppose I was writing window system, and I had written
a module for screen management. I would have some local data objects
(like the screen data and backing store data (after securing the appropriate
patent licence from AT&T, of course). I would also have some local functions
and finally, I would have some exported functionality (create-window, etc).

	I would rather not make my locally used functions and data structures
public if I don't have to, both to avoid cluttering the namespace and just
for general neatness. Scheme doesn't provide a way (that I know of) of
hiding anything except by nesting itside a function, and even if I
wrapped the entire module inside of letrec body I don't know how to make
the date structures permentent, and I only get one entry point (yuk).

	Or should I build everything dynamically and export a series of
continuations to use as entry points, ala:

(define (init-screen non-local-exit)
  (letrec ((screen-data (make-vector ...))
	   (entry-points '(()))
	   ...
	   )
    ;;
    ;; define the new entry points
    ;;
    (let ((x (call/cc (lambda (k) (cons 'init k)))))
      (case (car x)
	((init) (set-car! entry-points (cdr x)))
	((create-window) ...)
	((delete-window) ...)
	...))

    (non-local-exit entry-points)))
	
	
(define (go)
  (let ((screen-calls (call/cc (lambda (k) (init-screen k)))))

    ...
    
    (screen-calls 'create-window)

    ...

    (screen-calls 'delete-window)))



So, pray tell, whats to scoop? I'm working out of R3.99rs, so if this is
crystal clear in 4.0, just say so.
#################################		           :alex.
#Disclaimer: Anyone who agrees  #                 Systems Programmer
#with me deserves what they get.#    University of Maryland Baltimore County
#################################	    alex@umbc3.umbc.edu

gyro@cymbal.reasoning.COM (Scott Layson Burson) (03/05/91)

   Date: 3 Mar 91 20:28:48 GMT
   From: "Alex S. Crain" <alex@umbc4.umbc.edu>

	   I'm laying out a rather large project (an operation system) in
   scheme and I'm looking for a way to restrict the scope of some objects.
   In C++ or CLOS, I would use objects and methods, in vinnilla CL I would
   use packages. I can't find a good way to do this in scheme.

A simple solution is to prepend a "package prefix" to each of your
global symbols.  The disadvantage of this approach vis-a-vis CL packages
is that you must always include the "package prefix" when naming a
symbol; there is no concept of a "current package" in the context of
which the prefix may be omitted from symbols in that package.

That may sound distasteful, but I have used this approach in Lisps
without packages and found it workable.

If you really want objects that behave like instances, here is an
approach I have used in CL without CLOS:

;;; Do we have DEFSTRUCT in Scheme?  Anyhow, you get the idea.
(defstruct window
  ;; The slots are the operations, not the instance variables.
  expose
  move
  reshape
  ...)

(define (create-window left bottom width height ...)
  (let (... other instance variables ...)
    (letrec ((expose (lambda () ...))
	     (move (lambda (new-left new-bottom) ...))
	     ... other operations ...)
      ;; Now we build an instance of the WINDOW structure using EXPOSE etc.
      (make-window expose move reshape ...))))

Here the instance variables are the arguments to CREATE-WINDOW along
with any local variables bound in the LET.  As you see, they are not
accessible to the outside except by way of the operations you define.

Now to invoke the MOVE operation on WIN: ((window-move win) x y)

Note that this uses closures, but not continuations.

-- Scott