Jochen,

sorry for the example (I have written it in hurry); it should have looked 
rather like this:

===
266 /tmp> <q.groovy 
class q {
    static main(args) {
        def mc=new OCSNMC(org.codehaus.groovy.runtime.NullObject)
        mc.initialize()
        org.codehaus.groovy.runtime.NullObject.metaClass=mc

        println "null.foo() is OK: ${null.foo()==null}"
        println "null+null is OK: ${null+null==null}"
        println "null[null] is OK (and no 3 needed, ha!): ${null[null]==null}"
        println "null.foo though we won't see: ${null.foo==null}"
    }
}

class OCSNMC extends DelegatingMetaClass {
    OCSNMC(Class clazz) { super(clazz) }
    Object invokeMethod(Object object, String methodName, Object[] arguments) { 
null }
    Object getProperty(Class sender, Object receiver, String property, boolean 
isCallToSuper, boolean fromInsideClass) {
        println "getProperty called!" // actually never happens, dunno why
        null
    }
}
267 /tmp> /usr/local/groovy-2.4.15/bin/groovy q
null.foo() is OK: true
null+null is OK: true
null[null] is OK (and no 3 needed, ha!): true
Caught: java.lang.NullPointerException: Cannot get property 'foo' on null object
java.lang.NullPointerException: Cannot get property 'foo' on null object
        at q.main(q.groovy:10)
        at 
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at 
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at 
java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at 
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at 
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at 
java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
268 /tmp> 
===

Thanks and all the best,
OC

> On 14 Aug 2018, at 7:10 PM, ocs@ocs <o...@ocs.cz> wrote:
> 
> Jochen,
> 
>> On 14 Aug 2018, at 6:34 PM, Jochen Theodorou <blackd...@gmx.org 
>> <mailto:blackd...@gmx.org>> wrote:
>> [...]
>>> For the moment, the best solution — far as I have been able to ascertain — 
>>> consists of [*]
>>> (a) at launch, setting own DelegatingMetaClass subclass for a 
>>> Null.metaclass; it essentially would return null from invokeMethod, but 
>>> still needs to process special cases (like e.g., null.is <http://null.is/> 
>>> <http://null.is <http://null.is/>>(foo)) explicitly;
>> 
>> so for general Groovy... how are we supposed to recognized in a transform if 
>> "is" has been replaced?
> 
> It is definitely highly arguable, but in the very specific case of 
> “null?.is(null)“, which currently returns an absurd (though technically 
> understandable) false value, I would rather suggest to break the backward 
> compatibility.
> 
> I can't really see anyone whose code would actually use "?.is", and moreover, 
> rely on that “null?.is(null)“ is valid and returns null (instead of true). Is 
> there such a person in the sweet world?
> 
> Anyway, the point is, I'd say, rather at the unimportant side, for I believe 
> is() is being won't be widely used anyway, given we got === and !=== now.
> 
> Thus, even if we decide that breaking backward compatibility even in this 
> slightly insane case is a big no-no, we just can keep the current behaviour 
> of “null?.is(null)==null“ unchanged. There's no real harm; new code would 
> simply use === instead, and old one would work as before.
> 
>>> (b) since the above for some godforsaken reason does not work for property 
>>> access at all, still implement an ASTT with a 
>>> ClassCodeExpressionTransformer to set expression.safe=true for 
>>> get/setProperty, guarding explicitly against the known problematic cases 
>>> (e.g., super.getProperty).
>> 
>> are you saying x?.foo will NPE if x is null? Or that x?.getFoo() will NPE in 
>> that case? Not sure how to read your comment.
> 
> Provided only (a) “the Null.metaclass; returning null from invokeMethod” is 
> used and no ASTT, then yes, it would NPE. Easiest thing on earth to try:
> 
> ===
> 262 /tmp> <q.groovy                            
> class q {
>     static main(args) {
>         // ExpandoMetaClass.enableGlobally() // I thought this is needed; 
> seems not (though my application use it anyway)
>         def mc=new OCSNMC(org.codehaus.groovy.runtime.NullObject)
>         mc.initialize()
>         org.codehaus.groovy.runtime.NullObject.metaClass=mc
> 
>         println "null.foo() is OK: ${null.foo()==null}"
>         println "null.foo we won't see: ${null.foo==null}"
>     }
> }
> 
> class OCSNMC extends DelegatingMetaClass {
>     OCSNMC(Class clazz){
>         super(clazz)
>     }
>     Object invokeMethod(Object object, String methodName, Object[] arguments) 
> {
>         null
>     }
> }
> 263 /tmp> /usr/local/groovy-2.4.15/bin/groovy q
> null.foo() is OK: true
> Caught: java.lang.NullPointerException: Cannot get property 'foo' on null 
> object
> java.lang.NullPointerException: Cannot get property 'foo' on null object
>       at q.main(q.groovy:9)
>       at 
> java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>       at 
> java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
>       at 
> java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
>       at 
> java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>       at 
> java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
>       at 
> java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
> 264 /tmp> 
> ===
> 
>>> For all I know, this probably would not work properly with @CompileStatic 
>>> (which I do not use at all myself, but others do frequently).
>> 
>> the result type could be a problem... Worth to check.
> 
> Definitely :)
> 
>>> Trust me, been there, done that. I am pretty darn sure it would be 
>>> /infinitely/ easier and, what's important, more reliable in the core with 
>>> an explicit compiler support.
>> 
>> How about making a small github project to dump the current state there?
> 
> Not that easy, for my code is mixed up with other ASTT and runtime stuff; but 
> I'll try to make some simple proof-of-concept ASAP and send here.
> 
> Thanks and all the best,
> OC
> 

Reply via email to