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

Change the syntax of traits from 'is foo(val)' to '@Foo(val)', and let them precede the thing they annotate #257

Open
masak opened this issue Sep 16, 2017 · 12 comments · May be fixed by #505
Labels

Comments

@masak
Copy link
Owner

masak commented Sep 16, 2017

Following Python and Java's lead. Even TypeScript and ES.next, and (modulo a slight difference in syntax) C#.

Not sure I can fully motivate why I want to make this change, but (a) it feels a little bit more robust in some way, and (b) it's becoming clear that we can have use for traits on a number of things besides subs/macros:

  • Classes
  • Class properties

An example of the former: @Abstract; instead of making it a keyword. An example of the latter: @Readonly. Maybe @Lazy too.

@masak
Copy link
Owner Author

masak commented Sep 16, 2017

It just struck me that one issue with this change is that it delays how soon we can know which type of statement (or class member, etc) we're parsing. Basically, it goes against the grain of Perl 6's idea of having a "declarative prefix" in each rule after which you know what rule you're parsing.

@masak
Copy link
Owner Author

masak commented Sep 17, 2017

On second thought, it's not quite that hopeless. If we parse traits alongside statements in the statementlist rule, it works out fine. Have to mark up some Qtypes as "traitable" (maybe with... a trait?) and check for that, though.

@masak
Copy link
Owner Author

masak commented Sep 20, 2017

I can't find it right now, but somewhere I had quite a complicated is parsed that actually used the parameters of the macro for something. (I think it was to do with declarations and scopes.) I'll link it here if I find it.

Anyway, that'd be problematic if we reverse the order of traits and parameters. At least, we'd have to find some other way to achieve the same effect.

I'd like to find that is parsed example again so I can mull over how to solve that with traits sitting on top.

@masak
Copy link
Owner Author

masak commented Oct 13, 2017

Another small argument in favor of this syntax change: I find it somewhat easier to read this syntax:

foo(@Defined param) {}

Than this syntax:

foo(param is defined) {}

@masak
Copy link
Owner Author

masak commented Apr 15, 2018

It just struck me that one issue with this change is that it delays how soon we can know which type of statement (or class member, etc) we're parsing. Basically, it goes against the grain of Perl 6's idea of having a "declarative prefix" in each rule after which you know what rule you're parsing.

Coming back to it, I feel this was a valid objection to have, but it's by no means a show-stopper. Labels are much the same, in that they can precede many different types of statement and we don't know which one until we've finished parsing the label.

Maybe it'd be worth it to explore the dangers of allowing arbitrary expressions inside the @Annotation(...). If we allow functions there, that means we indirectly allow statements. Not sure I see the harm, really, though. It's all just nesting.

@masak
Copy link
Owner Author

masak commented Nov 15, 2018

Working on this in a branch. Realizing we'll probably need an issue where we also nail down the semantics of decorators.

They're interesting beasts. The ones for precedence and associativity will be driving in this, and they are mostly "metadata decorators" in the sense that they want to end up being attached to the declaration somehow, so that the parser can query them when it needs the information. There are more "business rules" connected to them than I remembered, for example (but not exhaustive):

  • Can't have multiple prec decorators, or multiple assoc decorators.
  • Can't have an assoc decorator if the prec decorator used is equiv.

It's an interesting question how much of that needs to be code, and how much can be captured declaratively somehow in the declaration of the decorators themselves.

@masak
Copy link
Owner Author

masak commented Nov 15, 2018

Simple question: how should the Qtree look for statements with decorators? (Hint: I don't know.)

@masak
Copy link
Owner Author

masak commented Dec 8, 2018

It's an interesting question how much of that needs to be code, and how much can be captured declaratively somehow in the declaration of the decorators themselves.

I think the former can be easily captured using a @unique decorator, or some such. (And it makes sense to me to do so.) Yay, decorators on decorators — that means we're just as cool as Java, does it not?

The latter sounds like a "business rule" to me, and should most likely be handled by whatever thing consumes those parser-targeting decorators. (That is, they should be handled by the parser.)

By the way, the solution I've struck upon with the 007 parser in Perl 6 is to carry that information from where the decorators are parsed to where the statement they're decorating is parsed, by using a dynamic variable. This, in some sense, feels like a sane solution. I could also imagine it being handled by using some sort of "parser state" — as long as the stack-like aspect of it all is still captured. (A previous comment hints at decorators occurring inside decorators via declarations. The dynamic variable handles this well, by storing its data essentially "in the call stack". A "parser state" solution would need to handle it as well.)

In passing, I note that I'm suddenly writing decorators with lowerCamelCase, like in Python, not with UpperCamelCase, like in Java. I have no idea why.

@masak
Copy link
Owner Author

masak commented Dec 8, 2018

Decorators can be

  • Functions, in which case they act on the runtime value as it's created at runtime.
  • Macros, in which case they act on the code structure as it's parsed at compile time.
  • Enum values, in which case they act as "marker decorators", and can be queried (in some unspecified way) by asking for all instances of a particular decorator on a declaration site.

@masak
Copy link
Owner Author

masak commented Dec 8, 2018

Simple question: how should the Qtree look for statements with decorators? (Hint: I don't know.)

What's the Simplest Possible Thing That Could Possibly Work?

From my vantage point, it's a special statement that contains a decorator and an inner statement. That is, a composite.

@masak
Copy link
Owner Author

masak commented Dec 8, 2018

...or maybe that's to general. Maybe a decorator captures what we want here? (That can't be a coincidence, can it?)

@masak
Copy link
Owner Author

masak commented Dec 9, 2018

  • Enum values

Let's hold off on that one. First, because we don't have enums yet in the language. Second, because it's kind of an exception, and I don't fully understand yet.

With just functions/macros in the mix, the rule is simple: a decorator desugars to a call. That is,

@foo(1, 2)
func whatever() {}

desugars to

my whatever = foo(func whatever() {}, 1, 2);

or something very much like it. In general, a decorator is always a function or a macro with an extra first parameter, which is the wrapped function-or-macro. (Or, if the decorator itself is a macro, its Qnode.)

As to "marker decorators", I think on second thought that all decorators are potential marker decorators. But specifically, if one leaves their implementation empty (or identity function), that's probably because they are meant to be used as markers.

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

Successfully merging a pull request may close this issue.

1 participant