Programming Languages & Software Engineering

CSE341: Programming Languages Lecture 15 Macros Brett Wortzman Summer 2019 Slides originally created by Dan Grossman What is a macro A macro definition describes how to transform some new syntax into different syntax in the source language A macro is one way to implement syntactic sugar Replace any syntax of the form e1 andalso e2 with if e1 then e2 else false A macro system is a language (or part of a larger language) for defining macros Macro expansion is the process of rewriting the syntax for each macro use Before a program is run (or even compiled)

Spring 2019 CSE341: Programming Languages 2 Using Racket Macros If you define a macro m in Racket, then m becomes a new special form: Use (m ) gets expanded according to definition Example definitions (actual definitions coming later): Expand (my-if e1 then e2 else e3) to (if e1 e2 e3) Expand (comment-out e1 e2) to e2 Expand (my-delay e) to (mcons #f (lambda () e)) Spring 2019

CSE341: Programming Languages 3 Example uses It is like we added keywords to our language Other keywords only keywords in uses of that macro Syntax error if keywords misused Rewriting (expansion) happens before execution (my-if x then y else z) (my-if x then y then z) ; (if x y z) ; syntax error (comment-out (car null) #f) (my-delay (begin (print "hi") (foo 15)))

Spring 2019 CSE341: Programming Languages 4 Overuse Macros often deserve a bad reputation because they are often overused or used when functions would be better When in doubt, resist defining a macro? But they can be used well Spring 2019 CSE341: Programming Languages 5 Now

How any macro system must deal with tokens, parentheses, and scope How to define macros in Racket How macro definitions must deal with expression evaluation carefully Order expressions evaluate and how many times The key issue of variable bindings in macros and the notion of hygiene Racket is superior to most languages here Spring 2019 CSE341: Programming Languages 6 Tokenization First question for a macro system: How does it tokenize? Macro systems generally work at the level of tokens not sequences of characters

So must know how programming language tokenizes text Example: macro expand head to car Would not rewrite (+ headt foo) to (+ cart foo) Would not rewrite head-door to car-door But would in C where head-door is subtraction Spring 2019 CSE341: Programming Languages 7 Parenthesization Second question for a macro system: How does associativity work? C/C++ basic example: #define ADD(x,y) x+y Probably not what you wanted:

1+2/3*4 ADD(1,2/3)*4 means not (1 + 2 / 3) * 4 So C macro writers use lots of parentheses, which is fine: #define ADD(x,y) ((x)+(y)) Racket wont have this problem: Macro use: (macro-name ) After expansion: something else in same place Spring 2019 CSE341: Programming Languages 8

Local bindings Third question for a macro system: Can variables shadow macros? Suppose macros also apply to variable bindings. Then: (let ([head 0][car 1]) head) ; 0 (let* ([head 0][car 1]) head) ; 0 Would become: (let ([car 0][car 1]) car) ; error (let* ([car 0][car 1]) car) ; 1 This is why C/C++ convention is all-caps macros and non-all-caps for everything else Racket does not work this way it gets scope right! Spring 2019 CSE341: Programming Languages 9 Example Racket macro definitions

Two simple macros (define-syntax my-if ; macro name (syntax-rules (then else) ; other keywords [(my-if e1 then e2 else e3) ; macro use (if e1 e2 e3)])) ; form of expansion (define-syntax comment-out ; macro name (syntax-rules () ; other keywords [(comment-out ignore instead) ; macro use instead])) ; form of expansion If the form of the use matches, do the corresponding expansion In these examples, list of possible use forms has length 1 Else syntax error Spring 2019

CSE341: Programming Languages 10 Revisiting delay and force Recall our definition of promises from earlier Should we use a macro instead to avoid clients explicit thunk? (define (my-delay th) (mcons #f th)) (define (my-force p) (if (mcar p) (mcdr p) (begin (set-mcar! p #t) (set-mcdr! p ((mcdr p))) (mcdr p)))) (f (my-delay (lambda () e))) (define (f p) ( (my-force p) ))

Spring 2019 CSE341: Programming Languages 11 A delay macro A macro can put an expression under a thunk Delays evaluation without explicit thunk Cannot implement this with a function Now client should not use a thunk (that would double-thunk) Rackets pre-defined delay is a similar macro (define-syntax my-delay (syntax-rules () [(my-delay e) (mcons #f (lambda() e))])) (f (my-delay e)) Spring 2019

CSE341: Programming Languages 12 What about a force macro? We could define my-force with a macro too Good macro style would be to evaluate the argument exactly once (use x below, not multiple evaluations of e) Which shows it is bad style to use a macro at all here! Do not use macros when functions do what you want (define-syntax my-force (syntax-rules () [(my-force e) (let([x e]) (if (mcar x) (mcdr x) (begin (set-mcar! x #t) (set-mcdr! p ((mcdr p)))

(mcdr p))))])) Spring 2019 CSE341: Programming Languages 13 Another bad macro Any function that doubles its argument is fine for clients (define (dbl x) (+ x x)) (define (dbl x) (* 2 x)) These are equivalent to each other So macros for doubling bad style but instructive examples: (define-syntax dblare (syntax-rules()[(dbl x)(+ x x)]))

(define-syntax dbl (syntax-rules()[(dbl x)(* 2 x)])) (dbl (begin (print "hi") 42)) These are not equivalent to each other. Consider: Spring 2019 CSE341: Programming Languages 14 More examples Sometimes a macro should re-evaluate an argument it is passed If not, as in dbl, then use a local binding as needed: (define-syntax dbl (syntax-rules () [(dbl x) (let ([y x]) (+ y y))])) Also good style for macros not to have surprising evaluation order

Good rule of thumb to preserve left-to-right Bad example (fix with a local binding): (define-syntax take (syntax-rules (from) [(take e1 from e2) (- e2 e1)])) Spring 2019 CSE341: Programming Languages 15 Local variables in macros In C/C++, defining local variables inside macros is unwise When needed done with hacks like __strange_name34 Here is why with a silly example: Macro:

(define-syntax dbl (syntax-rules () [(dbl x) (let ([y 1]) (* 2 x y))])) (let ([y 7]) (dbl y)) Use: (let ([y 7]) (let ([y 1]) (* 2 y y))) Nave expansion: Spring 2019 CSE341: Programming Languages 16 The other side of hygiene This also looks like it would do the wrong thing

Macro: (define-syntax dbl (syntax-rules () [(dbl x) (* 2 x)])) (let ([* +]) (dbl 42)) Use: (let ([* +]) (* 2 42)) Nave expansion: Spring2019 CSE341: Programming Languages But again Rackets hygienic macros get this right! 17

How hygienic macros work A hygienic macro system: 1. Secretly renames local variables in macros with fresh names 2. Looks up variables used in macros where the macro is defined Neither of these rules are followed by the nave expansion most macro systems use Without hygiene, macros are much more brittle (non-modular) On rare occasions, hygiene is not what you want Racket has somewhat complicated support for that Spring 2019 CSE341: Programming Languages 18 More examples See the code for macros that: A for loop for executing a body a fixed number of times

Shows a macro that purposely re-evaluates some expressions and not others Allow 0, 1, or 2 local bindings with fewer parens than let* Shows a macro with multiple cases A re-implementation of let* in terms of let Shows a macro taking any number of arguments Shows a recursive macro Spring 2019 CSE341: Programming Languages 19

Recently Viewed Presentations

  • Presentación de PowerPoint - UOC

    Presentación de PowerPoint - UOC

    objetivos del tfc. garantizar diponibilidad de servicios segÚn acuerdo de nivel establecido (lsa). sin coste adicional en licencias durante 5 aÑos.
  • Diapositive 1

    Diapositive 1

    University of Limoges, IRCER - UMR CNRS 7315,France. Thank you Mr Chairman. This talk deals with « the study of the densification mechanisms and thermomechanical properties of spark plasma sintered boron carbide ceramics ». This work has been conducted at...
  • LIQUIDS and SOLIDS - Weebly

    LIQUIDS and SOLIDS - Weebly

    Surface Tension- A force that tends to pull adjacent parts of a liquid's surface together due to attractive forces between particles. Capillary Action- The attraction of the surface of a liquid to the surface of a solid. Vaporization - Liquid...
  • COMP 104: Intro to Unix Week 3 Review

    COMP 104: Intro to Unix Week 3 Review

    COMP 104: Intro to Unix Week 3 Review of Last Week Unix file system structure File types and access permissions Create and use directories and files Edit files with vi Use the following Unix commands: cd, chmod, cp, id, mkdir,...
  • The Spread of Civilization: The Great River Valleys

    The Spread of Civilization: The Great River Valleys

    The Spread of Civilization: The Great River Valleys Slideshow #3
  • Topics Origin and adaptive superiority of vascular system,

    Topics Origin and adaptive superiority of vascular system,

    Times New Roman Arial Default Design 2_Default Design 3_Default Design 4_Default Design 5_Default Design 6_Default Design 7_Default Design 8_Default Design 9_Default Design 10_Default Design 11_Default Design 12_Default Design 13_Default Design PowerPoint Presentation PowerPoint Presentation PowerPoint Presentation plant life cycles compared...
  • Solar Plate Etching - Lancaster High School

    Solar Plate Etching - Lancaster High School

    Solar Plate Etching ... Work-back Maddie Hines (Print) S. Rogers (Work-back) 2014 Work-back Hannah Robinson (Print) S. Rogers (Work-back) 2016 Famous Photographers Dorothea Lange Famous Photographers James Nachtwey Famous Photographers Malcolm Browne Famous Photographers Helen Levitt Cindy ...
  • Alaska Aviation Weather & The Alaska Aviation System

    Alaska Aviation Weather & The Alaska Aviation System

    Alaska DOT&PF. Statewide Aviation. Weather Working Group. Background. An examination of weather reporting stations as part of the latest multifaceted Alaska Aviation System Plan Update. Weather Working Group Created . Working Group Members.