liufengyun / gestalt

gestalt : portable and solid macros for Scala
https://github.com/scalacenter/macros
31 stars 3 forks source link

Design considerations of extractors #73

Closed liufengyun closed 7 years ago

liufengyun commented 7 years ago

I'll try to document some of the thoughts in the design of constructor/extractors in this issue.

Prefer macro-structure over micro-structure

A good example is the design of Class and ForYield/ForDo. An alternative design for Class is to have primary constructors and templates. An alternative design for ForYield/ForDo is to have For/Yield.

The current design in gestalt is superior because they are more high-level, which will make it easier for different platform implementations. Each constructor/extractor is an assumption about some shape, it's better to have assumptions on the overall shape to minimise micro assumptions which are fragile.

For example, ForYield/ForDo only assumes the compiler being able to represent for/yield and for/do, while For/Yield assumes the compiler being able to represent the micro-structure yield, which could make some platform implementation more complex, while doesn't bring any benefits to meta-programmers.

The same consideration justifies the removal of template and primary constructor: the macro-assumptions are much easier to satisfy by platforms. Meanwhile, they make usage easier. The design consideration for InitCall is similar.

Note that currently import is against this principle, they should be improved.

liufengyun commented 7 years ago

The design of Apply and ApplyType is also against this principle, thus can be improved from this perspective.

The design of Match and Case is against this principle as well, though it doesn't pose a problem in practice, as there are not many Scala implementations, they are all similar.

valdisxp1 commented 7 years ago

I came across another example of this with New(AnonymousClass(...)) and New(InitCall(...)). New is redundant, it does not mean anything on its own. NewAnonymousClass(...) and NewInstance(...) should work better. Will send a PR fixing new instance creation with this change soon.

liufengyun commented 7 years ago

Have fewer constructors and extractors

As mentioned above, each abstract constructor and extractor is an assumption on compiler. Minimise the number of constructors and extractors certainly boosts portability.

Avoid providing extractors for problematic constructs, avoid constructors for deprecated language feature, avoid/delay constructors for rare & complex language features.

A common mistake here is to support everything in the language specification.

liufengyun commented 7 years ago

Design for both syntax and semantics

The design of constructors and extractors is mostly driven by syntax of the language. But syntax is not the only concern. Semantically, f(1) in f(1) = 3 is not a function call. Representing the left-hand side by a functional call potentially harms portability. That justifies the introduction of Update, Pat.Var, Pat.Ascribe, Pat.Tuple, Pat.Infix, Self, InitCall, NewInstance, etc.

liufengyun commented 7 years ago

Close, already in the paper.