The new features announced at Devoxx.

82 views
Skip to first unread message

Reinier Zwitserloot

unread,
Nov 20, 2010, 1:43:04 AM11/20/10
to Project Lombok
In case you haven't seen em yet, here are the announcements in rough
order of importance:

A. Support for 'val' - you can now write i.e. "val foo = new
ArrayList<String>();" or "for (val x : whatever())" in methods (local
declarations only, it's not for fields), and the type will be inferred
from the expression / iterable. The variable will be final.

B. Support for '@Delegate'. We've discussed delegate lots of times on
this group.

C. the new IntelliJ 10 release has added a bunch more API calls that
should make it relatively simple to add lombok support, and the
IntelliJ team has given us some contacts we can talk to when we need
help.

D. @Getter(lazy=true) gives you lazily initialized getters.

E. @EqualsAndHashCode now uses the 'instanceof' style, but adds a
canEqual method so you can extend classes with equality-affecting
state without breaking the equals contract. This style of equals
method is compatible with scala case classes.

F. @Log makes logging a bit easier for Apache Commons Logging, SLF4J,
java.util logging, and Apache Log4J. Essentially we adopted the idea
behind the morbok extension and included it into lombok itself.

G. Groovy 1.8 has taken a bunch of our annotations such as @ToString
and added support for this in groovy. They've put in the effort to be
quite compatible with what we do, which is awesome. In turn we're
probably going to take one of their ideas built into groovy's @Log
feature: If its clear at compile time what level a log statement is
targetting, a guarding 'if' is generated around it to skip that log
altogether if the logger says it will just discard that log level.
This is nice if the log expression is expensive to calculate.

H. You can put annotations on generated getters and setters now, like
so: @Setter(onMethod=@Deprecated, onParam=@WhateverYouLike).

'val' doesn't work in netbeans quite yet, and "@Delegate" doesn't work
in netbeans or javac. We're working on it.

Daniel Yokomizo

unread,
Nov 20, 2010, 8:31:08 AM11/20/10
to project...@googlegroups.com
On Sat, Nov 20, 2010 at 4:43 AM, Reinier Zwitserloot <rein...@gmail.com> wrote:
> In case you haven't seen em yet, here are the announcements in rough
> order of importance:

Great news.

>  B. Support for '@Delegate'. We've discussed delegate lots of times on
> this group.

Which design was used for @Delegate? There's no documentation on the site yet.

Best regards,
Daniel Yokomizo

Reinier Zwitserloot

unread,
Nov 20, 2010, 12:07:24 PM11/20/10
to Project Lombok
There will be once we finish the javac implementation for it. The
really short version:

@Delegate is legal on fields. @Delegate takes an array of classes as
parameter. Leaving it out is equal to specifying the field's type as
parameter.

All parameter types are inspected, all non-static public methods from
all these types and all their supertypes are added up, then all
methods in java.lang.Object are removed. Then any of these methods
already present in the class are also removed. Whatever's left gets
delegated. There's not currently any way to call pre/post hooks or any
other such more advanced features. Note that if you want generics to
work right you're stuck with no-arg @Delegate, as you can't put
generics in class literals.

Example:

@Delegate List<String> foo;

generates methods like clear(), add(String), addAll(Collection<?
extends String>) etc.

Example:

private interface CustomizeIt {
public int foo();
public void bar(String x);
}

@Delegate(CustomizeIt.class) Object whatever;

generates foo() and bar(String). Note that the type of 'whatever'
doesn't have to explicitly be a CustomizeIt (though of course if the
foo and bar methods don't exist in that type, you'll get compiler
errors), and your own class hosting the @Delegate field doesn't have
to implement CustomizeIt (or, for the first example, List), either.


On Nov 20, 2:31 pm, Daniel Yokomizo <daniel.yokom...@gmail.com> wrote:

Moandji Ezana

unread,
Nov 20, 2010, 12:24:38 PM11/20/10
to project...@googlegroups.com
This is awesome. I made the mistake of going to a different Devoxx session instead of yours that turned out to be extremely boring. 

However, pre-/post-hooks feel like more than boilerplate. I'm not sure it's necessary.

Moandji

Haakon Nilsen

unread,
Nov 20, 2010, 6:58:58 PM11/20/10
to Project Lombok
Thanks for the nice Devoxx talk, guys!

On Nov 20, 7:43 am, Reinier Zwitserloot <reini...@gmail.com> wrote:
>  A. Support for 'val' - you can now write i.e. "val foo = new
> ArrayList<String>();" or "for (val x : whatever())" in methods (local
> declarations only, it's not for fields), and the type will be inferred
> from the expression / iterable. The variable will be final.

I can't decide how to feel about "val". I'm a bit bothered that it's
not an annotation like all the other Lombok features. With no imports
required, val's dependency on Lombok is untraceable for someone
unfamiliar with Lombok. And it seems like the diamond operator in JDK7
will take care of the same kinds of boilerplate anyway.

On the other hand, cool! I love the Scala-like syntax. As long as
you're imitating Scala, have you considered an additional "var"
keyword for non-final references?

Why no fields support?

Reinier Zwitserloot

unread,
Nov 21, 2010, 12:21:38 AM11/21/10
to Project Lombok
Diamond Operator can't hold a candle to what val can do. For example,
this kind of stuff happens all the time, and diamond won't do anything
for it:

for (Map.Entry<String, List<String>> entry : map.entrySet()) { ... }


var will not be added, as we find the notion a fundamentally bad idea.
If other things are going to be assigned to the variable, the type of
that variable should be explicitly stated. For example:

var x = new ArrayList<String>();
x = new LInkedList<String>();

