From Mark.Bravington at csiro.au  Wed Jun  9 02:20:28 2004
From: Mark.Bravington at csiro.au (Mark.Bravington@csiro.au)
Date: Wed Jun  9 02:20:38 2004
Subject: [Rd] Using macros
Message-ID: <C4178DC99E08604EA5E2BDB989F093800240A2A6@extas2-hba.tas.csiro.au>

Hi John

I haven't looked at your application in detail, but you might also want to have a look at 'mlocal' in my 'mvbutils' package, which provides an alternative way of setting up "macros". (See also "do.in.envir" and "extract.named") There are some nice facilities, e.g. in letting you "declare" temporary variables that don't overwrite existing variables in the frame of the macro's caller. This gets round two potential usage pitfalls: creation of junk variables in the caller, and accidental overwriting of non-junk variables in the caller that happen to have the same name as a variable in the macro.

OTOMH the other technical pitfalls are 

(i) macro arguments are evaluated at time of calling the macro, not via "lazy evaluation" [though this might be fixable with 'delay']

(ii) 'return'-- just including a 'return' statement doesn't work. 'mvbutils' has a 'local.return' function that deals with this.

(iii) 'on.exit'-- macro or caller? 'mlocal' has a fix for this, allowing the 'on.exit' to apply only to the macro.

(iv) 'sys.call' etc.-- the frame sequence is not what you might guess.

The 'mlocal' documentation has notes on all of these.

I also haven't looked at Thomas' approach in detail, so I can't be sure all these things apply to his macro system too-- but I suspect they are generic.

Hope this helps

Mark

*******************************

Mark Bravington
CSIRO (CMIS)
PO Box 1538
Castray Esplanade
Hobart
TAS 7001

phone (61) 3 6232 5118
fax (61) 3 6232 5012
Mark.Bravington@csiro.au 

#-----Original Message-----
#From: r-devel-bounces@stat.math.ethz.ch
#[mailto:r-devel-bounces@stat.math.ethz.ch]On Behalf Of John Fox
#Sent: Wednesday, 9 June 2004 9:11 AM
#To: r-devel@stat.math.ethz.ch
#Subject: [Rd] Using macros
#
#
#Dear list members,
#
#I've been puzzling over how best to clean up the code for my 
#Rcmdr package.
#In particular, there's a lot of repetitive tcltk code in the 
#package, and as
#Martin M?chler has pointed out to me, this makes the package 
#difficult to
#maintain.
#
#If R were Lisp, I'd use macros for much of the clean up. My 
#efforts to do
#similar things with R functions has run into problems with 
#scoping issues.
#My attempts to solve these problems have worked, but lead to 
#awkward code
#(perhaps because I've not been clever enough to do it in a 
#natural way).
#
#Thomas Lumley describes a function for constructing R "macros" 
#in the Sept.
#2001 issue of R-news. Here's an application to producing standard OK,
#Cancel, and Help buttons using tcltk:
#
#    ### Thomas's defmacro:
#    defmacro <- function(..., expr){
#        expr <- substitute(expr)
#        a <- substitute(list(...))[-1]
#        ## process the argument list
#        nn <- names(a)
#        if (is.null(nn)) nn <- rep("", length(a))
#        for (i in seq(length=length(a))){
#            if (nn[i] == "") {
#                nn[i] <- paste(a[[i]])
#                msg <- paste(a[[i]], "not supplied")
#                a[[i]] <- substitute(stop(foo), list(foo = msg))
#                }
#            }
#        names(a) <- nn
#        a <- as.list(a)
#        ff <- eval(substitute(
#            function(){
#                tmp <- substitute(body)
#                eval(tmp, parent.frame())
#                },
#            list(body = expr)))
#        ## add the argument list
#        formals(ff) <- a
#        ## create a fake source attribute
#        mm <- match.call()
#        mm$expr <- NULL
#        mm[[1]] <- as.name("macro")
#        attr(ff, "source") <- c(deparse(mm), deparse(expr))
#        ## return the macro
#        ff
#        }
#
#    OKCancelHelp <- defmacro(window=top, OKbutton=OKbutton, onOK=onOK, 
#        cancelButton=cancelButton, onCancel=onCancel,
#        helpButton=helpButton, onHelp=onHelp, helpSubject,
#        expr={
#            OKbutton <- tkbutton(window, text="OK", fg="darkgreen",
#width="12", command=onOK, default="active")
#            onCancel <- function() {
#                tkdestroy(top)  
#                } 
#            cancelButton <- tkbutton(window, text="Cancel", fg="red",
#width="12", command=onCancel)
#            onHelp <- function() {
#                help(helpSubject)
#                }
#            helpButton <- tkbutton(window, text="Help", width="12",
#command=onHelp)
#            }
#        )
#    
#    test <- function(){
#        top <- tktoplevel()
#        onOK <- function(){
#            tkmessageBox(message="Foo.", icon="info", type="ok")
#            tkdestroy(top)
#            }
#        OKCancelHelp(helpSubject="lm")
#        tkgrid(OKbutton, cancelButton, helpButton)
#        }
#    
#    test()
#
#That is, the OKCancelHelp macro makes the buttons and the call-back
#functions onCancel and onHelp in the environment of the 
#calling function
#(here test). This seems to work fine, but I wonder whether 
#there are any
#hidden pitfalls to adopting this as a general strategy. For example, is
#there some problematic interaction with namespaces if I export 
#the macro
#OKCancelHelp?
#
#Any advice would be appreciated.
# John 
#
#--------------------------------
#John Fox
#Department of Sociology
#McMaster University
#Hamilton, Ontario
#Canada L8S 4M4
#905-525-9140x23604
#http://socserv.mcmaster.ca/jfox
#
#______________________________________________
#R-devel@stat.math.ethz.ch mailing list
#https://www.stat.math.ethz.ch/mailman/listinfo/r-devel
#


[Rd] Using macros
Mark.Bravington@csiro.au