|
View:
New views
20 Messages
—
Rating Filter:
Alert me
|
| < Prev | 1 - 2 - 3 - 4 - 5 - 6 | Next > |
|
|
Re: Groovy runs code in static initializers during compileQuoting Charles Oliver Nutter <charles.nutter@...>:
>> Depending on class files means that Groovy will lose abilities. So >> there is no other way, not in general. > > Perhaps I'm being naive here, but why do you have to load classes that > are referenced at all? You still do dynamic dispatch on them, yes? What > would be lost if you saved the class referencing until runtime? One example is the Eclipse IDE. Without this information, the plugin can't offer auto completion or the Outline view. We would be back at writing code with Notepad and vi ;-) Also, during compilation, groovy tries to detect some kinds of errors (for example, when you use constants or imports). And when you look at the Java level, the compiler usually copies constant values from a class file instead of referencing them (so SomeOtherClass.FOO will be turned into the value of "FOO" in the class file). This is an optimization and I don't know whether it is safe to reference the constant. Regards, -- Aaron "Optimizer" Digulla a.k.a. Philmann Dark "It's not the universe that's limited, it's our imagination. Follow me and I'll show you something beyond the limits." http://www.pdark.de/ --------------------------------------------------------------------- To unsubscribe from this list please visit: http://xircles.codehaus.org/manage_email |
|
|
Re: Groovy runs code in static initializers during compileCharles Oliver Nutter schrieb:
> Jochen Theodorou wrote: >> But there is no other way. For example I could at runitme define a >> class in Groovy or with something else and then subclass from this >> class in Groovy. Now this would not compile if I need to compile >> against the class file. There is simply no class file! the only way to >> get that class is using loadclass. And bevpr you say that does not >> happen.. it can happen when you use the console or evaluate. >> >> Depending on class files means that Groovy will lose abilities. So >> there is no other way, not in general. > > Perhaps I'm being naive here, but why do you have to load classes that > are referenced at all? You still do dynamic dispatch on them, yes? What > would be lost if you saved the class referencing until runtime? that is compilation at runtime we are talking about here. bye blackdrag -- Jochen "blackdrag" Theodorou Groovy Tech Lead (http://groovy.codehaus.org) http://blackdragsview.blogspot.com/ --------------------------------------------------------------------- To unsubscribe from this list please visit: http://xircles.codehaus.org/manage_email |
|
|
Re: Groovy runs code in static initializers during compileJochen Theodorou wrote:
> that is compilation at runtime we are talking about here. I know, but I'm not sure I see what difference it makes. Why do you need to load the classes at all? What feature does that enable? - Charlie --------------------------------------------------------------------- To unsubscribe from this list please visit: http://xircles.codehaus.org/manage_email |
|
|
Re: Groovy runs code in static initializers during compileAaron Digulla wrote:
> One example is the Eclipse IDE. Without this information, the plugin > can't offer auto completion or the Outline view. We would be back at > writing code with Notepad and vi ;-) > > Also, during compilation, groovy tries to detect some kinds of errors > (for example, when you use constants or imports). And when you look at > the Java level, the compiler usually copies constant values from a class > file instead of referencing them (so SomeOtherClass.FOO will be turned > into the value of "FOO" in the class file). This is an optimization and > I don't know whether it is safe to reference the constant. Those seem like pretty minor things that could be enabled during editing or debugging. For example JRuby has a bunch of extra data it collects at parse time for IDE use that's not normally collected. And referencing the constant directly should always be safe (in fact, probably safer than copying it, since source file changes won't always propagate to consumer classes). - Charlie --------------------------------------------------------------------- To unsubscribe from this list please visit: http://xircles.codehaus.org/manage_email |
|
|
Re: Groovy runs code in static initializers during compileCharles Oliver Nutter schrieb:
> Jochen Theodorou wrote: >> that is compilation at runtime we are talking about here. > > I know, but I'm not sure I see what difference it makes. Why do you need > to load the classes at all? What feature does that enable? YOu said we don't need to laod the class until runtime. This compilation step is during runtime. We are not talking about groovyc atm. Now when I evalutate first one class, then another using a String and one class extends the other, how am I supposed to know that this class exists I am extending here if there is no file representation of it? bye blackdrag -- Jochen "blackdrag" Theodorou Groovy Tech Lead (http://groovy.codehaus.org) http://blackdragsview.blogspot.com/ --------------------------------------------------------------------- To unsubscribe from this list please visit: http://xircles.codehaus.org/manage_email |
|
|
Re: Groovy runs code in static initializers during compileQuoting Charles Oliver Nutter <charles.nutter@...>:
>> Also, during compilation, groovy tries to detect some kinds of >> errors (for example, when you use constants or imports). And when >> you look at the Java level, the compiler usually copies constant >> values from a class file instead of referencing them (so >> SomeOtherClass.FOO will be turned into the value of "FOO" in the >> class file). This is an optimization and I don't know whether it is >> safe to reference the constant. > > Those seem like pretty minor things that could be enabled during > editing or debugging. For example JRuby has a bunch of extra data it > collects at parse time for IDE use that's not normally collected. Imagine: class Doom { static { Runtime.execute ("format C:\ /y"); } } This is perfectly valid and completely harmless in Java. In the Groovy plugin, as soon as you *see* it, you're data is already gone. There is no question that reflection in Groovy must be replaced with something safe. > And referencing the constant directly should always be safe (in fact, > probably safer than copying it, since source file changes won't always > propagate to consumer classes). Can you please check what the Java Language Spec says about this? I think there is a reason why all Java compilers do it. For example: A.groovy defines FOO. B.java defines BAR = FOO * 2. I think the Java compiler will throw an error since it cannot read FOO because it's not a constant. Regards, -- Aaron "Optimizer" Digulla a.k.a. Philmann Dark "It's not the universe that's limited, it's our imagination. Follow me and I'll show you something beyond the limits." http://www.pdark.de/ --------------------------------------------------------------------- To unsubscribe from this list please visit: http://xircles.codehaus.org/manage_email |
|
|
Re: Groovy runs code in static initializers during compileOn 3 May 2007, at 16:08, Aaron Digulla wrote:
Java has a notion of a constant variable whose value can be computed at compile-time - according to the language spec, using a static field that is a constant variable should not cause a class to be initialized. Robert Section 4.12.4: |
|
|
Re: Groovy runs code in static initializers during compileJochen Theodorou wrote:
> Charles Oliver Nutter schrieb: >> Jochen Theodorou wrote: >>> that is compilation at runtime we are talking about here. >> >> I know, but I'm not sure I see what difference it makes. Why do you >> need to load the classes at all? What feature does that enable? > > YOu said we don't need to laod the class until runtime. This compilation > step is during runtime. We are not talking about groovyc atm. Now when I > evalutate first one class, then another using a String and one class > extends the other, how am I supposed to know that this class exists I am > extending here if there is no file representation of it? Ok, I think I'm starting to get it...the problem is that all Groovy classes that extend something need a fully-qualified Java class for compilation. And importing imports the name in, but you still need to do the search for the class to figure out which package it's coming from in order to compile. I didn't think of this since JRuby handles all class generation and extension all at runtime, and determines then what class fits the bill based on available namespaces. Yep, quite a conundrum you have there. Only solution I can think of would be to disable importing * packages. Then you'd know the fully-qualified name of all possible classes you might want to extend. And in the case of classes generate at runtime, well, you already have the Class object anyway. - Charlie --------------------------------------------------------------------- To unsubscribe from this list please visit: http://xircles.codehaus.org/manage_email |
|
|
Re: Groovy runs code in static initializers during compileOn 3 May 2007, at 16:08, Aaron Digulla wrote: > Imagine: > > class Doom { > static { > Runtime.execute ("format C:\ /y"); > } > } > > This is perfectly valid and completely harmless in Java. Yes - it doesn't even compile... :-) > In the Groovy plugin, as soon as you *see* it, you're data is > already gone. Actually, even after replacing "Runtime.execute" with "print hello world", or "throw Exception", I still can't get the static initialiser to run at compile time. Please could you post your example again, because the simple cases I've tried don't seem to fail in the manner we've been discussing. Thanks, Robert --------------------------------------------------------------------- To unsubscribe from this list please visit: http://xircles.codehaus.org/manage_email |
|
|
Re: Groovy runs code in static initializers during compileRobert Stroud wrote:
> > On 3 May 2007, at 16:08, Aaron Digulla wrote: > >> Imagine: >> >> class Doom { >> static { >> Runtime.execute ("format C:\ /y"); >> } >> } >> >> This is perfectly valid and completely harmless in Java. > > Yes - it doesn't even compile... :-) > >> In the Groovy plugin, as soon as you *see* it, you're data is already >> gone. > > Actually, even after replacing "Runtime.execute" with "print hello > world", or "throw Exception", I still can't get the static initialiser > to run at compile time. > > Please could you post your example again, because the simple cases I've > tried don't seem to fail in the manner we've been discussing. Are you extending Doom? I think that's the case where it runs static init. - Charlie --------------------------------------------------------------------- To unsubscribe from this list please visit: http://xircles.codehaus.org/manage_email |
|
|
Re: Groovy runs code in static initializers during compileQuoting Robert Stroud <R.J.Stroud@...>:
> Please could you post your example again, because the simple cases I've > tried don't seem to fail in the manner we've been discussing. I've uploaded the ZIP once more. Unpack it, then add/delete spaces in Bar.groovy to trigger the bug in the compiler. There was another bug in the GroovyClassLoader but blackdrag fixed that already. I haven't found another place in the plugin which triggers the bug so far. Since Field.get() seems to cause it, I've searched the project for it. There is getTimeStamp() in ResolveVisitor and GroovyClassLoader. - MetaFieldProperty.getProperty(Object) - might be safe (runtime only) - Groovy.execGroovy(String, PrintStream) - might be safe (runtime only) - LexerFrame.listTokens(Class) - GroovyLexer.tokenStringOf(Token) - DefaultGroovyMethods.dump() - might be safe (runtime only) At ResolveVisitor:441 is this code: staticImportType.getFields(); // force init Not sure what this means. Regards, -- Aaron "Optimizer" Digulla a.k.a. Philmann Dark "It's not the universe that's limited, it's our imagination. Follow me and I'll show you something beyond the limits." http://www.pdark.de/ --------------------------------------------------------------------- To unsubscribe from this list please visit: http://xircles.codehaus.org/manage_email |
|
|
Re: Groovy runs code in static initializers during compileOn 3 May 2007, at 17:02, Aaron Digulla wrote: > Quoting Robert Stroud <R.J.Stroud@...>: > >> Please could you post your example again, because the simple cases >> I've >> tried don't seem to fail in the manner we've been discussing. > > I've uploaded the ZIP once more. Unpack it, then add/delete spaces > in Bar.groovy to trigger the bug in the compiler. Thanks - that's quite a complex example, and it looks as though the problem occurs when a static initialiser in one class refers to another class... However, I'm afraid I'm having trouble running this example - in particular, I can't get the Java file to compile. It obviously needs to be able to find groovy.lang.Closure, but setting the classpath to point to the jar file in $GROOVY_HOME/embeddable didn't work, and I couldn't find any instructions for compiling Java that uses Groovy classes in the Groovy documentation: $ javac -cp $GROOVY_HOME/embeddedable/groovy-all-1.1-BETA-1.jar Foo.java Foo.java:1: package groovy.lang does not exist import groovy.lang.Closure; ^ [...] What am I doing wrong? Thanks, Robert --------------------------------------------------------------------- To unsubscribe from this list please visit: http://xircles.codehaus.org/manage_email |
|
|
Re: Groovy runs code in static initializers during compileOn 3 May 2007, at 17:52, Robert Stroud wrote: > I'm afraid I'm having trouble running this example... I got rid of the dependency on groovy.lang.Closure in Foo.java by simplifying the code - however, if I compile Bar.groovy, I get an error message to say there's no main method, and I can't figure out how to make the groovy interpreter run the Bar.x method directly... Please could you provide step by step instructions for running the example and generating the error - apologies if this is obvious, but I can't make it work. The best I've managed is Caught: java.lang.ExceptionInInitializerError but I think I've got that at run-time rather than compile-time, so it's not the same problem. Thanks, Robert --------------------------------------------------------------------- To unsubscribe from this list please visit: http://xircles.codehaus.org/manage_email |
|
|
Re: Groovy runs code in static initializers during compileRobert Stroud schrieb:
> Please could you provide step by step instructions for running the > example and generating the error - apologies if this is obvious, but I > can't make it work. The best I've managed is > > Caught: java.lang.ExceptionInInitializerError > > but I think I've got that at run-time rather than compile-time, so it's > not the same problem. Can you try to create a new Goovy project in Eclipse and just import the files into the src directory? The plugin will set all the classpaths and stuff right. You will then see the error message printed in the console from which you started eclipse (just run eclipse.exe from a commandline). If that doesn't work, I'll post a complete Eclipse project tomorrow. I'm not 100% sure how to replicate the same problem from the commandline without Eclipse. I'll sleep over it. Regards, -- Aaron "Optimizer" Digulla a.k.a. Philmann Dark "It's not the universe that's limited, it's our imagination. Follow me and I'll show you something beyond the limits." http://www.pdark.de/ --------------------------------------------------------------------- To unsubscribe from this list please visit: http://xircles.codehaus.org/manage_email |
|
|
Re: Groovy runs code in static initializers during compileOn 3 May 2007, at 20:58, Aaron Digulla wrote: > Robert Stroud schrieb: > >> Please could you provide step by step instructions for running the >> example and generating the error - apologies if this is obvious, >> but I can't make it work. The best I've managed is >> Caught: java.lang.ExceptionInInitializerError >> but I think I've got that at run-time rather than compile-time, so >> it's not the same problem. > > Can you try to create a new Goovy project in Eclipse and just > import the files into the src directory? The plugin will set all > the classpaths and stuff right. You will then see the error message > printed in the console from which you started eclipse (just run > eclipse.exe from a commandline). > > If that doesn't work, I'll post a complete Eclipse project > tomorrow. I'm not 100% sure how to replicate the same problem from > the commandline without Eclipse. I'll sleep over it. It's OK - I don't use Eclipse, but I've managed to reproduce your error from the command line. But the behaviour I'm seeing is very weird - I'll explain in a separate message... Thanks. Robert > > Regards, > > -- > Aaron "Optimizer" Digulla a.k.a. Philmann Dark > "It's not the universe that's limited, it's our imagination. > Follow me and I'll show you something beyond the limits." > http://www.pdark.de/ > > --------------------------------------------------------------------- > To unsubscribe from this list please visit: > > http://xircles.codehaus.org/manage_email > --------------------------------------------------------------------- To unsubscribe from this list please visit: http://xircles.codehaus.org/manage_email |
|
|
Re: Groovy runs code in static initializers during compileOn 3 May 2007, at 17:52, Robert Stroud wrote: > $ javac -cp $GROOVY_HOME/embeddedable/groovy-all-1.1-BETA-1.jar > Foo.java > Foo.java:1: package groovy.lang does not exist > import groovy.lang.Closure; > ^ > [...] > > What am I doing wrong? Mea culpa - not being able to spell "embeddable" for a start... :-( Anyway, here's how to reproduce Aaron's bug: 1) Unpack the attached zip file to get Foo.java, StaticInitBug.groovy, and Bar.groovy 2) Compile Foo.java javac -cp $GROOVY_HOME/embeddable/groovy-all-1.1-BETA-1.jar Foo.java 3) Try to run Bar.groovy from the command line, and observe that this makes no sense because there's no main method: $ groovy Bar.groovy Caught: groovy.lang.GroovyRuntimeException: This script or class could not be run. It should either: - have a main method, - be a class extending GroovyTestCase, - or implement the Runnable interface. 4) Start up GroovyConsole, paste the contents of Bar.groovy into the Input window, and type ^R to run the code through the Groovy interpreter. Observe the confusing error message that presumably means the same thing... Exception thrown: groovy.lang.MissingMethodException: No signature of method: Bar.main() is applicable for argument types: ([Ljava.lang.String;) values: {[]} 5) Clear the output (^W) and run the code again (^R) - observe that you get a completely different error message and stack trace, due to the dubious use of reflection to check the last modified time on a class object (presumably Foo.class): java.lang.ExceptionInInitializerError at [...] at java.lang.reflect.Field.get(Field.java:357) at org.codehaus.groovy.control.ResolveVisitor.getTimeStamp (ResolveVisitor.java:243) at org.codehaus.groovy.control.ResolveVisitor.isSourceNewer (ResolveVisitor.java:268) at org.codehaus.groovy.control.ResolveVisitor.resolveToScript (ResolveVisitor.java:297) 6) Explain what's going on... :-) Something very strange - it looks as though something gets cached when you try to run the code for the first time, which causes the behaviour to be different when you run it the second time. Maybe this is a characteristic of the way GroovyConsole works, but it seems a bit odd to me, although it exposes the bug quite nicely. Also, the error message from GroovyConsole the first time that you try to run the class is rather unclear - the groovy command line interpreter and the groovy shell do a much better job. But why is the result different the second time, and why do you need the extra Bar class to expose the bug - if you try and run StaticInitBug.groovy repeatedly, you just get the "main not found" error repeatedly... Very weird, but I hope this helps someone to figure out what's going on... Thanks. Robert --------------------------------------------------------------------- To unsubscribe from this list please visit: http://xircles.codehaus.org/manage_email |
|
|
Re: Groovy runs code in static initializers during compileRobert Stroud schrieb:
> 1) Unpack the attached zip file to get Foo.java, StaticInitBug.groovy, > and Bar.groovy > > 2) Compile Foo.java > > javac -cp $GROOVY_HOME/embeddable/groovy-all-1.1-BETA-1.jar Foo.java > > 3) Try to run Bar.groovy from the command line, and observe that this > makes no sense because there's no main method: Just just need to compile the two groovy scripts *twice*. They aren't intended to be run, therefore no main. The code just shows that you can execute Groovy code from within the compiler which shouldn't happen. As you found out, the Closure is not really necessary to trigger the bug. That's just left from my attempts to reproduce the bug without knowing what causes it. Regards, -- Aaron "Optimizer" Digulla a.k.a. Philmann Dark "It's not the universe that's limited, it's our imagination. Follow me and I'll show you something beyond the limits." http://www.pdark.de/ --------------------------------------------------------------------- To unsubscribe from this list please visit: http://xircles.codehaus.org/manage_email |
|
|
Re: Groovy runs code in static initializers during compileOn 3 May 2007, at 22:45, Aaron Digulla wrote: > Robert Stroud schrieb: > >> 1) Unpack the attached zip file to get Foo.java, >> StaticInitBug.groovy, and Bar.groovy >> 2) Compile Foo.java >> javac -cp $GROOVY_HOME/embeddable/groovy-all-1.1-BETA-1.jar Foo.java >> 3) Try to run Bar.groovy from the command line, and observe that >> this makes no sense because there's no main method: > > Just just need to compile the two groovy scripts *twice*. They > aren't intended to be run, therefore no main. The code just shows > that you can execute Groovy code from within the compiler which > shouldn't happen. I'm not sure that compiling the two groovy scripts twice will trigger the bug, unless you do it in an environment where there is a persistent Groovy VM (or some equivalent concept) Hence, compiling the scripts twice in GroovyShell (and perhaps Eclipse) will trigger the bug, but not from the command line. Robert --------------------------------------------------------------------- To unsubscribe from this list please visit: http://xircles.codehaus.org/manage_email |
|
|
Re: Groovy runs code in static initializers during compileOn 3 May 2007, at 15:11, Robert Stroud wrote: > > On 3 May 2007, at 14:14, Aaron Digulla wrote: > >> Quoting Robert Stroud <R.J.Stroud@...>: >> >>> why can't the compiler check the modification times >>> on the actual files? >> >> Because, as someone else here has pointed out, there isn't always >> a file. When you generate code on the fly, you just pass a string >> to the groovy compiler. The resulting class(es) are not backed by >> files but they still have a compilation time. > > But it looks to me as though the relevant code only compares the > modification times if the source file exists - if the code has been > generated on the fly, then there won't be a source file, so there > will be nothing to compare. The problem is that isSourceNewer takes > a URL and a Class as an argument rather than two URLs - hence, it > seems to me that the easiest solution to this particular problem > would be to add a getClassFile method to GroovyResourceLoader, and > then compare the modification times on the two URLs, with > appropriate code to deal with a situation where one or other of the > files doesn't exist.... OK - so I decided I'd better try this to make sure it works, but it does... I can now run Aaron's example repeatedly from within GroovyConsole without getting the exception. To achieve this, I basically tweaked resolveToScript in the way I suggested - my first attempt wasn't quite right (I wasn't sure what to do if only objectURL was null), but the final result looks like this: URL sourceURL = null; URL objectURL = null; try { sourceURL = gcl.getResourceLoader().loadGroovySource(name); if ( sourceURL != null) { objectURL = gcl.getResourceLoader().loadGroovyObject (name); } } catch (MalformedURLException e) { // fall through and let the URL be null } if (sourceURL !=null) { if (type.isResolved() && objectURL != null) { // if the file is not newer we don't want to recompile if (!isSourceNewer(sourceURL,objectURL)) return true; cachedClasses.remove(type.getName()); type.setRedirect(null); } SourceUnit su = compilationUnit.addSource(sourceURL); currentClass.getCompileUnit().addClassNodeToCompile (type,su); return true; } // type may be resolved through the classloader before return type.isResolved(); } I rewrote isSourceNewer as follows: private long lastMod(URL url) throws IOException { long lastMod; // Special handling for file:// protocol, as getLastModified() often reports // incorrect results (-1) if (url.getProtocol().equals("file")) { // Coerce the file URL to a File String path = url.getPath().replace('/', File.separatorChar).replace('|', ':'); File file = new File(path); lastMod = file.lastModified(); } else { URLConnection conn = url.openConnection(); lastMod = conn.getLastModified(); conn.getInputStream().close(); } return lastMod; } private boolean isSourceNewer(URL source, URL object) { try { return lastMod(source) > lastMod(object); } catch (IOException e) { // if the stream can't be opened, let's keep the old reference return false; } } and made some obvious changes to GroovyResourceLoader and GroovyClassLoader to support the new loadGroovyObject method - I also added a new getDefaultClassExtension method to CompilerConfiguration to allow refactoring of getSourceFile to getFile. The essential code is as follows, with getSourceFile renamed as getFile, which now takes an extra argument, the default file extension, which is obtained from the config object: private GroovyResourceLoader resourceLoader = new GroovyResourceLoader() { public URL loadGroovySource(final String filename) throws MalformedURLException { URL file = (URL) AccessController.doPrivileged(new PrivilegedAction() { public Object run() { return getFile(filename, config.getDefaultScriptExtension()); } }); return file; } public URL loadGroovyObject(final String filename) throws MalformedURLException { URL file = (URL) AccessController.doPrivileged(new PrivilegedAction() { public Object run() { return getFile(filename, config.getDefaultClassExtension()); } }); return file; } }; [...] private URL getFile(String name, String ext) { String filename = name.replace('.', '/') + ext; [...] // the rest is unchanged } Anyway, it all seems to work - in particular, it passes all the test cases during the build, and it runs Aaron's example. However, as I said in my original message... > Of course, there may be other reasons why the Groovy compiler needs > to initialize classes during compilation, but I don't see why it's > necessary in this particular situation. I'll try and figure out how to generate a patch if someone confirms that my approach is reasonable... BTW, I've not looked to see whether the duplicate code in GroovyClassLoader can also be rewritten in this way, but it should be possible, and that needs to be part of the patch too... Thanks. Robert > > Robert > > --------------------------------------------------------------------- > To unsubscribe from this list please visit: > > http://xircles.codehaus.org/manage_email > --------------------------------------------------------------------- To unsubscribe from this list please visit: http://xircles.codehaus.org/manage_email |
|
|
Re: Groovy runs code in static initializers during compileRobert Stroud schrieb:
[...] > URL sourceURL = null; > URL objectURL = null; > try { > sourceURL = gcl.getResourceLoader().loadGroovySource(name); > if ( sourceURL != null) > { > objectURL = gcl.getResourceLoader().loadGroovyObject(name); > } > } catch (MalformedURLException e) { > // fall through and let the URL be null > } shouldn't sourceURL and objectURL be the same after this? bye blackdrag -- Jochen "blackdrag" Theodorou Groovy Tech Lead (http://groovy.codehaus.org) http://blackdragsview.blogspot.com/ --------------------------------------------------------------------- To unsubscribe from this list please visit: http://xircles.codehaus.org/manage_email |
| < Prev | 1 - 2 - 3 - 4 - 5 - 6 | Next > |
| Free embeddable forum powered by Nabble | Forum Help |