Hi Rüdiger,
Thanks for the questions...
There isn't a document. The rationale was mainly that many people didn't like the old syntax. Here are some details:
a. The old way required a bunch of implicits. This makes builds slower to compile. Much of this makes the user-visible API unnecessarily larger due to intermediate forms or implementation artifacts.
b. The old way had a finite number of allowed inputs (originally 9, raised to 15). The new way is in theory unlimited. It is possibly limited by compiler performance on heterogeneous lists in practice, although the macros give explicit types so maybe not. (I haven't checked too high.)
c. The old way gave poor error messages when using a task as an input to a setting or similar cases. In general, error messages are or can be improved by using a macro.
d. See the new input task syntax, which is built on the same new macro system. The improvement here is more than that for normal tasks and settings. Input tasks are a combination of settings, tasks, parsers, and State. It's hard to stack things in Scala and provide both the ability to work at one level for flexbility or work at the full stack for convenience and provide somewhat readable error messages. I think the new macro-based syntax is much improved here, although it will still need work for some more advanced cases and issues people see in practice.
e. Note that the old flatMap was really an apply followed by a flatMap. The current one is as well, but it is relevant to note that we are mainly talking about applicative functors when talking about tasks/settings and only rarely about monads.
f. macros can capture the source location of the definition site. If you look at 'inspect' in 0.13, you will see that it tells you where the setting/task was defined.
g. There were seven basic methods before (:=, +=, ++=, ~=, <+=, <++=, <<=). Of those, the three beginning with '<' are no longer needed (or are close to it). The new syntax allows tasks with and without dependencies to be defined in the same way (with just the first three). I haven't decided about ~=, but it isn't as necessary as before and you could reasonably get away with just those first three. The last three symbols were a big complaint.
h. A specific example of an improvement is that a task can take an Initialize[Task[T]] as a task input now and not just a TaskKey[T]. (So, no need to declare intermediate, named tasks.) This wasn't possible with standard approaches (I tried). This may not seem like a big deal (and maybe most users don't deal with that type), but it makes it possible to provide more flexible APIs.
i. No need for an intermediate name for the value computed by a setting/task in simple cases.
j. Overall, the documentation was simplified. It is easier to provide snippets and to introduce concepts. (For example, it is no longer necessary to differentiate tasks with and without dependencies as described above.) I have only incrementally updated the documentation, but I think it has made things easier to explain for Josh in sbt in Action as well.
There are some disadvantages to the new approach and to macros in general, but you only asked about the advantages ;)
> 2. will the old mechanism that does not use macros eventually be replaced
> by the macro mechanism, or will it be retained indefinitely?
There isn't currently plan to remove it, although if macros work well, it would make sense to remove the old way. If removed, I doubt it would be a normal removal cycle. I'd guess it would be deprecated, then behind an import, then perhaps still available as a plugin. It depends on demand. There are a lot of builds using the old way. Also, although the macros have been well-received so far, 0.13.0 is still not final and widely used.
> I must confess that I am slightly irritated about this. Is the expressive
> power of "vanilla" scala really so low that we need macros for absolutely
> everything?
The glib answer is yes. I wouldn't say that it is "so low" though, just that macros can make a substantial difference for users. So far, the feedback I have seen on the new macros has been overwhelmingly positive. Certainly there will be things to improve, but I think the benefits are there.
For an additional discussion beyond the points listed above, consider the for comprehension. It is special Scala syntax for monadic computation that you couldn't do yourself using the tools Scala provides. (Even as it is, it is limited.)
What is the equivalent for applicative functors? There isn't one in Scala. People have tried various syntaxes using Scala pre-macros and they have various limitations or are unpopular for various reasons. There are various projects now using macros to provide a better syntax and sbt is one of them.
Next, note that a macro doesn't actually change Scala's syntax. Scala code involving macros is parsed normally and it has to typecheck before and after a macro is run. In particular, the types are the same before and after the macro runs (or "expands"). You could possibly come up with a system that has a similar syntax to 0.13 without using macros, but it almost certainly would be mutable, with less compile-time checking, and less useful and less powerful.
Traditionally, features like default and named arguments, inference, implicits, overloading, and infix methods are used to define a DSL. It quickly becomes hard to provide good error messages in all cases. The error message is often removed from what the user is trying to do. This is a standard internal DSL drawback of course.
Also, it is hard to evolve implicits and overloading without breaking code and it is rather hard to know in advance how code will break, especially due to inference. I don't think anyone writing a DSL sets out to push the boundaries of these things. You start with some requirements and then you come up against a choice is between syntax and semantics and I'd sacrifice syntax almost every time. (I find the use of ThreadLocals to improve syntax such a bad tradeoff, but that's another story.) Macros somewhat mitigate the need in some cases with the usual tradeoff being in implementation complexity.
Lastly, it is hard to document everything involved in making the DSL. A lot isn't fundamentally necessary to know, but it still comes out in error messages or API docs. Macros ideally hide that and provide only what the user needs (ideally of course). 0.13 doesn't fully benefit here because it still supports the old style and other reasons.
At least for now, I don't think you'll find macros being that pervasive just because non-trivial ones are so hard and time consuming to write. That might change with quasiquotes, but I haven't tried them for the macros in sbt yet. Speaking only for myself, I would only resort to macros when there isn't a standard way to do something. As just one example, this new 0.13 feature uses only standard constructs:
http://www.scala-sbt.org/0.13.0/docs/Detailed-Topics/Tasks.html#getting-values-from-multiple-scopes
-Mark
> best regards,
>
> Rüdiger
>
> --
> You received this message because you are subscribed to the Google Groups "simple-build-tool" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to
simple-build-t...@googlegroups.com.
> To post to this group, send email to
simple-b...@googlegroups.com.
> Visit this group at
http://groups.google.com/group/simple-build-tool.
> For more options, visit
https://groups.google.com/groups/opt_out.
>
>