Should lombok now infer that x's intended type is List and not
ArrayList? But that would mean that a single assignment can change the
type of a variable, which is weird. Also, if we do that, should lombok
then infer List<? extends Number> from:

var x = new ArrayList<Integer>();
x = new LinkedList<Double>();

That's very complicated.

Basically the "List" in: "List<String> x = new ArrayList<String>();"
is not actually boilerplate. However, if x is also final then the
benefit of giving a separate type for x becomes so small that in
practice its not really going to add a lot of readability. We write
something like getFoo().getBar() all the time, and then you can't see
the type of getFoo() either. The bit these 2 cases have in common is
that while you'd have to check the type of the expression to know, you
only have to check that one expression.


No fields is for somewhat similar reasons; fields have far more reach
than local declarations. We can't guess that "List<String>" would be a
better fit than "ArrayList<String>" in "private val x = new
ArrayList<String>();" and unlike local variable declarations, later
changing the expression could have nasty side effects - it'll most
likely change the type and this causes serializableID to change and
binary compatibility failures when mixing a class with a new type
(invisibly new due to val) with classes compiled against the old one.
Granted, most fields are final (and we could simply error out if you
try to 'val' a field that isn't), but that's a bit too much magic for
our tastes.


One simple solution to the 'val is not visible!' dilemma is to put a
comment someplace in your source file (Yes, meh, but then a lombok
import is also a line you usually fold away at the very top of the
source), or better yet spread the word so everyone recognizes 'val' in
java as a lombok feature :P

Maaartin-1

unread,
Nov 21, 2010, 6:30:59 AM11/21/10
to project...@googlegroups.com
On 10-11-21 06:21, Reinier Zwitserloot wrote:
> Diamond Operator can't hold a candle to what val can do. For example,
> this kind of stuff happens all the time, and diamond won't do anything
> for it:
>
> for (Map.Entry<String, List<String>> entry : map.entrySet()) { ... }

I agree that the diamond operator is quite weak. Actually, I don't
grasp, why simple
List<String> x = new ArrayList();
without any diamond shouldn't suffice. There's an compatibility argument
saying the the constructor should return a raw ArrayList, but this is
IMHO pure nonsense. Who uses such a thing nowadays? There are people who
have to stick with Java 1.4, but the above line is no Java 1.4 anymore.
With any single use of templates, row types should get outlawed in the
whole source file (interfacing with legacy classes works fine using <?>).

> var will not be added, as we find the notion a fundamentally bad idea.
> If other things are going to be assigned to the variable, the type of
> that variable should be explicitly stated. For example:
>
> var x = new ArrayList<String>();
> x = new LInkedList<String>();
>
> Should lombok now infer that x's intended type is List and not
> ArrayList?

Of course not, this would get too far. If I needed something like this,
I'd declare it explicitly.

> But that would mean that a single assignment can change the
> type of a variable, which is weird. Also, if we do that, should lombok
> then infer List<? extends Number> from:
>
> var x = new ArrayList<Integer>();
> x = new LinkedList<Double>();
>
> That's very complicated.

Complicated and rare. However, a simple "var" without all the magic
could be quite useful and it's implementation (given val) is trivial.

> Basically the "List" in: "List<String> x = new ArrayList<String>();"
> is not actually boilerplate. However, if x is also final then the
> benefit of giving a separate type for x becomes so small that in
> practice its not really going to add a lot of readability. We write
> something like getFoo().getBar() all the time, and then you can't see
> the type of getFoo() either. The bit these 2 cases have in common is
> that while you'd have to check the type of the expression to know, you
> only have to check that one expression.

Nice argument.

> No fields is for somewhat similar reasons; fields have far more reach
> than local declarations. We can't guess that "List<String>" would be a
> better fit than "ArrayList<String>" in "private val x = new
> ArrayList<String>();" and unlike local variable declarations, later
> changing the expression could have nasty side effects - it'll most
> likely change the type and this causes serializableID to change and
> binary compatibility failures when mixing a class with a new type
> (invisibly new due to val) with classes compiled against the old one.

That's true, but this is no worse than renaming a field or adding a new
one. I don't think I'd change


private val x = new ArrayList<String>();

to
private val x = new LinkedList<String>();
any more often then changing something else. Quite the opposite, it's
very improbable (especially for a LinkedList, which is nearly always
slower; you'd have to try hard to find a use case where it wins).
Moreover, if such a change is needed, you may need to change List to
Queue or LinkedHashSet or whatever as well. There are so many other
changes affecting the serialVersionUID and not so many Serializable classes.

Additionally, the whole line can be considered to be the declaration.
When somebody is going to fiddle with it, they simply *must* see, that
the type changes. I can't imagine somebody using val (where the type
gets defined on the RHS) and being blind enough to overlook it.

Non-final instance/class variables and such initialized in the
constructor are a different case. With multiple constructors we could
run into the problem with different assignments just as in you example
above.

So, I'd suggest to extend val to final fields initialized in the
declaration. Nothing more, as it could get too complicated. Nothing
less, for reasons given above.

> Granted, most fields are final (and we could simply error out if you
> try to 'val' a field that isn't), but that's a bit too much magic for
> our tastes.

I don't understand this. The keyword "val" implies final, so what do you
mean?

> One simple solution to the 'val is not visible!' dilemma is to put a
> comment someplace in your source file (Yes, meh, but then a lombok
> import is also a line you usually fold away at the very top of the
> source),

Commenting each single source file looks like more boilerplate than
"val" can save.

or better yet spread the word so everyone recognizes 'val' in
> java as a lombok feature :P

Agreed, making val well-known is the best possibility. You could misuse
the package declaration like
package (lombok) com.example;
which could be used for all incompatible changes, e.g.,
package 7 com.example;
could mean that the source code needs jdk7 at least. This could have
been used for Java 4 (assert) and Java 5 (enum) incompatibilities as
well. But I don't think it's necessary for "val", just let us spread the
word instead.

Shervin

unread,
Nov 22, 2010, 6:01:18 AM11/22/10
to Project Lombok
Hi.

When will you build a new version for these new features?

Shervin

Roel Spilker

unread,
Nov 22, 2010, 6:07:36 AM11/22/10
to project...@googlegroups.com
You can download the Devoxx 2010 Special preview version at http://projectlombok.googlecode.com/files/lombok-0.10.0-BETA2.jar

Be aware: this is not a release. There are still some rought edges. For instance, @Delegate won't work on javac; only inside Eclipse. Also, the @Getter(lazy=true) uses a different implementation then the final release will.

But feel free to toy around.

Roel


> -----Oorspronkelijk bericht-----
> Van: shervin...@gmail.com
> [mailto:project...@googlegroups.com] Namens Shervin
> Verzonden: 22 November 2010 12:01
> Aan: Project Lombok
> Onderwerp: [project lombok] Re: The new features announced at Devoxx.

> --
> You received this message because you are subscribed to the
> Google Groups group for http://projectlombok.org/
>
> To post to this group, send email to
> project...@googlegroups.com To unsubscribe from this
> group, send email to
> project-lombo...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/project-lombok?hl=en
>
>

Maaartin-1

unread,
Nov 22, 2010, 8:29:31 AM11/22/10
to project...@googlegroups.com
On 10-11-22 12:07, Roel Spilker wrote:
> You can download the Devoxx 2010 Special preview version at http://projectlombok.googlecode.com/files/lombok-0.10.0-BETA2.jar
>
> Be aware: this is not a release. There are still some rought edges. For instance, @Delegate won't work on javac; only inside Eclipse. Also, the @Getter(lazy=true) uses a different implementation then the final release will.

I can live with these problems. What's worse is eclipse getting really
confused. I tried @Delegate to File and got other problems
- "assign to new field" in constructor puts the new field at the very
top of the source file
- selecting an expression below @Cleanup using shift-alt-up selects the
whole block containing @Cleanup instead
- the highlighting stops working sometimes
- a warning "The method toURL() from the type File is deprecated"

I had similar problems with the v0.9.2, too, I haven't tried v0.9.3. In
case v0.9.3 has no such problems, I'd switch to it, should I?

What is the best way for attaching the sources? I've got the working
tree from github (tag v0.10.0-BETA2), and attached it to the jar, but
clicking on e.g. @Cleanup brings me to a window different from the one
obtained by opening the file directly. Should I drop lombok.jar from my
classpath and add the lombok project instead? But this work somehow, I
could build lombok using build.xml, but it doesn't help me at all. I'd
need a .project and .classpath for eclipse. I though I could make them
by my own, but it doesn't work at all - everything looks nice, the class
files are where there belong to, but eclipse pretends they aren't there.
I triple checked it all, neither refresh nor restart help, it drives me mad.

Regards, Maaartin.

Jacek Furmankiewicz

unread,
Nov 22, 2010, 9:15:23 AM11/22/10
to project...@googlegroups.com
Let me the lone voice of dissent here.

As someone who is in charge of a team and responsible for the long-term maintenance of a project, I think you guys are crossing the line
between what you *can* do with AST post-processing vs. what you *should* do.

I think adding brand new keywords to Java and essentially forking the language is going too far.

Annotations that reduce boiler plate Java code are amazing.
New keywords that did no go through any JSR or will be a mystery to any brand new developer joining a project
with that code in it are a bridge too far IMHO.

When that version of Lombok comes I will forbid anyone in my group from using non-standard keywords such as "val".

Please stick to basic Java annotations please. 

Just my $0.02 Canadian.

Jacek

Roel Spilker

unread,
Nov 22, 2010, 9:50:08 AM11/22/10
to project...@googlegroups.com
Just some quick answers:

There are known problems with Cleanup. We already know a way to solve those, but didn't have time to implement them.

To get an Eclipse project, just run "ant eclipse"

About the toURL, we probably should add the @SuppressWarnings("all") to the generated methods.

The "assign to new field" does not work well with the @Synchronized annotation. Do you use that one? If not, the new @Delegate support is responsible for that one and we know how to fix it.

> -----Oorspronkelijk bericht-----
> Van: graj...@seznam.cz
> [mailto:project...@googlegroups.com] Namens Maaartin-1
> Verzonden: 22 November 2010 14:30
> Aan: project...@googlegroups.com
> Onderwerp: Re: [project lombok] Re: The new features
> announced at Devoxx.
>

Roel Spilker

unread,
Nov 22, 2010, 9:56:09 AM11/22/10
to project...@googlegroups.com
I agree that for some the val context sensitive keyword is a bridge too far. That said, as you suggested, you can forbid the use of it. Then again, if people do use it and are happy with it, we might start a JSR and have customer data to support it. That would be great, wouldn't it?
 
We are not against standards. Actually, Lombok is about moving the language forwards. The ARM blocks is one future construct that has alreay been scheduled for java7, and now they are talking about @Data functionality for java9. If all Lombok transformations are embedded in the language, our job is done. But don't worry, we will find some new boilerplate to bust.
 


Van: jac...@gmail.com [mailto:project...@googlegroups.com] Namens Jacek Furmankiewicz
Verzonden: 22 November 2010 15:15

Aan: project...@googlegroups.com
Onderwerp: Re: [project lombok] Re: The new features announced at Devoxx.
--

Maaartin-1

unread,
Nov 22, 2010, 10:07:54 AM11/22/10
to project...@googlegroups.com
On 10-11-22 15:15, Jacek Furmankiewicz wrote:
> New keywords that did no go through any JSR or will be a mystery to any
> brand new developer joining a project
> with that code in it are a bridge too far IMHO.

It takes ages, until something happens with JSR. Just look at project
coin with it's diamond operator. It's not as good as val and still not
part of Java.

Actually, I hate forking Java, but not moving anywhere is even worse. I
hope that some day Lombok gets integrated into JDK.

> When that version of Lombok comes I will forbid anyone in my group from
> using non-standard keywords such as "val".

This just makes no sense. A source code using Lombok either doesn't
compile without the agent (e.g., when using @Getter) or it does but
doesn't work (e.g., when using @Cleanup or @EqualsAndHashCode). The
situation with "val" is no different.

The functionality is great and there's no meaningful way how to express
it using annotations, so what? You could use something like

@Val List l = new ArrayList<? extends List<String>>();

but you'd just make it longer.

Maaartin-1

unread,
Nov 22, 2010, 12:20:55 PM11/22/10
to project...@googlegroups.com
On 10-11-22 15:50, Roel Spilker wrote:
> Just some quick answers:
>
> There are known problems with Cleanup. We already know a way to solve those, but didn't have time to implement them.

OK.

> To get an Eclipse project, just run "ant eclipse"

Thx, it works nice.

> About the toURL, we probably should add the @SuppressWarnings("all") to the generated methods.

But don't do it without also deprecating the delegating methods. I could
imagine to make it configurable, but simply copying the deprecation (and
suppressing warning on it) should be fine.

> The "assign to new field" does not work well with the @Synchronized annotation.
> Do you use that one?
> If not, the new @Delegate support is responsible for that one
> and we know how to fix it.

It was @Delegate.

There's one more serious problem: Simple rename (without refactoring)
doesn't work (Internal Error,
org.eclipse.jface.text.BadLocationException: ...)

This may be relating to other problems:
- only the first letter of a method gets underlined
- occurrences (ctrl-shift-u) works iff I mark only the first letter of a
method

All three problems happen always in all files, even in such not using
any Lombok features at all.

Reinier Zwitserloot

unread,
Nov 22, 2010, 4:35:37 PM11/22/10
to Project Lombok
Replies inline...

On Nov 21, 12:30 pm, Maaartin-1 <grajc...@seznam.cz> wrote:
> I agree that the diamond operator is quite weak. Actually, I don't
> grasp, why simple
> List<String> x = new ArrayList();
> without any diamond shouldn't suffice.

I don't really get that either. Sure, if you write something like: new
ArrayList().add(...), then the ArrayList has to remain a raw type or
you'd break backwards compatibility. But in that exact example, the
compiler can rather easily figure out that the warning it would
generate is completely pointless. Possibly there's more reason for
this if the constructor takes arguments that themselves use the type
arguments, though I believe there too you can apply some intelligence
and figure out all is well.

> Of course not, this would get too far. If I needed something like this,
> I'd declare it explicitly.

If we would write var, surely we'd indeed try to keep it simple like
that and not attempt to infer the common supertype when multiple
assignments are involved. However, this is still a somewhat unwanted
surprise - and we try not to include too many surprises. Maybe we'll
revisit this later.

>
> That's true, but this is no worse than renaming a field or adding a new
> one. I don't think I'd change
> private val x = new ArrayList<String>();
> to
> private val x = new LinkedList<String>();
> any more often then changing something else. Quite the opposite, it's
> very improbable (especially for a LinkedList, which is nearly always
> slower; you'd have to try hard to find a use case where it wins).

Hey, someone else that correctly ascribes to the maxim that any usage
of LinkedList is 99.99% certain to be a code smell ;)

Nevertheless, I don't agree with your argument here. The type of a
field is part of a signature. It's initialization is not. This is a
very important distinction; I'll change the initialization of a field
without a moment's hesitation about changing signatures, but with
'val' on fields that would change.

>
> So, I'd suggest to extend val to final fields initialized in the
> declaration. Nothing more, as it could get too complicated. Nothing
> less, for reasons given above.

Right; if we revisit this, the initialization would be mandatory.

>
> I don't understand this. The keyword "val" implies final, so what do you
> mean?
>

I meant 'private', not 'final'. Whoops.

>
> Agreed, making val well-known is the best possibility. You could misuse
> the package declaration like
> package (lombok) com.example;
> which could be used for all incompatible changes, e.g.,
> package 7 com.example;
> could mean that the source code needs jdk7 at least.

Can't do that. Lombok doesn't get to run unless the parser delivers an
error-free AST. This means the code has make syntactic sense.
Semantically it can be pure gobbledygook. For example, 'val' works
because its technically legal java code even without lombok: You're
declaring a local variable of type 'val'. Now in practice you'll never
write a class named 'val' (especially with the lower-case v), but
according to the JLS you can technically do that. Then lombok rewrites
it to the right type before the compiler moves on with further stages.

package 7 com.example;

does not parse.

We'd love to see (and actively campaigned for it in Project Coin, but
it was universally bashed for some reason except by Roel, myself, and
Howard Lovatt) a "source" keyword feature to indicate the source
version of java (the same thing you pass in the -source param to
javac). But, alas, it doesn't exist. Hence, it wouldn't parse, and
thus we can't use it.

Maaartin-1

unread,
Nov 22, 2010, 7:53:25 PM11/22/10
to project...@googlegroups.com
On 10-11-22 22:35, Reinier Zwitserloot wrote:
> Replies inline...
Me too...

First let me know, that "4ba4a37 Cleaned up the patch fixes in eclipse
for finding end of identifier ..." really helped. I'm using now 4ded143
and many things works fine.

Delegating to instances of my own classes doesn't work nicely. I get
their methods proposed, but they get marked red as undefined, and things
like extract local variable don't work with them. However, they work
(the program runs and they get called). The problem appears with
delegating to instances of my own classes, no matter if in the same or
in a different project. More precisely, it seems to concern all classes
except for those in jar files.

There's another problem:
http://dl.dropbox.com/u/4971686/101123/LombokInjectorDemo.java
I get the message "T cannot be resolved to a type", but only if I
delegate to another member coming after the injector like in the
example. When I swap Injector and String, it works.

@PrintAST does nothing, at least I never saw any output. But maybe I
just don't know where to look for it?

Continued inline...

> On Nov 21, 12:30 pm, Maaartin-1 <grajc...@seznam.cz> wrote:
>> I agree that the diamond operator is quite weak. Actually, I don't
>> grasp, why simple
>> List<String> x = new ArrayList();
>> without any diamond shouldn't suffice.
>
> I don't really get that either. Sure, if you write something like: new
> ArrayList().add(...), then the ArrayList has to remain a raw type or
> you'd break backwards compatibility. But in that exact example, the
> compiler can rather easily figure out that the warning it would
> generate is completely pointless. Possibly there's more reason for
> this if the constructor takes arguments that themselves use the type
> arguments, though I believe there too you can apply some intelligence
> and figure out all is well.

