[ https://issues.apache.org/jira/browse/GROOVY-11508?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17892860#comment-17892860 ]
Jochen Theodorou commented on GROOVY-11508: ------------------------------------------- [~jdaugherty] I think that we are talking about a trait is a bit of a false flag in the end. This code here {code:java} interface GormEntity<D> {} class Child implements GormEntity<Child> {} class Parent extends Child implements GormEntity<Parent> {} {code} Has no traits, no (static) methods nothing, still the Java compiler does not accept this. The connection to traits comes in play if you do not forget that there is the trait GormEntity for Groovy, but for the JVM this consists of the interface of the same name and some helper classes. Which means we get exactly the above situation, even if you remove all the otherwise generated code. And for the reasoning behind this I have this here [https://bugs.openjdk.org/browse/JDK-8030724] as an interesting read. Then there is the issue with the injected method getAll. In case of {code:java} trait GormEntity<Integer> { static List<Integer> getAll() {null} } class Parent implements GormEntity {} {code} Here Integer is not the class Integer, it is the generics placeholder like you normally use T: {code:java} trait GormEntity<D> { static List<D> getAll() {null} } class Parent implements GormEntity {} {code} Since the base type for D is Object using GormEntity is equal to GormEntity<Object> Now coming back to the original problem.... According to [http://docs.groovy-lang.org/docs/groovy-2.3.0/html/documentation/core-traits.html#_default_conflict_resolution] we have a conflict resolution specified in case of two traits providing a method with equal signature. That means in case of X implements GormEntity<String>, GormEntity<Integer> we would have a getAll returning List<Integer> and in the reverse case List<String>. Let us assume we have {code:java} trait GormEntity<D1> { List<D1> getAll() {null} } trait GormEntity2<D2> { List<D2> getAll() {null} } class Child implements GormEntity<Child>{} class Parent extends Child implements GormEntity2<Parent> {} {code} So without the static modifier. Then we get a List<Child>, that looks like List<Object> in Child and a List<Parent>, that looks like List<Object> in Parent, overriding the one in child, because the method signatures are equal after type erasure. That means Parent will have the method from GormEntity2. Now assume this in Java: {code:java} Parent parent = new Parent() Child child = parent List<Child> lc = child.getAll() List<Parent> ld = parent.getAll() {code} How can calling the same method produce one time List<Child> and another time List<Parent>? It cannot, and the Java compiler would refuse compiling the line for lc.. Therefore I am not really too keen on allowing the implementation of multiple parametrized interfaces of same name with different parameter configurations. In theory it could be allowed unless there is a conflict, but then there is the recompilation issue... feels like a can of worms to reopen here. Which means for me that the case of a static modifier is actually something where we have to take different aspects into consideration. One of them being that static methods are not really inherited like in the last variant. Parent.getAll() can call a different method than Child.getAll(). And [http://docs.groovy-lang.org/docs/groovy-2.3.0/html/documentation/core-traits.html#_static_methods_properties_and_fields] states that static methods are experimental. My suggestion would be to modify the way static aspects work by add an annotation preventing the trait interface to be added to the class receiving the trait. This would solve the problem for the static methods by simply putting them in a trait and use the annotation for the marker interface to not be used. Looking at https://github.com/grails/grails-data-mapping/blob/9.0.x/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/GormEntity.groovy I see two more groups of methods though... MOP related methods without generics, which are no problem... but then also methods like save(). Or as you mentioned already, refresh(). There would be in theory a solution using extension methods. Of course that means they are not callable from Java, not normally. > Multiple traits with related generic types cannot be used > --------------------------------------------------------- > > Key: GROOVY-11508 > URL: https://issues.apache.org/jira/browse/GROOVY-11508 > Project: Groovy > Issue Type: Bug > Components: Compiler > Affects Versions: 4.0.0 > Reporter: James Daugherty > Assignee: Eric Milles > Priority: Major > Attachments: screenshot-1.png, screenshot-2.png, screenshot-3.png > > > When updating Grails from Groovy 3.x to 4.x we discovered that GROOVY-5106 > prevents us from updating to Groovy 4 for the > [grails-data-mapping|https://github.com/grails/grails-data-mapping] (GORM) > project. Groovy-5106 does not take into account relationships between > generic types and groovy does not support inheritance in generic types on > traits so we have no workable solution for using Groovy 4. > > For example, the following is not possible in Groovy 4: > {code:java} > class Parent extends GormEntity<Parent> { > } > class Child extends GormEntity<Child> { > } > class GormEntity<? extends GormEntity> { // ? extends GormEntity is not > allowed > }{code} > > We have documented the impacts of this issue on the grails-data-mapping > project here: [https://github.com/grails/grails-data-mapping/issues/1811] > We have discovered that the original change could be reverted and continue to > work with the latest Java & Groovy. > > For Grails Data Mapping (GORM), there is support for inheritance between a > Parent & Child domain object. This is often implemented like this: > {code:java} > class Parent extends GormEntity<Parent> { > } > class Child extends GormEntity<Child> { > } > trait GormEntity<D> { // Simplified for this ticket > static D get(Serializable id) > > static List<D> getAll() > } > {code} > This allows someone to do the following in code: > {code:java} > Parent.get(1L) // Will find either a Child or Parent > Child.get(1L) // Will find only child types{code} > > Since Groovy-5106 does not take into account inheritance, can this change be > reverted or changed to a warning until inheritance is taken into account? -- This message was sent by Atlassian Jira (v8.20.10#820010)