[ https://issues.apache.org/jira/browse/GROOVY-7750?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15284401#comment-15284401 ]
Paul King edited comment on GROOVY-7750 at 5/16/16 11:45 AM: ------------------------------------------------------------- It is an interesting edge case that raises a few questions in my mind. It should be noted that there are arguably some slight inconsistencies in current behavior even ignoring @Lazy for the moment, e.g. take this code: {code} abstract class Foo {} new Foo() {code} This currently returns a compilation error: {noformat} You cannot create an instance from the abstract class 'Foo'. {noformat} However, this slight change: {code} abstract class Foo {} Foo.newInstance() {code} gives the previously mentioned {{InstantiationException}}. However, with some metaprogramming, this works fine: {code} abstract class Foo {} Foo.metaClass.constructor = { new Foo() {} } Foo.newInstance() {code} So, perhaps the compilation error (which we added 6 years ago) is arguably too strong for a dynamic language - but fine if TypeChecked or CompileStatic were in play. I can't recall all the discussion but I suspect at the time we were trying to catch a common developer mistake without the benefit of having TypeChecked/CompileStatic as an option. We can't easily cover all reflective code possibilities so we only handle the most common case. I don't necessarily have a problem with this inconsistency but I suspect it isn't well documented. So, now looking at the @Lazy situation, I think the case which needs to be handled is the special behavior when no initial value is given and the no-arg constructor is lazily called if needed to create a new instance (that's the equivalent to the {{new Foo()}} case above). If we wanted to be fully dynamic, there isn't much we can do apart from catching the {{InstantiationException}} and re-wrapping it in a nicer way. Ideally, we'd check more rigorously for TypeChecked/CompileStatic but that isn't simple. If however, we wanted to have some compromise (trading off some dynamic capability in return for catching a few more likely error cases at compile time), then we can easily check the type that would be instantiated for the case when there is no initial value and return a compilation error somewhat similar to the initial compilation exception at the start of this comment. So, I'm suggesting that this code: {code} abstract class Foo {} class Demo { @Lazy Foo foo } {code} might fail compilation with a message something like: {noformat} You cannot lazily create an instance from the abstract class 'Foo' for field 'foo'. {noformat} was (Author: paulk): It is an interesting edge case that raises a few questions in my mind. It should be noted that there are arguably some slight inconsistencies in current behavior even ignoring @Lazy for the moment, e.g. take this code: {code} abstract class Foo {} new Foo() {code} This currently returns a compilation error: {noformat} You cannot create an instance from the abstract class 'Foo'. {noformat} However, this slight change: {code} abstract class Foo {} Foo.newInstance() {code} gives the previously mentioned {{InstantiationException}}. However, with some metaprogramming, this works fine: {code} abstract class Foo {} Foo.metaClass.constructor = { new Foo() {} } Foo.newInstance() {code} So, perhaps the compilation error (which we added 6 years ago) is arguably too strong for a dynamic language - but fine if TypeChecked or CompileStatic were in play. I can't recall all the discussion but I suspect at the time we were trying to catch a common developer mistake without the benefit of having TypeChecked/CompileStatic as an option. We can't easily cover all reflective code possibilities so we only handle the most common case. I don't necessarily have a problem with this inconsistency but I suspect it isn't well documented. So, now looking at the @Lazy situation. If we wanted to be fully dynamic, there isn't much we can do apart from catching the {{InstantiationException}} and re-wrapping it in a nicer way. Ideally, we'd check more rigorously for TypeChecked/CompileStatic but that isn't simple. If however, we wanted to have some compromise (trading off some dynamic capability in return for catching a few more likely error cases at compile time), then we can easily check the type that would be instantiated for the case when there is no initial value and return a compilation error somewhat similar to the initial compilation exception at the start of this comment. So, I'm suggesting that this code: {code} abstract class Foo {} class Demo { @Lazy Foo foo } {code} might fail compilation with a message something like: {noformat} You cannot lazily create an instance from the abstract class 'Foo' for field 'foo'. {noformat} > @Lazy allows instantiation of abstract class > -------------------------------------------- > > Key: GROOVY-7750 > URL: https://issues.apache.org/jira/browse/GROOVY-7750 > Project: Groovy > Issue Type: Bug > Components: groovy-runtime > Affects Versions: 2.4.4 > Reporter: Johann > Priority: Minor > Labels: usability > > Given this code: > {code:java} > @Lazy > Foo foo > abstract class Foo {} > {code} > You'll get: > {code} > java.lang.InstantiationException > at > sun.reflect.InstantiationExceptionConstructorAccessorImpl.newInstance(InstantiationExceptionConstructorAccessorImpl.java:48) > at java.lang.reflect.Constructor.newInstance(Constructor.java:526) > at > org.codehaus.groovy.reflection.CachedConstructor.invoke(CachedConstructor.java:80) > at > org.codehaus.groovy.runtime.callsite.ConstructorSite$ConstructorSiteNoUnwrapNoCoerce.callConstructor(ConstructorSite.java:105) > at > org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallConstructor(CallSiteArray.java:60) > at > org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:235) > at > org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:239) > {code} > This isn't really helpful. If I mistype a method name, Groovy will help me > out with suggestions, why not here? > MODIFICATION by blackdrag: > @Lazy should recognize this and fail compilation to avoid the initialization > of an abstract class. -- This message was sent by Atlassian JIRA (v6.3.4#6332)