Re: Defining a global variable
Merlin Beedell: > I sure wish the word 'global' was used instead of > 'static'. It just kinda makes more sense to me! Those are orthogonal concepts. `static' denotes an element whose existance is with the program, and `dynamic' -- an element whose existance is with an instance of a dymamic object. `global' denotes an element that is accessible from all over a program unit (which may be module, class, namespace, or entire program), and `local` denotes an element owned by, accessible from within, a program unit. The local/global dichotomy is relative: a variable may be global to a method, but local to the class. Fields in OOP are local with respect to the containing class, but gloal with respect to the methods, which is why I so dislike them. Hold on, MG, I have not forgotten about your e-mail.
Re: Defining a global variable
Hi Merlin, I don't know how your reply pertains to what I said, but generally speaking having implicit variables is imho generally a very poor design choice, as anyone who has experienced them in e.g. a Basic dialect will be able to confirm, simply because one innocuous typo can introduce a hard to track bug into your code, by implicitly defining a new variable instead of modifying an existing one. Cheers, mg On 21/10/2020 17:46, Merlin Beedell wrote: I thought that implicit variables would overcome this. Not an elegant solution - as you are simply declaring variables on the fly without an explicit data type or even a 'def'. Having said, it is generally safer to explicitly list the parameters used in a method when used in this context (e.g. in a script without an explicit class declaration to mop up this case). And as for 'global' - I sure wish the word 'global' was used instead of 'static'. It just kinda makes more sense to me! //=== test='' //implicit declaration of a variable void func() { println(test) } test = 'hello' func() //=== Or just //=== void func() { println(test) } test = 'hello' func() //=== Merlin Beedell -Original Message- From: MG Sent: 15 October 2020 6:21 PM To: users@groovy.apache.org; Jochen Theodorou Subject: Re: Defining a global variable On 15/10/2020 18:27, Jochen Theodorou wrote: well.. even scripts are first compiled into a class before the class is then executed. Groovy has no interpreter Which, I think, is a lesser known fact, and quite surprising to people who perceive Groovy just under its "script language" aspect ;-)
RE: Defining a global variable
I thought that implicit variables would overcome this. Not an elegant solution - as you are simply declaring variables on the fly without an explicit data type or even a 'def'. Having said, it is generally safer to explicitly list the parameters used in a method when used in this context (e.g. in a script without an explicit class declaration to mop up this case). And as for 'global' - I sure wish the word 'global' was used instead of 'static'. It just kinda makes more sense to me! //=== test='' //implicit declaration of a variable void func() { println(test) } test = 'hello' func() //=== Or just //=== void func() { println(test) } test = 'hello' func() //=== Merlin Beedell -Original Message- From: MG Sent: 15 October 2020 6:21 PM To: users@groovy.apache.org; Jochen Theodorou Subject: Re: Defining a global variable On 15/10/2020 18:27, Jochen Theodorou wrote: > well.. even scripts are first compiled into a class before the class > is then executed. Groovy has no interpreter Which, I think, is a lesser known fact, and quite surprising to people who perceive Groovy just under its "script language" aspect ;-)
Re: Defining a global variable
On 15/10/2020 18:27, Jochen Theodorou wrote: well.. even scripts are first compiled into a class before the class is then executed. Groovy has no interpreter Which, I think, is a lesser known fact, and quite surprising to people who perceive Groovy just under its "script language" aspect ;-)
Re: Defining a global variable
On 15.10.20 12:16, Anton Shepelev wrote: Jochen Theodorou to Anton Shepelev: Jochen Theodorou: Frankly... for years we have been defending this position, but now, with so much distance I actually really wonder why we keep this. Perhaps it would have helped if you had documented not only language features but also their rationale (justification), at least is difficult, debatable cases. the reason is easy: it reflects the implementation. But the implementation can be changed The implementation reflects the implementation? I do not understand. specification by implementation I mean [...] Whereas methods are also code, I believe it would be much clearer if it said "immediate code" -- code that is executed immediately rather than compiled into a callable method. well.. even scripts are first compiled into a class before the class is then executed. Groovy has no interpreter [...] I am not sure, but we both failed to find that paragraph until Maarten pointed it out. But now that I think about it again, it is the right place. I was searching for something different. A more high-level description of variable scopes and how they work instead of describing the specific case of a script with the common base class. bye Jochen
Re: Defining a global variable
On 14.10.20 17:01, Anton Shepelev wrote: Jochen Theodorou to Anton Shepelev: [...] Frankly... for years we have been defending this position, but now, with so much distance I actually really wonder why we keep this. Perhaps it would have helped if you had documented not only language features but also their rationale (justification), at least is difficult, debatable cases. the reason is easy: it reflects the implementation. But the implementation can be changed [...] it is actually less the assignment operator itself, it is the effect of scopes of dynamic variables. To compare.. in Java you have a static scope for a variable. But I do not know Java and am learning Groovy as a stand- alone language, not as a Java derivative. Sure, any other language you know ;) Python for example has a different variable scoping system. But most static languages have something like those static variable scopes. The compiler knows at any time where a variable is declared, and where to write it to (local variable or class). In Groovy we also have the static variable scopes, but they are "extended" in dynamic Groovy with dynamic variables. This means the (meta) class is "asked" for the value and existence of a variable at runtime as soon as we leave the static scope. Somewhat similar to metatables in Lua, isn't it? I never worked with Lua, but from what I have seen I would answer yes. Why does not the same thing work from class methods, even from static class methods? -- class Boo { static def boo() {x = 1 } } It does work, only a class does not have the special implementation Script has. class AlwaysAnswer{ def getProperty(String something){ 42 } def ask(question){ return answer } } def alwaysAnswer = new AlwaysAnswer() assert alwaysAnswer.answerToMeaningOfLife == 42 assert alwaysAnswer.myName == 42 assert alwaysAnswer.ask("Are you kidding me?") == 42 The class AlwaysAnswer is a real class and exists additionally to the class we generate for the script itself. You will see that the code above does not throw any exception, that is because I implemented the getProperty method, which is used by the meta class system to answer when asked for an unknown property. For a static method/property we have something too: https://docs.groovy-lang.org/latest/html/documentation/core-metaprogramming.html#_static_propertymissing If you look at https://github.com/apache/groovy/blob/master/src/main/java/groovy/lang/Script.java#L54 you see that the class Script does implement getProperty method. Script is normally used as base class for all Groovy scripts. My example above for example will generate code like this: class AlwaysAnswer{ def propertyMissing(String something){ 42 } def ask(question){ return answer } } class Scrip1243324 extends groovy.lang.Script{ void run() { def alwaysAnswer = new AlwaysAnswer() assert alwaysAnswer.answerToMeaningOfLife == 42 assert alwaysAnswer.myName == 42 assert alwaysAnswer.ask("Are you kidding me?") == 42 } } It is now possible to let the Groovy compiler use a different base class for scripts, in which case the runtime behaviour changes and you could let it disallow those global variables - or allow read before write. Or the script defines overwrites the getProperty method and defines this kind of behaviour itself. [...] In another reply, Maarten Boekhold refers to section 3.4 (Variables) of the "Program structure" document, which has the following to say about assignments to undeclared (or undefined?) variables: if the variable is undeclared, it goes into the script binding. The binding is visible from the methods, and is especially important if you use a script to interact with an application and need to share data between the script and the application. I think you should read the whole chapter 3 http://groovy-lang.org/structure.html#_scripts_versus_classes Otherwise you miss out on some of the concepts and I think this passage alone then makes much less sense. On the other hand Maarten really explain most of that already in his mail The explanation is OK, but I failed to look into that document. Do you think you can provide better documentation at a better place? If so, I should certainly appreciate it. I also thank Maarten for reply. A better place? What was wrong? bye Jochen
Re: Defining a global variable
Jochen Theodorou to Anton Shepelev: > > String test > > > > void func() > > { > >println(test) > > } > > > > test = 'hello' > > func() > > > > Why, then, is `test' inaccessible from the function in > > my script? > > because the method you defined is not nested in another > method, instead it exists parallel to the other method > that represents your script body, and they do not share > local variables. Thanks for the explanation, Jochen. > Frankly... for years we have been defending this position, > but now, with so much distance I actually really wonder > why we keep this. Perhaps it would have helped if you had documented not only language features but also their rationale (justification), at least is difficult, debatable cases. > It comes up as a problem on a regular base, but wouldn't > be so hard to "fix" really. I mean it is not broken, it > works as designed, just not very intuitive. Now that I know the answer, I am not sure the behavior should be changed: the must be a way to dictinguish between local variables of the `run' method, the class fields, and the binding variables. > it is actually less the assignment operator itself, it is > the effect of scopes of dynamic variables. To compare.. in > Java you have a static scope for a variable. But I do not know Java and am learning Groovy as a stand- alone language, not as a Java derivative. > The compiler knows at any time where a variable is > declared, and where to write it to (local variable or > class). In Groovy we also have the static variable scopes, > but they are "extended" in dynamic Groovy with dynamic > variables. This means the (meta) class is "asked" for the > value and existence of a variable at runtime as soon as we > leave the static scope. Somewhat similar to metatables in Lua, isn't it? Why does not the same thing work from class methods, even from static class methods? -- class Boo { static def boo() {x = 1 } } > I would have loved to point to our documentation for this, > but I actually am unable to find this there. In another reply, Maarten Boekhold refers to section 3.4 (Variables) of the "Program structure" document, which has the following to say about assignments to undeclared (or undefined?) variables: if the variable is undeclared, it goes into the script binding. The binding is visible from the methods, and is especially important if you use a script to interact with an application and need to share data between the script and the application. The explanation is OK, but I failed to look into that document. Do you think you can provide better documentation at a better place? If so, I should certainly appreciate it. I also thank Maarten for reply.
Re: Defining a global variable
Hi, I've been caught out by this in the past as well. It's actually quite simple... A Groovy Script like: String test void func(){ println(test) } test = 'hello' func() Gets compiled to a class as: class MyScript extends Script { def run() { String test test = 'hello' func() } void func() { println(test) } } All "lose code" gets collected into the run() method, and functions defined in your script are copied into the class as methods. As you can see, the declaration "String test" ends up as part of the run() method, and therefore the "test" variable is scoped locally to that run() method. It's not a class member. Your func() method is not able to see it. You can work around that by annotating the "String test" declaration with the @Field annotation: @Field String test void func() { println(test) } test = 'hello' func() This will cause the "String test" declaration to be included in the Script class as a class member: class MyScript extends Script { String test def run() { test = 'hello' func() } void func(){ println(test) } } This is described in https://docs.groovy-lang.org/latest/html/documentation/core-metaprogramming.html#xform-Field. It is also very lightly mentioned in https://groovy-lang.org/structure.html#_variables, but that page probably doesn't make it clear enough. Maarten On 14/10/2020 15:45, Anton Shepelev wrote: Hello, all I tried to define a global variable in a Groovy script. Section 1.1. of the "Semantics" documents says that one way to define a variable is via its type, so I defined one in the global scope of my script: String test void func() { println(test) } test = 'hello' func() but it failed with the error: "No such property: test for class: Script1". That didn't explain to me what the problem was, but I learned that the script was looking for a property named `test' in the global autogenerated Script class. OK, thought I, I will give it what it asks, and cosulted section 1.6.2. (Properties) of the "Object orientation" document, which told me that the definition of a property is identical to the definition of a variable I used above, i.e. that String test defienes a string property `test' or a string variable `test', depending on context. I was now stuck and resorted to an internet search, which brought up the following page Groovy Variable Scope: https://www.baeldung.com/groovy/variable-scope where I read: Scopes in Groovy follow, above all, the rule that all variables are created public by default. This means that, unless specified, we'll be able to access any variable we created from any other scope in the code. Why, then, is `test' inaccessible from the function in my script? And below: The easiest way to create a global variable in a Groovy script is to assign it anywhere in the script without any special keywords. We don't even need to define the type: x = 200 After I removed the "String test" line from my script it started to work, but why? I returned to the "Semantics" document and read section 1.2. (Variable assignment) to see whether the assignment operator may have the side effect of defining a missing variable, but there is no indication that it has. Can you please explain to me, preferable with the correspoding references to official documentation, why my scirpt does not work whereas the modified one does?
Re: Defining a global variable
On 14.10.20 13:45, Anton Shepelev wrote: [...] String test defienes a string property `test' or a string variable `test', depending on context. the context here is that of a method, so it is a local variable I was now stuck and resorted to an internet search, which brought up the following page Groovy Variable Scope: https://www.baeldung.com/groovy/variable-scope where I read: Scopes in Groovy follow, above all, the rule that all variables are created public by default. This means that, unless specified, we'll be able to access any variable we created from any other scope in the code. Why, then, is `test' inaccessible from the function in my script? because the method you defined is not nested in another method, instead it exists parallel to the other method that represents your script body, and they do not share local variables. Frankly... for years we have been defending this position, but now, with so much distance I actually really wonder why we keep this. It comes up as a problem on a regular base, but wouldn't be so hard to "fix" really. I mean it is not broken, it works as designed, just not very intuitive. And below: The easiest way to create a global variable in a Groovy script is to assign it anywhere in the script without any special keywords. We don't even need to define the type: x = 200 After I removed the "String test" line from my script it started to work, but why? without the declaration you are writing to a outer scope variable, which in case of a script usually ends up in the binding. A variable in the binding of a script is defined by writing it. Reading a non-existent variable would cause an error. I returned to the "Semantics" document and read section 1.2. (Variable assignment) to see whether the assignment operator may have the side effect of defining a missing variable, but there is no indication that it has. it is actually less the assignment operator itself, it is the effect of scopes of dynamic variables. To compare.. in Java you have a static scope for a variable. The compiler knows at any time where a variable is declared, and where to write it to (local variable or class). In Groovy we also have the static variable scopes, but they are "extended" in dynamic Groovy with dynamic variables. This means the (meta) class is "asked" for the value and existence of a variable at runtime as soon as we leave the static scope. In Java leaving the static scope would mean an compilation error. But in Groovy we are then using the MOP to find meaning in what is requested. In case of a Closure this results in checking the enclosed scope for the value of a variable. In case of a class this results in set/getProperty and similar methods being called as part of the MOP. A Groovy script is a class too, only that its getProperty method checks the binding for the value and setProperty writes it. There is no formal way to declare a variable in a binding, it is solely defined by the program writing it. As such it has no static type (as all dynamic variables). I would have loved to point to our documentation for this, but I actually am unable to find this there. I actually thought I have written something years ago (back when it was still codehaus), but I cannot find any trace of that either I guess I should really get used to write everything I write for a project also on my blog, so that I can have at least one original reference. So no references I am aware of, sorry bye Jochen