Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Suggestion: (attr once) for macros to enable safe macro side-effects #200

Closed
ChengCat opened this issue Oct 2, 2018 · 6 comments
Closed

Comments

@ChengCat
Copy link
Contributor

ChengCat commented Oct 2, 2018

In general, a macro may be evaluated more than once, for the following cases:

  1. speculative evaluating to determine argument types
  2. type-of
  3. eval-expression
  4. eval-macro-call

Therefore it's not safe in general for macros to have side effects. On the other hand, macro side-effects are useful, so I suggest that we introduce a new attribute (attr once), for those macros which do have side-effects to be safely written. This attribute will guarantee the macro is evaluated at most once, by prohibiting evaluation in all the above listed cases.

It's still possible for one appearance of macro in source code to be evaluated more than once:

(import cstdio)
(import macros)
(using-namespace std.macros
  (def m (macro intern (void)
    (printf "m is evaluated\n")
    (mnfv mc 1)))
  (def dup (macro intern (x)
    (qq do (uq x) (uq x)))))
(def main (fn extern-c int (void)
  (dup (m))
  0))
@ChengCat
Copy link
Contributor Author

ChengCat commented Oct 2, 2018

Another idea is (attr notype). notype macros won't be evaluated only to determine its return type, and the situation of multiple evaluation of notype macros is similar to that of traditional LIsp languages.

@porky11
Copy link
Contributor

porky11 commented Oct 8, 2018

ChangCat:
I think you are right, that evaluating the expressions of macros is in most cases not a good idea, because in most cases, you would just want to use macros without ever directly evaluating the forms, like let does.

Scopes for example will have two different kinds of macros: One, that works on the S-Expressions directly, like traditional lisp, and one that works on a typed AST.
Like there I would prefer two different kinds of macros, one just syntax and one with type information.
Maybe the one with type information could even be implemented on top of the one without, by manually evaluating the yet untyped forms and calling typed version then.

(attr notype) seems like the best simple solution for now, and would also do the same as two different macro kinds.

@ChengCat
Copy link
Contributor Author

ChengCat commented Oct 9, 2018

@porky11 I know of Scopes, and feel that its approach with two different syntax tree is weird, i.e. one is the written sexp, and the other is the underlying semantics. In traditional Lisps and Dale, there is only one kind of syntax tree. Having two different kinds of syntax tree seems to be an unwanted complication. I have tried to reach its author along with some other concerns, but unfortunately haven't got any reply yet.

I think Dale's approach is fine. It's already not perfectly safe to do side effects in a macro in traditional Lisp languages, and Dale's type-of-related mechanisms just opens up more possibilities for a macro to be evaluated multiple times. This breaks an assumption we implicitly hold when writing Lisp programs, but it is mostly fine when the macro is without any side effects. I think providing a mechanism for safe macro side-effects would be nice. To be honest, I am not entirely satisfied with my suggestions, I hope someone can come up with something better.

@ChengCat
Copy link
Contributor Author

ChengCat commented Oct 9, 2018

Another idea is that, we forbid overloading the same symbol with both functions and macros, when we can't determine only by the number of arguments whether it's function or macro to dispatch. This way, operator-macros will still work, and an entire class of multiple evaluation of macros is eliminated.

This idea can be combined with (attr notype), to get a behaviour similar to that of traditional Lisp.

@porky11
Copy link
Contributor

porky11 commented Oct 9, 2018

That also was my idea, that (attr notype) would disallow defining macros with the same types.

@ChengCat
Copy link
Contributor Author

Closing this issue, since we now have a better idea in #201 to enable safe macro side effects, without any attribute annotation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants