groovy-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Dinko Srkoč <dinko.sr...@gmail.com>
Subject Re: Failing to change the value of a Java variable from wihtin a Groovy script (potential issue?)
Date Wed, 09 Mar 2016 11:36:11 GMT
On 9 March 2016 at 11:56, Thierry Hanser
<Thierry.Hanser@lhasalimited.org> wrote:
> Thank you for the suggestion Dinko.
>
> I tried your experiment and the binding variables set remains actually empty ([:]) which
is what I expected since there is no explicit binding involved (the variable 'x' is directly
declared in the base script which is the point of the approach)

Interestingly this is different from what I'm getting. The statement
`x = 'two'` adds the value 'two' to the newly added binding variable
`x` (with binding being empty before that statement).

Cheers,
Dinko

>
> An interesting hint to the problem is that if I explicitly implement the getter and don't
have a setter, there will be indeed an expected 'can't change a read-only value' compilation
error which means that the getter/setter status is correctly analysed in the compilation decision
tree and the setter must be present (or implicit) in order to allow the assignment in line
2 (x = 'two'); the problem is that it is not invoked at runtime; i.e. at compilation time
Groovy's understanding is correct but the compiled code does not actually invoke the setter.
>
> This is disturbing and concerning as it leads to unpredictable behaviour.
>
> Thierry
>
>
> -----Original Message-----
> From: Dinko Srkoč [mailto:dinko.srkoc@gmail.com]
> Sent: 08 March 2016 18:20
> To: users@groovy.apache.org
> Subject: Re: Failing to change the value of a Java variable from wihtin a Groovy script
(potential issue?)
>
> On 8 March 2016 at 18:11, Thierry Hanser <Thierry.Hanser@lhasalimited.org> wrote:
>>
>> Thank you  Jason, you were indeed right, without CompileStatic or using TypeChecked
works.
>
> Well, it works, but probably not the way you think it works. Here's what you can do to
get more insight into what's going on:
>
> * print the script's variable bindings - add to `scriptSource`:
> `println binding.variables`
> * access the field `x` directly - to `JavaScriptDemo` add a method like this:
>
>     public String myX() { return x; }
>
>   then print that as well: `println myX()`
> * run the script with and without `CompileStatic` and compare the results
>
> After running the experiment you'll probably notice that the field `x` is never really
changed. When you try to add the value 'two' to `x` you're actually creating a new binding
variable. The difference with CompileStatic is in accessing the field or the binding if binding
exists.
>
> Cheers,
> Dinko
>
>>
>> This is concerning as I would prefer static compilation (type checking being a must).
>>
>>
>>
>> I can work around the issue in my context but it impacts the elegance of the underlying
DSL.
>>
>> However from the Groovy script engine perspective it is more concerning.
>>
>>
>>
>> Maybe Cedric or Guy know if there are any known issues and planned fixes related
to that problem?
>>
>>
>>
>> Thanks again Jason.
>>
>>
>>
>> Thierry
>>
>>
>>
>> ---
>>
>> PS:  There was a couple of typos in the source code (never post-edit in outlook ;-)
). Apologies for any inconveniences.
>>
>> Here is the correct adjusted and working code:
>>
>>
>>
>> import org.codehaus.groovy.control.CompilerConfiguration;
>>
>> import
>> org.codehaus.groovy.control.customizers.ASTTransformationCustomizer;
>>
>>
>>
>> import groovy.lang.Binding;
>>
>> import groovy.lang.GroovyShell;
>>
>> import groovy.lang.Script;
>>
>> import groovy.transform.CompileStatic;;
>>
>>
>>
>> public abstract class JavaScriptDemo extends Script
>>
>> {
>>
>>     public String x;
>>
>>
>>
>>     public JavaScriptDemo()
>>
>>     {
>>
>>            x="one";
>>
>>            System.out.println("init x: " + x);
>>
>>     }
>>
>>
>>
>>      /**
>>
>>      * Demo main
>>
>>      * @param args
>>
>>      * @throws Throwable
>>
>>      */
>>
>>     public static void main(String...args) throws Throwable
>>
>>     {
>>
>>            ////
>>
>>            // Compilation configuration
>>
>>            CompilerConfiguration configuration = new
>> CompilerConfiguration();
>>
>>            configuration.addCompilationCustomizers(new
>> ASTTransformationCustomizer(CompileStatic.class));
>>
>>
>> configuration.setScriptBaseClass(JavaScriptDemo.class.getName());
>>
>>            GroovyShell shell = new
>> GroovyShell(JavaScriptDemo.class.getClassLoader(), new Binding(),
>> configuration);
>>
>>
>>
>>            // source code
>>
>>            String scriptSource= "println '1 = ' + x; x = 'two';
>> println '2 = ' + x\n";
>>
>>
>>
>>            // compile the source code and run the compiled script
>>
>>            JavaScriptDemo compiledScript =
>> (JavaScriptDemo)shell.parse(scriptSource);
>>
>>         compiledScript.run();
>>
>>     }
>>
>> }
>>
>>
>>
>> From: Winnebeck, Jason [mailto:Jason.Winnebeck@windstream.com]
>> Sent: 08 March 2016 16:46
>> To: users@groovy.apache.org
>> Subject: RE: Failing to change the value of a Java variable from
>> wihtin a Groovy script (potential issue?)
>>
>>
>>
>> Unfortunately static compile can be pretty flaky at times and I run into bugs often
with it and have to redesign code. For small scripts I would advise against it (if you need
type checking, use TypeChecked). I’m wondering if the script is getting compiled to get
field x from the base class but favors setting binding.x = ‘two’ in the script.
>>
>>
>>
>> I would try without static compilation and see if it works. If it does work without
static compilation, upgrade to the very latest Groovy (2.4.6) as bugs are fixed in static
compiler all the time. If that doesn’t fix the problem, then change the Java field to private
and create a getX() and setX(String). If that doesn’t work and you still need static compile,
try an explicit setX(‘two’) or this.x = ‘two’ in the script. Historically the static
compiler has been more reliable when you are more explicit.
>>
>>
>>
>> Jason
>>
>>
>>
>> From: Thierry Hanser [mailto:Thierry.Hanser@lhasalimited.org]
>> Sent: Tuesday, March 08, 2016 11:32 AM
>> To: 'users@groovy.apache.org' <users@groovy.apache.org>
>> Subject: Failing to change the value of a Java variable from wihtin a
>> Groovy script (potential issue?)
>>
>>
>>
>> Hi,
>>
>>
>>
>> The following very simple code is behaving really strangely.
>>
>> Could anyone please tell me if this is an issue in Groovy or something I am not doing
properly (I would like to vote for the latter, yet...).
>>
>>
>>
>> In Java
>>
>>
>>
>> x='one';
>>
>> System.out.println("init x: " + x);
>>
>>
>>
>> In Groovy
>>
>>
>>
>> println '1 = ' + x
>>
>> x = 'two'
>>
>> println '2 = ' + x
>>
>>
>>
>> Output:
>>
>>
>>
>> init x: one  <- initial value assignement OK
>>
>>
>>
>> 1 = one      <- successfully accessing ‘x’ from within the compiled script
OK
>>
>>                 the Groovy script has picked up the value of the Java
>> variable;
>>
>>                 the implicit getX() has been called
>>
>>
>>
>> 2 = one                <- should be ‘two’ as per Groovy code (second line)
>>
>>                 but is unchanged ???
>>
>>
>>
>> It seems that the Groovy script can’t change the value of ‘x’ (can’t
>> access setX()). However there is no compilation error (‘x’ is not
>> read-only)
>>
>> When implementing getX/setX methods, only the getter is called (in both print statements,
line 1,3) but during the assignment instruction (line 2), the setter is silently ignored (the
value of ‘x’ remains ‘one’ instead of ‘two’.
>>
>>
>>
>> The Java/Groovy binding is operational since the ‘one’ value of ‘x’ in the
Java  base class is successfully retrieved. So could anyone please tell me where the issue
is?
>>
>> The confusing part is that even within in the Groovy context alone,
>> the assignment ‘x=’two’ is not honoured (and yet there are no
>> compilation/runtime error)
>>
>>
>>
>> Note that I tried all combinations of setters/getters/visibility and
>> can at the best read but never modify the variable ‘x’. The same
>> behaviour occurs with using the GroovyScriptEngine or
>> GroovyClassLoader
>>
>>
>>
>> Thank you very much in advance for your help.
>>
>>
>>
>> Thierry
>>
>> -
>>
>>
>>
>> PS: (I am not sure if my previous message went through as I was still
>> in the mailing list registration process, apologies if it is a
>> duplicate)
>>
>>
>>
>> Full code:
>>
>>
>>
>> import org.codehaus.groovy.control.CompilerConfiguration;
>>
>> import
>> org.codehaus.groovy.control.customizers.ASTTransformationCustomizer;
>>
>>
>>
>> import groovy.lang.Binding;
>>
>> import groovy.lang.Closure
>>
>> import groovy.lang.GroovyClassLoader;
>>
>> import groovy.lang.GroovyShell;
>>
>> import groovy.transform.CompileStatic;;
>>
>>
>>
>> abstract class GroovyDemoScript extends Script
>>
>> {
>>
>>     public String x;
>>
>>
>>
>>     public GroovyDemoScript()
>>
>>     {
>>
>>            x='one';
>>
>>            System.out.println("init x: " + x);
>>
>>     }
>>
>>
>>
>>     public static void main(String...args) throws Throwable
>>
>>     {
>>
>>            ////
>>
>>            // Compilation configuration
>>
>>            CompilerConfiguration configuration = new
>> CompilerConfiguration();
>>
>>            configuration.addCompilationCustomizers(new
>> ASTTransformationCustomizer(CompileStatic.class));
>>
>>
>>
>>                                 // make sure we use the Java base
>> class where ‘x’ is defined
>>
>>
>> configuration.setScriptBaseClass(GroovyDemoScript.class.name);
>>
>>
>>
>>            GroovyShell shell = new
>> GroovyShell(this.getClass().getClassLoader(), new Binding(),
>> configuration);
>>
>>
>>
>>            // source code
>>
>>            String scriptSource= "println '1 = ' + x; x = 'two';
>> println '2 = ' + x\n";
>>
>>
>>
>>            // compile the source code and run the compiled script
>>
>>            GroovyDemoScript compiledScript =
>> shell.parse(scriptSource);
>>
>>            compiledScript.run();
>>
>>     }
>>
>> }
>>
>>
>>
>> ________________________________
>>
>> Switchboard: +44 (0)113 394 6020
>>
>> Technical Support: +44 (0)113 394 6030
>>
>> ________________________________
>>
>> Lhasa Limited, a not-for-profit organisation, promotes scientific knowledge &
understanding through the development of computer-aided reasoning & information systems
in chemistry & the life sciences. Registered Charity Number 290866. Registered Office:
Granary Wharf House, 2 Canal Wharf, Leeds, LS11 5PS. Company Registration Number 01765239.
Registered in England and Wales.
>>
>> This communication, including any associated attachments, is intended for the use
of the addressee only and may contain confidential, privileged or copyright material. If you
are not the intended recipient, you must not copy this message or attachment or disclose the
contents to any other person. If you have received this transmission in error, please notify
the sender immediately and delete the message and any attachment from your system. Except
where specifically stated, any views expressed in this message are those of the individual
sender and do not represent the views of Lhasa Limited. Lhasa Limited cannot accept liability
for any statements made which are the sender's own. Lhasa Limited does not guarantee that
electronic communications, including any attachments, are free of viruses. Virus scanning
is recommended and is the responsibility of the recipient.
>>
>> ________________________________
>>
>> This email message and any attachments are for the sole use of the intended recipient(s).
Any unauthorized review, use, disclosure or distribution is prohibited. If you are not the
intended recipient, please contact the sender by reply email and destroy all copies of the
original message and any attachments.

Mime
View raw message