I can't find a good example for this, but it seems to me, that the only
thing necessary is to suppress the warning whenever the LHS has all type
parameters and the RHS not. Eclipse can infer the type arguments, so it
should be able to shut up, too.

> If we would write var, surely we'd indeed try to keep it simple like
> that and not attempt to infer the common supertype when multiple
> assignments are involved. However, this is still a somewhat unwanted
> surprise - and we try not to include too many surprises. Maybe we'll
> revisit this later.

I hope so. Most of my variables are final, most of my non-final
variables are loop counters or simple types, so the gain wouldn't be so
high. However, I don't see any surprise there, I just read
var l = new ArrayList<? extends Set<String>>();
as a shortcut for the terribly long expression and nothing else. Just
the non-final pendant to val, with no type inference and nothing to
think about.

> Hey, someone else that correctly ascribes to the maxim that any usage
> of LinkedList is 99.99% certain to be a code smell ;)
>
> Nevertheless, I don't agree with your argument here. The type of a
> field is part of a signature. It's initialization is not. This is a
> very important distinction; I'll change the initialization of a field
> without a moment's hesitation about changing signatures, but with
> 'val' on fields that would change.

Sure, but...

1. With only "val" on the LHS it's clear that the type stands on the
RHS. However, changing the only type information in the row should make
it clear that you're changing the type of the variable.

