On 08/25/2012 12:19 PM, Neil Toronto wrote:
A lot of macros start by renaming some syntax that's assumed to
eventually represent a runtime value, like the `or' macro does:

 > (syntax->datum (expand-syntax #'(or #t #f)))
'(let-values (((or-part) '#t)) (if or-part or-part '#f))

But it's not always a good thing, particularly when the output will be
processed by another macro, and parts will be tested using an
`identifier=?' function. For example, my `inline-sort' takes `<' as an
argument. So

   (inline-sort < a b)

expands to

   (let ([lt? <] [temp1 a] [temp2 b])
     (if (lt? temp1 temp2) (values temp1 temp2) (values temp2 temp1)))

Well, it did at first. When I discovered that Typed Racket's optimizer
would never detect that `lt?' is actually `<' and replace it with
`unsafe-fl<', I altered the macro to detect when the `<' is an
identifier, and not rename it with a `let'.

Is it feasible to make the TR optimizer smarter about this? That would be the best solution.

I know that I should assert my rights under the Macro Bill. But I like
to program defensively. So what's safe to not rename? I think the
following are:

I've reordered these a bit:

number
string
bytes
character
regexp

In other words, "literal data". But did you check that the '#%datum' macro associated with them has the standard meaning? If not, they could expand into arbitrary expressions (possibly with side effects)!

symbol

Do you mean identifier, as in "it's just a variable reference"? But it could be an identifier macro. Or it could be a variable that other parts of the code could concurrently mutate. For example, suppose 'match' expanded less cautiously than it actually does:

  (match x [(cons a b) a])
  =>
  (if (pair? x) (unsafe-car x) (match-error ....))

Now suppose that x is a module-level variable that some other thread mutates between the 'pair?' check and the 'unsafe-car'.

null
prefab struct key

I don't know what you mean by these in this context. Maybe 'quote' expressions containing them?

--

If you must do such things, the safest way in general is to fully local-expand the expression you want to analyze; that gives you something with a known grammar. Now it's feasible to identify literal data: it's any 'quote' expression. You don't have to worry about identifier macros, but the 'set!' danger remains for any variables that you don't completely control the scope of.

In your specific case, it would also be safe to check whether the comparison expression is an identifier free-identifier=? to one of a fixed list of known (immutable) variables; if so, it's safe to duplicate.

Also, should I ever have to intern syntax that's one of these kinds of
things?

Do you mean intern the data? IIUC, yes: the reader interns literal data, but macros are free to introduce non-interned literal data. (It will probably get interned again when the compiled form is loaded from zo, but there's a period during the expansion of the enclosing module when it won't be interned.)

Ryan

_________________________
 Racket Developers list:
 http://lists.racket-lang.org/dev

Reply via email to