AspectScheme - Aspects in Higher-Order Languages

AspectScheme - Aspects in Higher-Order Languages

Version 2, 31 January 2006,`'
by Christopher Dutchyn <>

     Copyright (C) 2005-6 Christopher Dutchyn.  This program is Free
     Software; you can redistribute it and/or modify it under the
     terms of the GNU Lesser General Public License as published by
     the Free Software Foundation; either version 2.1 of the License,
     or (at your option) any later version.  This program is
     distributed in the hope that it will be useful, but without any
     warranty; without even the implied warranty of merchantability or
     fitness for a particular purpose.  See the GNU Lesser General
     Public License [LGPL] for details.  For other license options and
     commercial consulting, contact the author.


AspectScheme is an implementation of the Scheme programmng language
[R5RS] built on MzScheme [MZSCHEME], providing support for pointcuts
and advice aspect-oriented programming.  In order to use it, place
    (require (planet "" ("cdutchyn" "aspect-scheme.plt" 2 1)))
in your code, before using any AspectScheme features.

   AspectScheme is a lightweight language, constructed using the
continuation marks [STEPPER] and macro facilities offered by MzScheme.
It recognizes join points as procedure applications, within a context
of in-progress join points.  These join points in context are
recognized by pointcuts -- predicates over the join point and context
(represented as a list of join points).  When a pointcut matches,
advice transforms the join point into a new procedure.  Aspects,
consisting of a pointcut and an advice are introduced by the around
and fluid-around constructs:

    (around <pc> <adv>              (fluid-around <pc> <adv>
      <body>...)                      <body>...)

which differ in the scoping of the aspect application.  Static aspects
(around) apply only to join points present lexically within the body.
Dynamic aspects apply to join points that are present dynamically
within the execution of the body.

  Users should be aware that advice that breaks tail-call properties
will cause stack growth. Pointcuts can also break tail-call properties
by forcing continuations to be marked in order to preserve calling
context.  We adopt a simple approach to continuation marks, and hence
advised code may not remain tail-call optimization.

  Predefined pointcuts include: call    within
                                top     below
                                &&      ||     !
                                cflow   cflowbelow.

  For usage examples, please see  For more details,
please refer to the paper `Aspects in Higher-Order Languages' [AHOL],
or its precursor, `Pointcuts and Advice in Higher-Order Languages'
[PAHOL].  But, beware, this is an extended implementation, where pointcuts
are expected to return arguments from the matches.

  ;; Join Point
  ;;                proc           args
  ;; jp ::= call-jp a->b             a	;; procedure application ('a' can be values (ie. tuple {...})
  ;;     |  exec-jp a->b             a	;; procedure execution (cannot be advised only matched)
                                        ;; AspectJ matches and transforms dispatches and calls,
                                        ;; but not executions.  To wit, AspectJ chooses poor names
                                        ;; (dispatch == `call', call == `execution').
  ;;     |  adv-jp  (a->b)->c->a->b  c	;; advice execution ... 'c' can be values as well

  ;; Pointcuts
  ;; pc :: {[jp]*jp*[jp]}->c		;; above * jp * below

  ;; combinators    (&& pc ...)   -- return all arguments in order
  ;;                (|| pc ...)   -- return first match arguments
  ;;                (! pc)
  ;; control-flow testing   top?  bottom?          -- true/false
  ;;                        top below above bottom -- return matching pc's arguments
  ;;                        cflowtop cflowbelow cflowbottom cflowabove
  ;;                        cflow within
  ;; value accessing        target
  ;;                        args
  ;;                        some-args        -- used for masking out certain arguments
  ;; kind testing           call? exec? adv? -- true/false
  ;;                        call exec adv    -- also provides arguments 

  ;; Advices
  ;; adv :: (a->b)->c->a->b   -- procedure transformers
  ;; Aspects
  ;; aspect ::=    fluid-around pc adv body  ;; dynamic scoping
  ;;         |           around pc adv body  ;; lexical scoping
  ;;         |  toplevel-around pc adv       ;; top-level scoping (i.e. body is rest of repl)

  ;; Other kinds of advice (before, after) are special cases; using them might inform a type-
  ;; checker and enable it to recognize behaviour as extensional rather than superpositional.
  ;; (before pc                       | (around pc
  ;;                                  |         (lambda (proceed)
  ;;         (lambda ctxt             |           (lambda ctxt
  ;;           (lambda args           |             (lambda args
  ;;             ...adv-body...))     |               ...adv-body...
  ;;                                  |               (proceed args))))
  ;;   body)                          |   body)

  ;; (after pc                        | (around pc
  ;;                                  |         (lambda (proceed)
  ;;        (lambda ctxt              |           (lambda ctxt
  ;;          (lambda args            |             (lambda args
  ;;                                  |               (let-values ([r (with-handlers ([(lambda (x) #t)
  ;;                                  |                                               (lambda (x) adv-body
  ;;                                  |                                                            raise x)])
  ;;                                  |                                 (proceed args)])
  ;;            adv-body))            |                 adv-body
  ;;                                  |                 (values r)))))
  ;;   body)                          |   body)

  ;; (after-throwing pc               | (around pc
  ;;                                  |         (lambda (proceed)
  ;;                 (lambda ctxt     |           (lambda ctxt
  ;;                   (lambda args   |             (lambda args
  ;;                                  |               (with-handlers ([(lambda (x) #t)
  ;;                     adv-body))   |                                (lambda (x) adv-body
  ;;                                  |                                            raise x)])
  ;;                                  |                 (proceed args)))))
  ;;   body)                          |   body)

  ;; (after-returning pc              | (around pc
  ;;                                  |         (lambda (proceed)
  ;;                  (lambda ctxt    |           (lambda ctxt
  ;;                    (lambda args  |             (lambda args
  ;;                                  |               (let-values ([r (proceed args)])
  ;;            adv-body))            |                 adv-body
  ;;                                  |                 (values r)))))
  ;;   body)                          |   body)


  The papers use `jp' as the parameter to advice, `proceed' is more
common in aspect-oriented programming.


This implementation differs slightly from the submitted paper [AHOL];
we expect to update the paper to this version upon review and
acceptance.  The differences are simplifications and clarifications,
as itemized at the commentary introducing

  A much-extended version (v2), supporting

    * access to context values
    * call / execution / advice join points
    * above, cflowabove, etc.
    * proper tail-call behaviour (as permitted by advice and pointcuts)

comprises this release.

  We also include an extended version of let/let*/letrec that accepts
the MIT-style curried lambdas, just like define.  This makes advice
much easier to write:  it looks like
(let ([(((adv proceed) context values ...) arguments) body...])
  (around ...
This was shamelessly appropriated from Eli Barzilay's swindle/


     D. Tucker, S. Krishnamurthi, C. Dutchyn, Aspects in Higher-Order
     Languages, accepted to Science of Computer Programming, 2006.

     The AspectSandbox, University of British Columbia, 2003.

     Free Software Foundation, "GNU Lesser General Public License,"
     Version 2.1, February 1999, 59 Temple Place, Suite 330, Boston,
     02111-1307 USA.

     M. Flatt, PLT MzScheme: Language Manual, TR97-280, Rice
     University, 1997.

     D. Tucker, S. Krishnamurthi, Pointcuts and Advice in Higher-Order
     Languages, AOSD 2003.

     R. Kelsey, W. Clinger, J. Rees (eds.), Revised5 Report on the
     Algorithmic Language Scheme, Higher-Order and Symbolic Computation,
     Vol. 11, No. 1, August, 1998.

     J. Clements, M. Flatt, M. Felleisen, Modelling an Algebraic
     Stepper, LNCS 2028.