2. Would you hesitate to add a static initializer to a class? AFAIK, it
means nothing important to the class signature, often it's just an
alternate way for initializing static variables. However, it changes the
SUID, too.
http://download.oracle.com/javase/1.5.0/docs/guide/serialization/spec/class.html#4100

3. Any improvement and any tool can and will lead to a problem for
somebody one day. The probability and the weight of this problem is to
be compared to the gain obtained. For me the probability is very low and
the weight too (such errors should be caught by tests anyway), and the
gain is not small.

4. Even so, this problem applies to serializable classes only. So you
may just let it work for all others. I'm afraid, you can't find out if a
class is "indirectly" serializable due to inheritance without
resolution, can you?

>> I don't understand this. The keyword "val" implies final, so what do you
>> mean?
>
> I meant 'private', not 'final'. Whoops.

I nearly started arguing against this restriction too, but there are not
enough non-private fields in my code to justify it. :)

>> package (lombok) com.example;


>
> Can't do that. Lombok doesn't get to run unless the parser delivers an
> error-free AST. This means the code has make syntactic sense.

I see. Is there a chance to overcome this restriction in the future
somehow? I'm asking because of potential syntax extensions done by Lombok.

> Semantically it can be pure gobbledygook. For example, 'val' works
> because its technically legal java code even without lombok: You're
> declaring a local variable of type 'val'. Now in practice you'll never
> write a class named 'val' (especially with the lower-case v), but
> according to the JLS you can technically do that. Then lombok rewrites
> it to the right type before the compiler moves on with further stages.

That's really funny, actually it's obvious but I never thought about it.

> package 7 com.example;
>
> does not parse.

Maybe in JDK123 they'll accept an idea like that.

> We'd love to see (and actively campaigned for it in Project Coin, but
> it was universally bashed for some reason except by Roel, myself, and
> Howard Lovatt) a "source" keyword feature to indicate the source
> version of java (the same thing you pass in the -source param to
> javac). But, alas, it doesn't exist. Hence, it wouldn't parse, and
> thus we can't use it.

I'd really prefer the discreet "7" in the package declaration to a new
keyword. However, something like this should have ever existed,
specifying the version on the command line is pure non-sense, since the
version is a property of the source file and nothing else. It's much
more like compiling C and C++ than like enabling assertions. There could
even be source trees containing a mixture of 1.4 and 1.5 sources (using
"enum" as an id and as a keyword, respectively), which would work
perfectly with version specification in the source file, but couldn't be
compiled using -source at all. I know, this example is quite improbable,
but things should be done right.

Regards, Maaartin.

Reinier Zwitserloot

unread,
Nov 22, 2010, 7:54:01 PM11/22/10
to Project Lombok
Some minor collateral damage in the more exotic eclipse features when
using lombok is more or less acceptable to us (we'd love to fix them
but aren't going to hold back a release for it), but if the mere
installation of lombok into eclipse causes features to break on files
with no lombok in them, that's bad.

I cannot reproduce the problem of "rename doesn't work, even in files
that don't have any lombok stuff in it". I don't know what you mean
with "only the first letter of a method gets underlined" - what kind
of eclipse feature underlines methods? Or did you change eclipse
settings to change the formatting of something or other to underline?

Nevertheless I'm virtually positive I know what we're doing wrong,
even though I can't reproduce it. Does this edge build I just put
online fix it?

http://projectlombok.org/download-edge.html


Many of the other problems with @Delegate is because I put the
finishing touches on it half-drunk during the night at Barcamp London
8 ;) - I need to replace the inject method mechanism with our standard
one which fixes a bunch of issues.

