Annotations for language features
Reinier Zwitserloot
reinier at zwitserloot.com
Sun Aug 16 12:27:23 PDT 2009
On 2009/16/08, at 20:45, Adam Malter wrote:
> They have been universally fragile, difficult to test, difficult to
> code and difficult to debug.
Huh? We're talking about using annotations as language features. Tool
support isn't relevant to this discussion at all - whether assert was
done as 'assert (boolean);' or as "@Assert (expression);" (supposing
that would be legal) is irrelevant to how well or badly eclipse and
other tools would support it.
> The 'code' must be
> generated realtime in order to preserve 'as your type' error hints
Exactly, which is why lombok does what it does. the AST reflects what
you typed, immediately.
> All those nice Eclipse/Idea/Netbeans features like dynamic method
> lookup, error highlighting, templating, etc, must run the annotation
> processors/plugins on the entire codebase as you go.
So? Lombok's performance impact on either javac or eclipse is not
measurable. And yet the lombok transformation core is run by eclipse
everytime you type a character.
>
> Also, the hurdle for building a Java IDE with these basic features
> is raised.
>
No, it's lowered.
We're now speaking about two entirely different things, but either
way, Java IDE authors will be happy with you.
If we're talking about hardcoding the meaning and result of
annotations into the JLS (Such as @Override), then Java IDEs have it
marginally easier compared to introducing a keyword, because they
don't need to make changes to their grammar processor. A *LOT* of coin
proposals involved syntactic formats which either didn't even fit the
LL(1) model, or would have been non-trivial to implement for grammar
parsers. If you for example look at the difference between the eclipse
parser pre- and post- java1.5 additions, you'd barely recognize the
parser codebase. Annotations can only be useful for a fraction of
those issues (quick: Name a java 1.5 language feature that could have
been done with annotations instead. I can't think of even one!) - but
where annotations fit, the AST building process does not have to
change at all - much easier for IDE developers.
If we're talking about a 'roll your own language features' framework,
e.g. making AST rewriting a plugin architecture like lombok, then IDE
developers will be *much* happier with you. They add support for this
admittedly complex thing once, and then most further features are
delivered either directly in the JDK via sunoracle, or they themselves
write for this framework. Their IDEs would be compatible with feature
java language features right off the bat.
> I believe that tools like Project Lombok are useful for illustrating
> new paths the language can take, but I'd be hesitant to integrate any
> library using it into any production project.
You can't tell. No, really - you cannot tell if a library uses lombok
unless you inspect the source code. Lombok produces class files that
are indistinguishable from the class files generated if you hadn't
used lombok and instead wrote it out longhand.
>
> While the class files for the library may be 'JVM' compatible, without
> the exact version of the plugin, the source files might as well be
> Groovy or Scala (aka, opaque to the java developer)
That's just not true. If you see:
private @Getter int x;
you're not really going to argue here that you, or any other java
programmer is going to be as utterly baffled by what's happening, as
if you rewrote the whole thing in scala, right? Or, to be a bit more
fair about it, isn't this true for *ANY* new language feature?
Therefore your argument boils down to: Java should never change, ever,
ever, ever, because people will get confused, and it'll be like a new
language. We could argue that, at length, but then why are you even on
coindev in the first place? As an argument it has some merit against
adding a 'roll-your-own' framework to java itself, but I don't think
that's what we're talking about, and such a framework would most
definitely be off limits for coin anyway.
lombok-produced class files do not have a dependency on lombok.jar and
are indistinguishable from class files generated by javac (or eclipse)
sans lombok but written out.
> - I know this
> hyperbole, we are only talking about getters/setters, but the slippery
> slope argument is no fallacy
Slippery Slope is by definition a fallacy. You just cannot argue 'This
is going to devolve into insanity' without showing a likely course of
events for how that would happen. So far you've given me absolutely no
indication. I'll get things started with a counter-proof: Between the
various tricks as shown in the Java Puzzlers book, and abusing
reflection, it seems clear that anybody could easily write utterly
fragile, impossible to read or maintain code. And yet the java
community writes code that is by and large readable. Therefore, your
'giving the programmers tools that could possibly be used to shoot
oneself in the foot is going to lead to severe problems' is just a
falsehood. I'll prove it to you, even: In order for a language to be
turning complete, something we generally want in our programming
languages, you also give the programmer the ability to shoot
themselves in the foot. That's the price you pay for allowing code to
be sufficiently expressive to do anything. So far nobody's managed to
build a language that is turing complete and yet prevents you from
writing shoddy code.
So, -yet again-, I implore all to move away from these hyperbolic
gestures of 'that way lies the madness', and actually show HOW the
madness could happen, and discuss BOTH sides of the coin here: It'll
make java code harder to follow mechanically (what -exactly- does this
do), but it'll make code easier to read (you can express the same
thing on a higher level, which is easier for a human brain to get the
gist of). Generics has undoubtedly made understanding how java code
actually works -MUCH- harder, but on the flipside, a lot of code has
become much more readable, because you now know exactly what's in all
those lists and maps. The discussion on whether the cost was worth the
gain is of course a complex one, but it's nevertheless the one we
should be having.
Personally, I'm of the conviction that generating getters and setters
by annotating (with an annotation or a keyword) the field causes
barely any confusion, and makes code -muuuch- easier to maintain and
read. It's got a great value for a marginal cost. We should add things
that offer good value for low costs.
> As an alternative, if what the @Property annotation did was both
> create the getters/setters in the original source, validated them if
> they were already present, and served as a hint to aware IDE's (which
> would then hide the boiler plate), I'd be on board 100%.
>
That's what lombok does (well, not with @Property, but with @Getter
and @Setter). Unless you mean actually write the physical characters
into the source file, but that's a rather preposterous maintainance
nightmare - you'd be burdened with rather a lot of content to read
just to go: "Oh, this entire 3-page thing was just generated by 7
lines of code and 5 annotations!" - that's rather a spectacular waste
of everyone's time. You'd also be incapable of editing things - unless
you propose that the @Property annotation magically knows the name of
its field before you edited that name, and removes those setters and
getters while adding the new one.
A final note on the current state of the APT API: It's a great API. I
recall Joe saying that the original sun.* API was always intended to
be a testrun, so that the true API (javax.annotation.*) can be better.
It paid off well - the javax.annotation.* API is easy to write
against, and the code you end up with is quite readable. I know of
many APIs that are part of the core java platform where this does not
at all hold. Example: Getting type info via reflection including the
generics. That API (.getGenericReturnType() and friends) is horrid. I
wish they did the "testrun once - build it properly after that"
approach for that one.
More information about the coin-dev
mailing list