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
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.
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
>
>
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.
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.
>
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.
--
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.
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.
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.
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
--
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
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.
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???
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
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
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