Reinier Zwitserloot

unread,
Nov 22, 2010, 11:23:43 PM11/22/10
to project...@googlegroups.com
Yeah, looks like our type copy code screws up on something there with the <T> stuff in com.google.guice.Injector.

'val' is reasonably stable and has a bunch of tests for it, @Delegate isn't so lucky, and as you can see we really need to cover a heck of a lot more bases before we can push this out in a non-beta release. Heck, including it in that beta was overzealous. Whoops.

Thanks for the detailed reporting, I'll make sure we cover all of these in the tests.


@PrintAST prints to System.out. When using it in eclipse, this basically means you can't see it at all, unless you go out of your way to start eclipse in a way that you get a text console. It takes a file as parameter as an alternative, though to use it, I strongly recommend you comment out the PrintAST line, write it in full, then uncomment it. Eclipse reparses as you type, which means lombok will attempt to create a bajillion files (If you're type "/foo/bar", it'll create /f, /fo, /foo, /foo/b, /foo/ba, and /foo/bar if you type slow!). It's an internal debug feature.

In eclipse/ecj, @PrintAST will not work on resolution-based stuff such as val and @Delegate, though. At least, not right now.


The reason for 'val' intentionally not working in fields is not JUST based on serialization. It also breaks class compatibility, which means compiling one class but not recompiling another results in FieldNotFoundErrors if the erased type of the field changes. This is IMO a much bigger issue than serialization, though it has lots in common with it (if you break a field type, you definitely also break serialization). Also, implementing 'val' for fields is significantly more complicated ;P. It also opens the door to some catch-22 situations:

public class HeadAsplodes {
    static var x = HeadAsplodes2.y;
}

public class HeadAsplodes2 {
    static var y = HeadAsplodes.x;
}

Seems like a crappy and mostly irrelevant academic distinction, but there's a deeper problem here: Java is resolved in phases. Phase 1 determines the names of types and the signatures of these types' members. Phase 2 does all the rest. If we added 'val' support to fields, we'd need to do some phase 2 stuff (eval expressions) during phase 1. I'm fairly sure both javac and ecj are very much not designed to do that. So it's partly motivated by laziness: Adding it would be lots of effort, most likely.

Still, thanks for pressing the issue. I realize I hadn't fully formed this thought until you brought it up.


We've been dreaming of a Lombok (and this dream has a release name, "Flying Turtle") which just takes over, completely, the job of parsing. It would normalize error messages across all environments (IntelliJ, Eclipse, NetBeans, javac), gives us unlimited freedom to add whatever we want, would completely normalize all AST modifications (i.e. only need to write to 1 nice documented API instead of three times, to javac's and ecj's internal messy APIs, and IntelliJ's messiness-to-be-determined API), and gives us a chance at fixing the at times abhorrent recovery of ecj and javac. We even have the parser built to do it: It's the lombok.ast project. It's a bit too slow still, but close enough that I think we can get there.

However, doing so is a very very drastic step, and would also require starting javac with a -J-agent parameter, which is almost a show-stopping drawback. So, in the short and mid-term, no, I don't think we'll get there.



 --Reinier Zwitserloot



Stephen Haberman

unread,
Nov 23, 2010, 12:32:18 AM11/23/10
to project...@googlegroups.com

> We've been dreaming of a Lombok (and this dream has a release name, "Flying
> Turtle") which just takes over, completely, the job of parsing.

That sounds really intriguing. Especially if it made user-driven AST
meta programming easier.

Out of curiosity, if you're doing all of the parsing, it is worth using
the rest of the javac/ecj compiler tool chains?

Seems like writing your own would be easier than integrating with 2-3
internal compiler APIs. Though I suppose your goal is to keep all of
the JDT UI awesomeness and not have to reinvent that?

- Stephen

Reinier Zwitserloot

unread,
Nov 23, 2010, 12:52:27 AM11/23/10
to project...@googlegroups.com
Yes. Parsing is fairly difficult (and by far the slowest of the compile process), but resolution is even more complicated (unfortunately, resolving things leads to cool new features like 'val' and '@Delegate', so by releasing these things, Flying Turtle is further away now), and desugaring and actually compiling similarly complex. We can already turn out AST into eclipse/javac AST _perfectly_ (exactly equal to what javac/ecj would have parsed, even down to the positions), so we can then let these tools do the rest. All layers are used by their respective tools so we HAVE to convert it back to the native AST/binding API anyway.

So, yeah, we'll keep using the underlying tools. Probably we'll parse it ourselves, do some rewriting of the AST, turn it into a javac/eclipse AST, give it to javac/eclipse to resolve, hook into the middle of this process to pick up resolution work and attach these to our AST, run more lombok transformers, somehow figure out what they are changing and transfer these changes back to the host AST, and then let the rest of the process run all on the native platform, then hook in as the bytecode is written to disk to run the post compile hooks.

If you need to introduce new syntax but to figure out what thats supposed to do you need resolution, you'd need to write two steps: First convert the new syntax into something that can be turned into a Javac/ecj AST (i.e. vanilla java, as convoluted as you want it to be though), then write a second transformer that scans for this converted AST and then fixes it into the end result using the associated resolution info.

 --Reinier Zwitserloot




--

Stephen Haberman

unread,
Nov 23, 2010, 11:40:15 AM11/23/10
to project...@googlegroups.com

