Uploaded image for project: 'Groovy'
  1. Groovy
  2. GROOVY-1008

Overriding properties defined w/ @Property gives wrong results

Details

    • Bug
    • Status: Closed
    • Major
    • Resolution: Fixed
    • 1.0-JSR-2
    • 1.0-JSR-4
    • None
    • None
    • Groovy jsr02, jdk 1.4.2_08

    Description

      Accessing a property that is overridden in a subclass gives wrong result. See included test case for details.

      Attachments

        1. property_bug.groovy
          0.4 kB
        2. property_nobug.groovy
          0.5 kB
          Kim, Pilho
        3. PropertyOverrideTest.groovy
          0.7 kB
          Kim, Pilho

        Activity

          phkim Kim, Pilho added a comment -

          Here is a similar example for Java.

          X-------------------------------------------------------------
          // PropertyOveride.java
          public class PropertyOveride {
          public static void main(String[] args)

          { FooSubClass b = new FooSubClass(); System.out.println("b.x = " + b.x); System.out.println("b.aMethod() = " + b.aMethod()); }

          }

          // FooSuperClass.java
          class FooSuperClass {
          public String x = "foo";
          protected String aMethod()

          { return this.x; }

          }

          // FooSubClass.java
          class FooSubClass extends FooSuperClass {
          public String x = "bar";
          }
          X-------------------------------------------------------------

          Output is:
          b.x = bar
          b.aMethod() = foo

          phkim Kim, Pilho added a comment - Here is a similar example for Java. X------------------------------------------------------------- // PropertyOveride.java public class PropertyOveride { public static void main(String[] args) { FooSubClass b = new FooSubClass(); System.out.println("b.x = " + b.x); System.out.println("b.aMethod() = " + b.aMethod()); } } // FooSuperClass.java class FooSuperClass { public String x = "foo"; protected String aMethod() { return this.x; } } // FooSubClass.java class FooSubClass extends FooSuperClass { public String x = "bar"; } X------------------------------------------------------------- Output is: b.x = bar b.aMethod() = foo
          phkim Kim, Pilho added a comment -

          Both of the attached two file "property_nobug.groovy" and "PropertyOverrideTest.groovy"
          work fine.

          So it seems that there is nothing to do to fix this issue.

          phkim Kim, Pilho added a comment - Both of the attached two file "property_nobug.groovy" and "PropertyOverrideTest.groovy" work fine. So it seems that there is nothing to do to fix this issue.
          antti.karanta@napa.fi Antti Karanta added a comment -

          I don't think that's the same thing. @Property creates properties, which in Java map to get / set methods. The instance variable storing the actual value is of no direct interest. This would be the same thing in Java:

          // PropertyOverride.java
          public class PropertyOverride {
          public static void main(String[] args)

          { FooSubClass b = new FooSubClass(); System.out.println("b.x = " + b.getX()); System.out.println("b.aMethod() = " + b.aMethod()); }


          }

          // FooSuperClass.java
          class FooSuperClass {
          public String getX()

          {return "foo";}

          public String aMethod()

          { return this.getX(); }


          }

          // FooSubClass.java
          class FooSubClass extends FooSuperClass {
          public String getX()

          {return "bar";}

          }
          X-------------------------------------------------------------

          Output is:

          C:\Temp\javatest>java PropertyOverride
          b.x = bar
          b.aMethod() = bar

          Also compare overriding the properties to languages that have real "properties", such as c# and Ruby (and also Groovy = ).

          antti.karanta@napa.fi Antti Karanta added a comment - I don't think that's the same thing. @Property creates properties, which in Java map to get / set methods. The instance variable storing the actual value is of no direct interest. This would be the same thing in Java: // PropertyOverride.java public class PropertyOverride { public static void main(String[] args) { FooSubClass b = new FooSubClass(); System.out.println("b.x = " + b.getX()); System.out.println("b.aMethod() = " + b.aMethod()); } } // FooSuperClass.java class FooSuperClass { public String getX() {return "foo";} public String aMethod() { return this.getX(); } } // FooSubClass.java class FooSubClass extends FooSuperClass { public String getX() {return "bar";} } X------------------------------------------------------------- Output is: C:\Temp\javatest>java PropertyOverride b.x = bar b.aMethod() = bar Also compare overriding the properties to languages that have real "properties", such as c# and Ruby (and also Groovy = ).
          phkim Kim, Pilho added a comment -

          This issue is closed with no fix.
          If you disagree, reopen this issue.

          But the test example "PropertyOverrideTest.groovy" will be added
          to test-suits .

          phkim Kim, Pilho added a comment - This issue is closed with no fix. If you disagree, reopen this issue. But the test example "PropertyOverrideTest.groovy" will be added to test-suits .
          antti.karanta@napa.fi Antti Karanta added a comment -

          In PropertyOverrideTest.groovy:

          def protected aMethod() {
          this.x
          }

          This method should return the value of the property x for the current object (corresponding to the getX() method in Java). The value of this property is "bar" for instances of SubBar. However, "foo" is returned, which would be correct for instances of SuperFoo, but not for instances of SubBar.

          The same reasoning goes for file property_nobug.groovy

          antti.karanta@napa.fi Antti Karanta added a comment - In PropertyOverrideTest.groovy: def protected aMethod() { this.x } This method should return the value of the property x for the current object (corresponding to the getX() method in Java). The value of this property is "bar" for instances of SubBar. However, "foo" is returned, which would be correct for instances of SuperFoo, but not for instances of SubBar. The same reasoning goes for file property_nobug.groovy
          phkim Kim, Pilho added a comment -

          In PropertyOverrideTest.groovy:

          def protected aMethod() {
          this.x = "another value"
          this.x // what should be returned here?
          }

          phkim Kim, Pilho added a comment - In PropertyOverrideTest.groovy: def protected aMethod() { this.x = "another value" this.x // what should be returned here? }
          phkim Kim, Pilho added a comment -

          > I don't think that's the same thing. @Property creates properties, which in Java map to get / set methods. The instance variable storing the actual value is of no direct interest. This would be the same thing in Java:

          No.
          We consider setter for property x.

          this.x = "another value"; // This change the property x.
          // But the getter getX() can not return the changed value.

          phkim Kim, Pilho added a comment - > I don't think that's the same thing. @Property creates properties, which in Java map to get / set methods. The instance variable storing the actual value is of no direct interest. This would be the same thing in Java: No. We consider setter for property x. this.x = "another value"; // This change the property x. // But the getter getX() can not return the changed value.
          antti.karanta@napa.fi Antti Karanta added a comment -

          def protected aMethod() {
          this.x = "another value"
          this.x // what should be returned here?
          }

          I don't see any ambiguity - the value of property x for the current object. It was set to "another value" on the previous line, so that is obviously its value.

          That is, unless the setX(String newX) method is defined in some strange way to set the value to something else.

          Think of this in terms of the getX() and setX(String newX) methods. We are not accessing the value of the instance variable - we are accessing the value of the property. Since property accessors (and mutators) can be overridden, the values returned should reflect this.

          Compare w/ this simple groovy script:

          —

          class Foo {

          def aMethod()

          { println this.doMyThing() }

          def doMyThing()

          { "foo" }

          }

          class Bar extends Foo {

          def doMyThing()

          { "bar" }

          }

          def b = new Bar()

          b.aMethod() // prints "bar"

          —

          What doMyThing() returns does not depend how it is defined in the same class as the calling method - it depends how it is defined for the current object (works the same way for Java), i.e. doMyThing can be overridden. Property accessors (and mutators) can be overridden just the same.

          antti.karanta@napa.fi Antti Karanta added a comment - def protected aMethod() { this.x = "another value" this.x // what should be returned here? } I don't see any ambiguity - the value of property x for the current object. It was set to "another value" on the previous line, so that is obviously its value. That is, unless the setX(String newX) method is defined in some strange way to set the value to something else. Think of this in terms of the getX() and setX(String newX) methods. We are not accessing the value of the instance variable - we are accessing the value of the property. Since property accessors (and mutators) can be overridden, the values returned should reflect this. Compare w/ this simple groovy script: — class Foo { def aMethod() { println this.doMyThing() } def doMyThing() { "foo" } } class Bar extends Foo { def doMyThing() { "bar" } } def b = new Bar() b.aMethod() // prints "bar" — What doMyThing() returns does not depend how it is defined in the same class as the calling method - it depends how it is defined for the current object (works the same way for Java), i.e. doMyThing can be overridden. Property accessors (and mutators) can be overridden just the same.
          phkim Kim, Pilho added a comment -

          Your last example is an example for the method overriding.
          But your first example was an example for the property overriding.

          phkim Kim, Pilho added a comment - Your last example is an example for the method overriding. But your first example was an example for the property overriding.
          antti.karanta@napa.fi Antti Karanta added a comment -

          > No.
          > We consider setter for property x.
          >
          > this.x = "another value"; // This change the property x.
          > // But the getter getX() can not return the changed value.

          Properties can be read-only or write-only.

          As property accessors and mutators are really methods, some programmer might define them in such a way that the value read by the accessor does not reflect the value set by the mutator, e.g.

          class Foo {
          private String _f;
          public String getF()

          {return _f;}

          public String setF(String newF)

          { _f = "dumdeededum" + newF }

          }

          Not that this is encouraged as it is very confusing for the users of the class, just to show that accessor and mutator methods are just that - methods. And they are that in every respect - they can be overridden (or defined as one wants).

          This bug report originated from the simple case that this.x in groovy should be equivalent to this.getX(), i.e. return the value of property x for the given object. Or at least I think so. See also blackdrag's comment on the subject:
          http://article.gmane.org/gmane.comp.lang.groovy.user/5008

          "seems like this.x is handled as field access instead of property
          access... hmmm. For a field the behavior is correct."

          This is what I have been trying to say the whole time.

          There is an ambiguity in case when there is both an instance variable x and an accessor method getX(). What to do then, I don't know - maybe it's better to return the value of the instance variable as there is otherwise no way to access it directly. However, I would not expect @Property to generate an instance variable named x (as this would make it ambitious whether I am accessing the instance variable directly or via the accessor).
          It is a widely adopted coding convention in Java to prefix instance variables e.g. w/ _ (an underscore). In that case the instance variables are never the same as the actual property names (as reflected in the names of the get/set methods), e.g.
          private String _x;
          public String getX()

          {return _x;}

          I think it is reasonable that if the programmer wants to access some instance variable directly he will declare it himself. So, the name of the instance variable defined by @Property does not need to be (and in fact, should not be) the same as the name of the property. It may be documented, though, so someone defining a property may also access the instance variable directly if the so wishes.

          antti.karanta@napa.fi Antti Karanta added a comment - > No. > We consider setter for property x. > > this.x = "another value"; // This change the property x. > // But the getter getX() can not return the changed value. Properties can be read-only or write-only. As property accessors and mutators are really methods, some programmer might define them in such a way that the value read by the accessor does not reflect the value set by the mutator, e.g. class Foo { private String _f; public String getF() {return _f;} public String setF(String newF) { _f = "dumdeededum" + newF } } Not that this is encouraged as it is very confusing for the users of the class, just to show that accessor and mutator methods are just that - methods. And they are that in every respect - they can be overridden (or defined as one wants). This bug report originated from the simple case that this.x in groovy should be equivalent to this.getX(), i.e. return the value of property x for the given object. Or at least I think so. See also blackdrag's comment on the subject: http://article.gmane.org/gmane.comp.lang.groovy.user/5008 "seems like this.x is handled as field access instead of property access... hmmm. For a field the behavior is correct." This is what I have been trying to say the whole time. There is an ambiguity in case when there is both an instance variable x and an accessor method getX(). What to do then, I don't know - maybe it's better to return the value of the instance variable as there is otherwise no way to access it directly. However, I would not expect @Property to generate an instance variable named x (as this would make it ambitious whether I am accessing the instance variable directly or via the accessor). It is a widely adopted coding convention in Java to prefix instance variables e.g. w/ _ (an underscore). In that case the instance variables are never the same as the actual property names (as reflected in the names of the get/set methods), e.g. private String _x; public String getX() {return _x;} I think it is reasonable that if the programmer wants to access some instance variable directly he will declare it himself. So, the name of the instance variable defined by @Property does not need to be (and in fact, should not be) the same as the name of the property. It may be documented, though, so someone defining a property may also access the instance variable directly if the so wishes.
          antti.karanta@napa.fi Antti Karanta added a comment -

          > Your last example is an example for the method overriding.
          > But your first example was an example for the property overriding.

          Property accessors and mutators are methods.

          In Groovy:

          —

          class Foo {

          @Property x = "foo"

          def aMethod()

          { this.x }

          }

          class Bar extends Foo

          { @Property x = "bar" }

          —

          The same thing in Java (overriding the property):

          —

          class Foo {

          private String _x = "foo";

          public String getX()

          { return _x;}
          public void setX(String newX) { _x = newX; }

          public String aMethod() { return this.getX(); }

          }

          class Bar extends Foo {

          private String _x = "bar";

          public String getX() { return _x;}

          public void setX(String newX)

          { _x = newX; }

          }

          —

          Now, if you do:

          Bar b = new Bar();
          System.out.println(b.getX());

          you get "bar". If you do

          System.out.println(b.aMethod());

          you also get "bar".

          antti.karanta@napa.fi Antti Karanta added a comment - > Your last example is an example for the method overriding. > But your first example was an example for the property overriding. Property accessors and mutators are methods. In Groovy: — class Foo { @Property x = "foo" def aMethod() { this.x } } class Bar extends Foo { @Property x = "bar" } — The same thing in Java (overriding the property): — class Foo { private String _x = "foo"; public String getX() { return _x;} public void setX(String newX) { _x = newX; } public String aMethod() { return this.getX(); } } class Bar extends Foo { private String _x = "bar"; public String getX() { return _x;} public void setX(String newX) { _x = newX; } } — Now, if you do: Bar b = new Bar(); System.out.println(b.getX()); you get "bar". If you do System.out.println(b.aMethod()); you also get "bar".
          phkim Kim, Pilho added a comment -

          This is your first example.

          X-----------------------------------------------------------------
          package groovy.bugs

          /**

          • Test to demonstrate that a bug w/ a property that is overridden in a subclass
            *
          • @author Antti Karanta
            */
            public class PropertyOverrideBug extends GroovyTestCase {
            void testPropertyOverride() { def b = new Bar() assertEquals(b.x, b.aMethod()) }

          }

          class Foo {

          @Property x = "foo"

          def aMethod()

          { this.x }

          }

          class Bar extends Foo

          { @Property x = "bar" }

          X-----------------------------------------------------------------

          assertEquals(b.x, b.aMethod())

          Here b.x equals b.getX()
          But b.aMethod() equals new Foo().getX()

          The reason is that the method aMethod() of Foo has not been
          overriden by its subclass Bar.

          If Bar overrides aMethod(), then assertEquals(b.x, b.aMethod()) will success.

          phkim Kim, Pilho added a comment - This is your first example. X----------------------------------------------------------------- package groovy.bugs /** Test to demonstrate that a bug w/ a property that is overridden in a subclass * @author Antti Karanta */ public class PropertyOverrideBug extends GroovyTestCase { void testPropertyOverride() { def b = new Bar() assertEquals(b.x, b.aMethod()) } } class Foo { @Property x = "foo" def aMethod() { this.x } } class Bar extends Foo { @Property x = "bar" } X----------------------------------------------------------------- assertEquals(b.x, b.aMethod()) Here b.x equals b.getX() But b.aMethod() equals new Foo().getX() The reason is that the method aMethod() of Foo has not been overriden by its subclass Bar. If Bar overrides aMethod(), then assertEquals(b.x, b.aMethod()) will success.
          antti.karanta@napa.fi Antti Karanta added a comment -

          > Here b.x equals b.getX()
          > But b.aMethod() equals new Foo().getX()

          Huh? The definiton of aMethod is

          def aMethod()

          { this.x }

          Which just returns the value for the property x for the current object. It does not create any new objects (of any class).

          b.aMethod() calls the method "aMethod" for object b. Object b is of class Bar, but "aMethod" is not defined there. It is found in Bar's superclass Foo. This is completely legal. It's like calling
          b.hashCode() // the hashCode() method is defined in class Object, not in class Bar

          antti.karanta@napa.fi Antti Karanta added a comment - > Here b.x equals b.getX() > But b.aMethod() equals new Foo().getX() Huh? The definiton of aMethod is def aMethod() { this.x } Which just returns the value for the property x for the current object. It does not create any new objects (of any class). b.aMethod() calls the method "aMethod" for object b. Object b is of class Bar, but "aMethod" is not defined there. It is found in Bar's superclass Foo. This is completely legal. It's like calling b.hashCode() // the hashCode() method is defined in class Object, not in class Bar
          phkim Kim, Pilho added a comment -

          public String aMethod()

          { return this.getX(); // This is a good point. }

          this.getX() is different this.x, because aMethod() exists in Foo,
          which contains the field x in Foo.
          The property x of Foo roles inside Foo/ as a field.
          So "return this.x;" acts differently from "return this.getX()".

          phkim Kim, Pilho added a comment - public String aMethod() { return this.getX(); // This is a good point. } this.getX() is different this.x, because aMethod() exists in Foo, which contains the field x in Foo. The property x of Foo roles inside Foo/ as a field. So "return this.x;" acts differently from "return this.getX()".
          antti.karanta@napa.fi Antti Karanta added a comment -

          > this.getX() is different this.x, because aMethod() exists in Foo,
          > which contains the field x in Foo.
          > The property x of Foo roles inside Foo/ as a field.
          > So "return this.x;" acts differently from "return this.getX()".

          Yes, I know this is what currently happens - that is why test case I provided fails. My point was that should this be so? I asked on the mailing list (before posting a bug report) and at least blackdrag seemed to agree (see a reference to the mailing list above).

          This issue boils down to two things:

          1) When using groovy notation (reference.nameOfProperty) to access a property of an object and both an accessible instance variable and a property accessor (or mutator, depending whether reading or writing) exist, which one should take precedence? From your comment above it seems the instance variable takes precedence. This seems logical, as otherwise accessing the instance variable would be impossible.
          2) Does @Property mean that an instance variable w/ the same name as that of the property itself is generated into the class? I think it should be different for disambiguity. That way I could access the property from within the class the same way as from outside it (this.nameOfProperty).

          I think it is very counterintuitive that the following fails:

          // insert this code in aMethod in my original example - the assert fails
          def o = this
          assert this.x == o.x

          The assert above would not fail if this.x was property access.

          antti.karanta@napa.fi Antti Karanta added a comment - > this.getX() is different this.x, because aMethod() exists in Foo, > which contains the field x in Foo. > The property x of Foo roles inside Foo/ as a field. > So "return this.x;" acts differently from "return this.getX()". Yes, I know this is what currently happens - that is why test case I provided fails. My point was that should this be so? I asked on the mailing list (before posting a bug report) and at least blackdrag seemed to agree (see a reference to the mailing list above). This issue boils down to two things: 1) When using groovy notation (reference.nameOfProperty) to access a property of an object and both an accessible instance variable and a property accessor (or mutator, depending whether reading or writing) exist, which one should take precedence? From your comment above it seems the instance variable takes precedence. This seems logical, as otherwise accessing the instance variable would be impossible. 2) Does @Property mean that an instance variable w/ the same name as that of the property itself is generated into the class? I think it should be different for disambiguity. That way I could access the property from within the class the same way as from outside it (this.nameOfProperty). I think it is very counterintuitive that the following fails: // insert this code in aMethod in my original example - the assert fails def o = this assert this.x == o.x The assert above would not fail if this.x was property access.
          phkim Kim, Pilho added a comment -

          >> Here b.x equals b.getX()
          >> But b.aMethod() equals new Foo().getX()
          >
          > Huh? The definiton of aMethod is
          >
          > def aMethod()

          { > this.x > }


          >
          > Which just returns the value for the property x for the current object. It does not create any new objects (of any class).
          >

          Because aMethod(0 exists in Foo itself, this.x means the field x of an instance of Foo itself.
          If we suppose that you are right, we can never access to the field of Foo directly in Foo itself.

          class Foo {
          @Property x = "foo"

          Obejct getX()

          { // What is this.x here? Do you want an infinite loop here? retrun someThing. }

          ........................................
          ........................................
          }

          > b.aMethod() calls the method "aMethod" for object b. Object b is of class Bar, but "aMethod" is
          > not defined there. It is found in Bar's superclass Foo. This is completely legal. It's like calling
          > b.hashCode() // the hashCode() method is defined in class Object, not in class Bar

          I hope that the next example will help you.

          X---------------------------------------------------------
          class TestClass {
          @Property x = "foo"
          public Object getX()

          { return x + " by getX()" }

          def aMethod()

          { return this.x }

          def bMethod()

          { return this.getX() }

          }

          def a = new TestClass()
          println( a.aMethod() )
          println( a.bMethod() )
          println( a.x )
          println( a instanceof GroovyObject )
          assert( a.aMethod() == "foo" )
          assert( a.bMethod() == "foo by getX()" )
          assert( a instanceof GroovyObject )
          assert( a.x == "foo by getX()" )
          X---------------------------------------------------------

          phkim Kim, Pilho added a comment - >> Here b.x equals b.getX() >> But b.aMethod() equals new Foo().getX() > > Huh? The definiton of aMethod is > > def aMethod() { > this.x > } > > Which just returns the value for the property x for the current object. It does not create any new objects (of any class). > Because aMethod(0 exists in Foo itself, this.x means the field x of an instance of Foo itself. If we suppose that you are right, we can never access to the field of Foo directly in Foo itself. class Foo { @Property x = "foo" Obejct getX() { // What is this.x here? Do you want an infinite loop here? retrun someThing. } ........................................ ........................................ } > b.aMethod() calls the method "aMethod" for object b. Object b is of class Bar, but "aMethod" is > not defined there. It is found in Bar's superclass Foo. This is completely legal. It's like calling > b.hashCode() // the hashCode() method is defined in class Object, not in class Bar I hope that the next example will help you. X--------------------------------------------------------- class TestClass { @Property x = "foo" public Object getX() { return x + " by getX()" } def aMethod() { return this.x } def bMethod() { return this.getX() } } def a = new TestClass() println( a.aMethod() ) println( a.bMethod() ) println( a.x ) println( a instanceof GroovyObject ) assert( a.aMethod() == "foo" ) assert( a.bMethod() == "foo by getX()" ) assert( a instanceof GroovyObject ) assert( a.x == "foo by getX()" ) X---------------------------------------------------------

          I should clarify some things. Besides how groovy does behave the important thing is how groovy SHOULD bahave!

          for JSR we decided that the property access is overlaying the field access. This means:

          a = this.x

          is in all cases a property access if there is a proeprty x OR a getter getX(). For the case we want a field of the same name we have to use:

          a = this.@c

          same for setter. For inheritance this means:

          class Foo {
          @Property x = "foo"
          def aMethod()

          { this.x }

          }

          class Bar extends Foo {
          @Property x = "bar"
          }

          the "this.x" in Foo is the property access, so this.x is equal to this.getX(). This means

          b = new Bar();
          assert b.x=="bar"
          assert b.aMethod()=="bar"

          if you modify the above code:

          class Foo {
          @Property x = "foo"
          def aMethod()

          { this@.x }

          }

          class Bar extends Foo {
          @Property x = "bar"
          }

          then:

          b = new Bar();
          assert b.x=="bar"
          assert b.aMethod()=="foo"

          blackdrag Jochen Theodorou added a comment - I should clarify some things. Besides how groovy does behave the important thing is how groovy SHOULD bahave! for JSR we decided that the property access is overlaying the field access. This means: a = this.x is in all cases a property access if there is a proeprty x OR a getter getX(). For the case we want a field of the same name we have to use: a = this.@c same for setter. For inheritance this means: class Foo { @Property x = "foo" def aMethod() { this.x } } class Bar extends Foo { @Property x = "bar" } the "this.x" in Foo is the property access, so this.x is equal to this.getX(). This means b = new Bar(); assert b.x=="bar" assert b.aMethod()=="bar" if you modify the above code: class Foo { @Property x = "foo" def aMethod() { this@.x } } class Bar extends Foo { @Property x = "bar" } then: b = new Bar(); assert b.x=="bar" assert b.aMethod()=="foo"
          phkim Kim, Pilho added a comment -

          If GROOVY-1025 has not been fixed,
          how can we change the value of this.@x in the super class Foo ?

          phkim Kim, Pilho added a comment - If GROOVY-1025 has not been fixed, how can we change the value of this.@x in the super class Foo ?
          phkim Kim, Pilho added a comment -

          Hi Jochen

          Suppose that your point is right.
          Then we should use the syntax "this.@someField" in many places,
          it make Groovy very different from Java.

          IMO, such a feature is not good.

          What do you think abut this?

          phkim Kim, Pilho added a comment - Hi Jochen Suppose that your point is right. Then we should use the syntax "this.@someField" in many places, it make Groovy very different from Java. IMO, such a feature is not good. What do you think abut this?

          1) getter and setter should really only do as much work as possible. Ideally just get the value of the field
          2) if following 1, ther is no difference between this.x and this.@x
          3) most groovy classes will follow this convention and therefor is no this.@ needed
          4) if not following the rule 1 you need something to know when you mean the field and when you mean the property object.property is normal for groovy to access the property from outside, then why not use the property way for this.x too? Making this.x always a field access when there is a field x and prefer it over the property means inconsistent behavior between inside the class and outside

          So I think prefering the properties when there is a proeprty like access as with object.proeprty is the best solution. I too think that this.@x should fail if there is no field x. the .@ notation should NEVER fall back to the property access to avoid confusion.

          blackdrag Jochen Theodorou added a comment - 1) getter and setter should really only do as much work as possible. Ideally just get the value of the field 2) if following 1, ther is no difference between this.x and this.@x 3) most groovy classes will follow this convention and therefor is no this.@ needed 4) if not following the rule 1 you need something to know when you mean the field and when you mean the property object.property is normal for groovy to access the property from outside, then why not use the property way for this.x too? Making this.x always a field access when there is a field x and prefer it over the property means inconsistent behavior between inside the class and outside So I think prefering the properties when there is a proeprty like access as with object.proeprty is the best solution. I too think that this.@x should fail if there is no field x. the .@ notation should NEVER fall back to the property access to avoid confusion.
          phkim Kim, Pilho added a comment -

          > the .@ notation should NEVER fall back to the property access to avoid confusion.

          .@ is not an operator to access a property, but an operator to access a field or an attribute.

          phkim Kim, Pilho added a comment - > the .@ notation should NEVER fall back to the property access to avoid confusion. .@ is not an operator to access a property, but an operator to access a field or an attribute.

          >.@ is not an operator to access a property, but an operator to access a field or an attribute.

          that's what I have said, or not? if we declare a property through:

          @Property x

          then we generate a setter, a getter and a field for x

          this.@x will access the field and never execute the getter or setter

          blackdrag Jochen Theodorou added a comment - >.@ is not an operator to access a property, but an operator to access a field or an attribute. that's what I have said, or not? if we declare a property through: @Property x then we generate a setter, a getter and a field for x this.@x will access the field and never execute the getter or setter
          phkim Kim, Pilho added a comment -

          this.x should mean the field x not getX() inside the same class.

          If not, you can open this issue in the developer list.

          phkim Kim, Pilho added a comment - this.x should mean the field x not getX() inside the same class. If not, you can open this issue in the developer list.
          antti.karanta@napa.fi Antti Karanta added a comment -

          I don't know whether this is the same issue, but looks like it. In the code below, the assert fails.

          – clip –

          class Base {

          def getFoo()

          {null}

          }

          class Child extends Base {
          @Property foo = "giddya!"
          }

          def c = new Child()

          assert c.foo == c.getFoo()

          – clip –

          So, from outside the class c.foo returns the value of the property, but c.getFoo() calls the superclass method. What's going on here? I think we all agree that from outside the class, with no instance variables visible, c.foo and c.getFoo() should be equivalent?

          antti.karanta@napa.fi Antti Karanta added a comment - I don't know whether this is the same issue, but looks like it. In the code below, the assert fails. – clip – class Base { def getFoo() {null} } class Child extends Base { @Property foo = "giddya!" } def c = new Child() assert c.foo == c.getFoo() – clip – So, from outside the class c.foo returns the value of the property, but c.getFoo() calls the superclass method. What's going on here? I think we all agree that from outside the class, with no instance variables visible, c.foo and c.getFoo() should be equivalent?

          the getFoo method from the property is only added if there is no getFoo method.
          I think as we should try to hide implementation details and affort as less implementation knowledge as possible, the user should be given a compiletime error here. The error should be something like: "implicit declaration of method getFoo() through property foo will overwrite method getFoo() in the superclass Base. Please write an explicit declaration of that method in Child (for example 'def getFoo()

          { this.@foo}

          ', or 'def getFoo()

          {super.getFoo()}

          ') if you wish to overwrite it."

          Why that message? Because I think it smells like bad design having such a construction. And because I think people will not have this very often. So I think going the less implicit way here is much clearer

          blackdrag Jochen Theodorou added a comment - the getFoo method from the property is only added if there is no getFoo method. I think as we should try to hide implementation details and affort as less implementation knowledge as possible, the user should be given a compiletime error here. The error should be something like: "implicit declaration of method getFoo() through property foo will overwrite method getFoo() in the superclass Base. Please write an explicit declaration of that method in Child (for example 'def getFoo() { this.@foo} ', or 'def getFoo() {super.getFoo()} ') if you wish to overwrite it." Why that message? Because I think it smells like bad design having such a construction. And because I think people will not have this very often. So I think going the less implicit way here is much clearer
          phkim Kim, Pilho added a comment -

          This code works fine. The difference is the return type of getFoo(). That is, String vs Object

          X---------------------------------------------------
          class Base {

          public String getFoo()

          {null}

          }

          class Child extends Base

          { @Property foo = "giddya!" }

          def c = new Child()

          assert c.foo == c.getFoo()
          X---------------------------------------------------

          If you compare the byte codes generated by the command "groovyc", then
          you will get more accurate informations.

          c.foo // This invokes the method getProperty() internally.
          c.getFoo() // This invokes the method invokeNoArgumentsMethod() internally.

          Here is a part of my comapre.
          X---------------------------------------------------
          86: aload_0
          87: ldc #54 <String "c">
          89: invokestatic #62 <Method java.lang.Object getGroovyObjectProperty(groovy.lang.GroovyObject, java.lang.String)>
          92: ldc #64 <String "foo">
          94: invokestatic #68 <Method java.lang.Object getProperty(java.lang.Object, java.lang.String)>
          97: aload_0
          98: ldc #54 <String "c">
          100: invokestatic #62 <Method java.lang.Object getGroovyObjectProperty(groovy.lang.GroovyObject, java.lang.String)>
          103: ldc #72 <String "getFoo">
          105: invokestatic #75 <Method java.lang.Object invokeNoArgumentsMethod(java.lang.Object, java.lang.String)>
          108: invokestatic #79 <Method boolean compareEqual(java.lang.Object, java.lang.Object)>
          X---------------------------------------------------

          phkim Kim, Pilho added a comment - This code works fine. The difference is the return type of getFoo(). That is, String vs Object X--------------------------------------------------- class Base { public String getFoo() {null} } class Child extends Base { @Property foo = "giddya!" } def c = new Child() assert c.foo == c.getFoo() X--------------------------------------------------- If you compare the byte codes generated by the command "groovyc", then you will get more accurate informations. c.foo // This invokes the method getProperty() internally. c.getFoo() // This invokes the method invokeNoArgumentsMethod() internally. Here is a part of my comapre. X--------------------------------------------------- 86: aload_0 87: ldc #54 <String "c"> 89: invokestatic #62 <Method java.lang.Object getGroovyObjectProperty(groovy.lang.GroovyObject, java.lang.String)> 92: ldc #64 <String "foo"> 94: invokestatic #68 <Method java.lang.Object getProperty(java.lang.Object, java.lang.String)> 97: aload_0 98: ldc #54 <String "c"> 100: invokestatic #62 <Method java.lang.Object getGroovyObjectProperty(groovy.lang.GroovyObject, java.lang.String)> 103: ldc #72 <String "getFoo"> 105: invokestatic #75 <Method java.lang.Object invokeNoArgumentsMethod(java.lang.Object, java.lang.String)> 108: invokestatic #79 <Method boolean compareEqual(java.lang.Object, java.lang.Object)> X---------------------------------------------------
          phkim Kim, Pilho added a comment -

          Here are two examples, the difference of them is the order of two say()'s.
          But their outputs are differents.
          That is, the latter say() is invoked.
          Of course, this bad mathod overload is not allowed in Java.
          Then is this a bug of Groovy or a feature of Groovy?

          X---------------------------------------------------
          class BadOverloadTest {
          public String say()

          { return "string" }

          public Object say() { return new Long(100) }

          public static void main(args) { def a = new BadOverloadTest() println (a.say()) }
          }
          X---------------------------------------------------
          Output is:
          100


          X---------------------------------------------------
          class BadOverloadTest {
          public Object say() { return new Long(100) }

          public String say() { return "string" }

          public static void main(args)

          { def a = new BadOverloadTest() println (a.say()) }

          }
          X---------------------------------------------------
          Output is:
          string

          phkim Kim, Pilho added a comment - Here are two examples, the difference of them is the order of two say()'s. But their outputs are differents. That is, the latter say() is invoked. Of course, this bad mathod overload is not allowed in Java. Then is this a bug of Groovy or a feature of Groovy? X--------------------------------------------------- class BadOverloadTest { public String say() { return "string" } public Object say() { return new Long(100) } public static void main(args) { def a = new BadOverloadTest() println (a.say()) } } X--------------------------------------------------- Output is: 100 X--------------------------------------------------- class BadOverloadTest { public Object say() { return new Long(100) } public String say() { return "string" } public static void main(args) { def a = new BadOverloadTest() println (a.say()) } } X--------------------------------------------------- Output is: string

          People

            phkim Kim, Pilho
            antti.karanta@napa.fi Antti Karanta
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: