Sorry, I said I'd include an example of actives in my previous message, then forgot to include it.

Kjell Godo wrote:
An active variable is a variable that expands when it is referenced or
assigned to.  Now where would that be useful?  Any examples?
I didn't explain it well, see below for another attempt, and some examples.

What happens to the value of the variable when this expansion takes place?
Is code what goes into the variable on a reference?

I think I answer these two question below.

Is this like in Scheme where variables can contain functions?
No, though Coke/Jolt variables are exactly like Scheme variables in this respect.

Can you give an example of how active variables are defined and used?
Or a link.

I looked up active variable but didn't get anything.

Actives are not documented in the main coke paper (ie. http://piumarta.com/software/cola/coke.html). I found them while exploring the implementation of jolt, in Compiler.st. In trying to understand how actives work, it's useful to know how Coke/Jolt syntax's (for lack of a better name) work. Syntax's _are_ documented in that paper, and there are working examples in the file syntax.k in the jolt implementation. It is also helpful to understand how backquote works. Backquote is also documented in that paper.

Syntax's are function-like in the sense that they only get expanded when the appear at the front of a list. So if we define a bit of syntax like:

  (syntax begin
    (lambda (node compiler)
      `(let () ,@[node copyFrom: '1])))

We can only use "begin" in the places where function call can go (at the beginning of a form):

  (begin
      (printf "%d" 10)
      (printf "and %d\n" 20)
      )

Putting "begin" someplace else will result in "undefined: trans:begin" error.

Actives, on the other hand, are variable-like in that can be placed anywhere variables can be placed.

Actives are defined with an "active" special form.  For example:

 (active A
   (lambda (name compiler) 'DUMMY)
   (lambda (name compiler) '(addrof DUMMY))
   )

 (define DUMMY 0)

 (set A 100)
 (printf "%d\n" A)
 ; prints: 100

 (set A 4)
 (printf "%d\n" A)
 ; prints: 4

This (not very useful) active special form creates an active "A" which simply defines a wrapper around "DUMMY". That is, assigments to A are assignments to DUMMY, reads from A are reads from DUMMY.

The active special form takes one or two lambdas (functions) as arguments.

The _second_ lambda is called (at compile time) when the active is the target of a set special form. It is called with the name of the active and the current compiler, and it must return an expression who's result after evaluation is the address of the memory location that the set special form will change. If the active special form doesn't have a second lambda, the active can't be used as the target of a set (it's read only).

The _first_ lamba is called (at compile time) when the active is used in any other place (is read/fetched from). It is also called with the name of the active and the current compiler, but it must return an expression whose value is used as the value of the active.

This next example is the same as the last with two printf's stuck into each lambda to see when each lambda is executed, and when the code returned by each lambda is executed:

(active B
 (lambda (name compiler)
    (begin
(printf "compile time read of %s\n" [[name printString] _stringValue])
      `(begin
(printf "exec time read of %s\n" [[(quote ,name) printString] _stringValue])
        DUMMY)))
 (lambda (name compiler)
    (begin
      (printf "compile time set of %s\n" [[name printString] _stringValue])
      `(begin
(printf "exec time set of %s\n" [[(quote ,name) printString] _stringValue])
        (addrof DUMMY))))
  )


(set B 100)
; prints: compile time set of #B
; and prints: exec time set of #B
(printf "%d\n" B)
; prints: compile time read of #B
; and prints: exec time read of #B
; and prints: 100

(set B 4)
; etc
(printf "%d\n" B)
; etc




It's important to understant that these printf can be arbitrary code, code which examines the current compiler, perhaps makes changes to it, allocates memory, what ever. The following example creates "variables" in malloc'ed memory, keeps track of this memory in a dictionary, and uses an active to make the "variables" look like regular variables to the rest of the code:

(define IdentityDictionary (import "IdentityDictionary"))
(define DICT [IdentityDictionary new])

[DICT at: 'A put: (malloc 4)]
(active A
  (lambda (name compiler) '(long@ [DICT at: 'A]))
  (lambda (name compiler) '[DICT at: 'A])
  )
(set A 100)

[DICT at: 'B put: (malloc 4)]
(active B
  (lambda (name compiler) '(long@ [DICT at: 'B]))
  (lambda (name compiler) '[DICT at: 'B])
  )
(set B 200)

(printf "A in DICT=%d\n" A)
(printf "B in DICT=%d\n" B)

(set A 40)
(set B 50)
(printf "A in DICT=%d\n" A)
(printf "B in DICT=%d\n" B)


This final example wraps the previous example up in a new syntax, so that createing variables in malloc'ed memory is as simple as creating normal variables:



(define DICT [IdentityDictionary new])
(syntax define-in-DICT
  (lambda (node compiler)
     (let ((active-name [node second])
           (initial-value-expr [node third]))
       `(all
           [DICT at: (quote ,active-name) put: (malloc 4)]
           (active ,active-name
(lambda (name compiler) '(long@ [DICT at: (quote ,active-name)]))
             (lambda (name compiler) '[DICT at: (quote ,active-name)])
             )
           (set ,active-name ,initial-value-expr)
           )
         )))

;; all -- begin without creating a new scope
;; (not the best implementation) (define _all
 (lambda (node idx)
   (if [idx >= [node size]]
   `()
   `((or ,[node at: idx] 1)
         ,@(_all node [idx + '1])))))

(syntax all
 (lambda (node compiler)
   `(and ,@(_all node '1))))



(define-in-DICT A 100)
(define-in-DICT B 200)

(printf "%d\n" A)
(printf "%d\n" B)

(set A 40)
(set B 50)
(printf "%d\n" A)
(printf "%d\n" B)

Hope this is helpfull.


-gavin...


_______________________________________________
fonc mailing list
[email protected]
http://vpri.org/mailman/listinfo/fonc

Reply via email to