> I cannot reproduce the problem of "rename doesn't work, even in files
> that don't have any lombok stuff in it". I don't know what you mean
> with "only the first letter of a method gets underlined" - what kind
> of eclipse feature underlines methods?

I was seeing the same sort of weirdness where the first letter of all of
my method names was a different color than the rest of the characters in
the method name. Rename was also not working.

Updating to head fixed both problems. Thanks!

- Stephen


Maaartin-1

unread,
Nov 23, 2010, 1:51:33 PM11/23/10
to project...@googlegroups.com
On 10-11-23 01:54, Reinier Zwitserloot wrote:
> Some minor collateral damage in the more exotic eclipse features when
> using lombok is more or less acceptable to us (we'd love to fix them
> but aren't going to hold back a release for it), but if the mere
> installation of lombok into eclipse causes features to break on files
> with no lombok in them, that's bad.

I only now noticed this posting of yours. It was really bad, but the fix
helped (as I already wrote).

> I cannot reproduce the problem of "rename doesn't work, even in files
> that don't have any lombok stuff in it". I don't know what you mean
> with "only the first letter of a method gets underlined" - what kind
> of eclipse feature underlines methods? Or did you change eclipse
> settings to change the formatting of something or other to underline?

I meant the method name, it's bold and underlined with my settings. I'm
not sure if it is the original setting or not, I've been using it for
years this way.
http://dl.dropbox.com/u/4971686/101123/eclipse-underline.png
Instead of "main", only "m" was bold and underlined.

> Nevertheless I'm virtually positive I know what we're doing wrong,
> even though I can't reproduce it. Does this edge build I just put
> online fix it?
>
> http://projectlombok.org/download-edge.html

I didn't try it, I compiled 4ded143 instead, works fine.

> Many of the other problems with @Delegate is because I put the
> finishing touches on it half-drunk during the night at Barcamp London
> 8 ;) - I need to replace the inject method mechanism with our standard
> one which fixes a bunch of issues.

Drinking may not make the work better but it surely makes it more fun.

Maaartin-1

unread,
Nov 23, 2010, 2:59:05 PM11/23/10
to project...@googlegroups.com
On 10-11-23 05:23, Reinier Zwitserloot wrote:
> Yeah, looks like our type copy code screws up on something there with
> the <T> stuff in com.google.guice.Injector.
>
> 'val' is reasonably stable and has a bunch of tests for it, @Delegate
> isn't so lucky, and as you can see we really need to cover a heck of a
> lot more bases before we can push this out in a non-beta release. Heck,
> including it in that beta was overzealous. Whoops.
>
> Thanks for the detailed reporting, I'll make sure we cover all of these
> in the tests.

Thanks for the good work.

> @PrintAST prints to System.out. When using it in eclipse, this basically
> means you can't see it at all, unless you go out of your way to start
> eclipse in a way that you get a text console.

I thought starting it from console with parameters -console -consoleLog
-debug (whatever they mean, they gathered somehow in my eclipse.ini)
should help, but it didn't. With the stupid OS parody I'm using,
everything is possible.

> It takes a file as
> parameter as an alternative, though to use it, I strongly recommend you

This works.

> comment out the PrintAST line, write it in full, then uncomment it.
> Eclipse reparses as you type, which means lombok will attempt to create
> a bajillion files (If you're type "/foo/bar", it'll create /f, /fo,
> /foo, /foo/b, /foo/ba, and /foo/bar if you type slow!). It's an internal
> debug feature.

I'd like to learn a bit about the internals.

> In eclipse/ecj, @PrintAST will not work on resolution-based stuff such
> as val and @Delegate, though. At least, not right now.
>
> The reason for 'val' intentionally not working in fields is not JUST
> based on serialization. It also breaks class compatibility, which means
> compiling one class but not recompiling another results in
> FieldNotFoundErrors if the erased type of the field changes.

You mean lava.lang.NoSuchFieldError, right? But it only happens, when
the field gets actually accessed from outside of the class, so it
doesn't apply to private fields, does it? I've just tested it using
javac, untouched fields seem to be no problem.

> This is IMO
> a much bigger issue than serialization, though it has lots in common
> with it (if you break a field type, you definitely also break
> serialization). Also, implementing 'val' for fields is significantly
> more complicated ;P. It also opens the door to some catch-22 situations:
>
> public class HeadAsplodes {
> static var x = HeadAsplodes2.y;
> }
>
> public class HeadAsplodes2 {
> static var y = HeadAsplodes.x;
> }

Not really. This is about just the same as

public class A {
final static int x = B.y * 2 / 3 + 14;
}
public class B {
final static int y = A.x * 5 / 7 + 12;
}

The only right answer is A.x = B.y = 42, but you can never get it;
moreover the result depends on what class gets loaded first. So you
should not require doing any better for type inference.

There are simple and sane rules for such initialization games in Java,
which IMHO could be extended to val. Restricting to private fields
eliminates most of the problems, doesn't it? Restricting to references
to fields defined earlier in the same class could eliminate the rest.

Or maybe a bit more generous:
val a = "a";
val b = d; // works since it references a fixed type
val c = b; // works since it references a type defined above
val d = "d";
But I don't think it's necessary. Raising a compiler error for
everything leading to any complication should suffice for now. So you
could start with val restricted to private fields defined using a fixed
type, and possibly loosen the rules later.

> Seems like a crappy and mostly irrelevant academic distinction, but
> there's a deeper problem here: Java is resolved in phases. Phase 1
> determines the names of types and the signatures of these types'
> members. Phase 2 does all the rest. If we added 'val' support to fields,
> we'd need to do some phase 2 stuff (eval expressions) during phase 1.
> I'm fairly sure both javac and ecj are very much not designed to do
> that. So it's partly motivated by laziness: Adding it would be lots of
> effort, most likely.

I can't tell. Is that true even when assuming the strictest
restrictions? No matter how the rules should be, it would cover the
majority of use cases.

> Still, thanks for pressing the issue. I realize I hadn't fully formed
> this thought until you brought it up.
>
> We've been dreaming of a Lombok (and this dream has a release name,
> "Flying Turtle") which just takes over, completely, the job of parsing.
> It would normalize error messages across all environments (IntelliJ,
> Eclipse, NetBeans, javac), gives us unlimited freedom to add whatever we
> want, would completely normalize all AST modifications (i.e. only need
> to write to 1 nice documented API instead of three times, to javac's and
> ecj's internal messy APIs, and IntelliJ's messiness-to-be-determined
> API), and gives us a chance at fixing the at times abhorrent recovery of
> ecj and javac. We even have the parser built to do it: It's the
> lombok.ast project. It's a bit too slow still, but close enough that I
> think we can get there.
>
> However, doing so is a very very drastic step, and would also require
> starting javac with a -J-agent parameter, which is almost a
> show-stopping drawback. So, in the short and mid-term, no, I don't think

My eclipse starts already with
-javaagent:lombok.jar -Xbootclasspath/a:lombok.jar
so what's the difference???

Reinier Zwitserloot

unread,
Nov 23, 2010, 11:49:38 PM11/23/10
to Project Lombok
For eclipse the javaagent doesn't matter as that's already how lombok
works there, but for javac (and maven and ant and many other command
line tools), switching from the current annotation processor design to
an agent is a major drawback.

val for fields is not going to happen in the short term. We've got
more interesting boilerplate to bust, and while no doubt we can
probably get something working, that whole mixing of phase 1 and phase
2 is bound to lead to weird quirks that will be extremely difficult to
debug. As I said, mixing phases is not something javac and ecj were
designed to do. If we hack it in, who knows what's going to break? We
don't know javac and ecj quite that inside and out yet to
authoritatively say we don't introduce a potential serious issue by
trying.

Stephen Haberman

unread,
Nov 24, 2010, 12:39:40 AM11/24/10
to project...@googlegroups.com

> but for javac (and maven and ant and many other command line tools)

More comments from the peanut gallery, but your devotion to lombok
working across multiple compilers/IDEs both impresses and surprises me.

If it was me, I'd be terribly tempted to:

1) Only support Eclipse, as then you get both an IDE and a headless
compiler in one go.

(Rationale: if users are willing to couple their build to a lombok
annotation processor that hacks `com.sun.*` APIs, it's not that much
farther to just using a different compiler like ecj all together.
Though perhaps it's easier to sneak by politically as an <quote> APT
</unquote> processor. :-)

2) Fork the Eclipse codebase instead of donkey patching.

(Same rationale, users are coupling their project to your enhanced
Eclipse, what difference is a java-agent argument vs. a separate
install. Though, again, I imagine it's easier to slip by saying "oh,
just run this java -jar" vs. "we're using 'Lombok Eclipse' (TM) now".)

So, I definitely respect the approach you guys are taking, as I agree it
will lead to wider adoption of lombok than an Eclipse-only version
would.

It just seems like you aren't making it any easier on yourselves. :-)

(Sorry if I'm rehashing old points that have already been discussed on
the mailing list.)

- Stephen

Petr Jiricka

unread,
Nov 24, 2010, 10:35:10 AM11/24/10
to project...@googlegroups.com
On Nov 24, 2010, at 6:39 AM, Stephen Haberman wrote:
>
> If it was me, I'd be terribly tempted to:
>
> 1) Only support Eclipse, as then you get both an IDE and a headless
> compiler in one go.

I don't quite understand this. Are you saying that people should not have Ant scripts or Maven pom files and only use Eclipse to build, or are you saying that people should somehow hack Ant/Maven to use the Eclipse compiler instead of javac? Not having a scripted build environment sounds really scary to me.

Petr

Stephen Haberman

unread,
Nov 24, 2010, 12:46:59 PM11/24/10
to project...@googlegroups.com

> or are you saying that people should somehow hack Ant/Maven to use the
> Eclipse compiler instead of javac?

Yes, although using the Eclipse batch compiler is fairly straight
forward from ant:

http://emacsblog.org/2007/02/13/emacs-jdee-ant-and-the-eclipse-java-compiler/

I imagine the same thing is true for maven.

> Not having a scripted build environment sounds really scary to me.

Agreed! That is not what I was proposing. :-)

- Stephen

Reinier Zwitserloot

unread,
Nov 24, 2010, 1:52:39 PM11/24/10
to project...@googlegroups.com
Don't worry folks. We did our little stunt at devoxx about IntelliJ support for a reason :) - We don't intend to become an eclipse/ecj only tool.

Yes, this makes life hard for us.

 --Reinier Zwitserloot



xcemus

unread,
Jan 8, 2011, 5:35:05 AM1/8/11
to Project Lombok
On 20 lis 2010, 07:43, Reinier Zwitserloot <reini...@gmail.com> wrote:

> ...... and "@Delegate" doesn't work
> in netbeans or javac. We're working on it.

Hi guys, you are having amazing project. I am really amazed. But I
would like to know how does it look with the @Delegate in Netbeans. I
haven't found a reported issue for it but still it seems to be not
working. Thanks a lot

rjee

unread,
Jan 8, 2011, 6:29:48 AM1/8/11
to Project Lombok

We haven't added an explicit issue for netbeans support, thought we
are looking into it. We cannot confirm that it will be in the 0.10.0
gold, but we're going to give it our best shot.
Reply all
Reply to author
Forward
0 new messages