That's not how I meant my sample eval helper method to be used :-)
(for brevity I will write neval for eval(true) here)

What I meant was: How easy would it be to get a similar result to what you 
want, by wrapping a few key places (e.g. a whole method body) in your code in 
neval { ... } ? Evidently that would just mean that any NPE inside the e.g. 
method would lead to the whole method result being null. 
To give a simple example:
final x = a?.b?.c?.d
could be written as
final x = neval { a.b.c.d }
Of course the two expressions are not semantically identical, since neval will 
transform any NPE inside evaluation of a, b, c, and d into the result null - 
but since you say you never want to see any NPEs...
(The performance of neval should be ok, since I do not assume that you expect 
your code to actually encounter null values, and accordingly NPEs, all the time)

-------- Ursprüngliche Nachricht --------Von: "ocs@ocs" <o...@ocs.cz> Datum: 
14.08.18  23:14  (GMT+00:00) An: dev@groovy.apache.org Betreff: Re: suggestion: 
ImplicitSafeNavigation annotation 
mg,

On 14 Aug 2018, at 11:36 PM, mg <mg...@arscreat.com> wrote:
I am wondering: In what case does what you are using/suggesting differ 
significantly from simply catching a NPE that a specific code block throws and 
letting said block evaluate to null in that case:
def eval(bool nullSafeQ, Closure cls) {  try {    return cls()  }  
catch(NullPointerException e) {    if(nullSafeQ) {      return null    }    
throw e  }}

Conceptually, not in the slightest.
In practice, there's a world of difference.
For one, it would be terrible far as the code cleanness, fragility and 
readability are concerned — even worse than those ubiquitous question marks:
=== the code should look, say, like this ===@ImplicitSafeNavigation def 
foo(bar) {  def x=baz(bar.foo)?:bax(bar.foo)  x.allResults {    def y=baz(it)   
 if (y>1) y+bax(y-1)    else y–bax(0)  }}=== the eval-based equivalent would 
probably look somewhat like this ===def foo(bar) {  def 
x=eval(true){baz(eval(true){bar.foo})?:bax(bar.foo)}  eval(true){    
x.allResults {      def y=eval(true){baz(it)}      if (y>1) 
eval(true){y+bax(y-1)}      else eval(true){y–bax(0)}    }  }}===
and quite frankly I am not even sure whether the usage of eval above is right 
and whether I did not forget to use it somewhere where it should have been. It 
would be ways easier with those question marks.
Also, with the eval block, there might be a bit of a problem with the type 
information: I regret to say I do not know whether we can in Groovy declare a 
method with a block argument in such a way that the return type of the function 
is automatically recognised by the compiler as the same type as the block 
return value? (Definitely I don't know how to do that myself; Cédric or Jochen 
might, though ;))
Aside of that, I wonder about the efficiency; although premature optimisation 
definitely is a bitch, still an exception harness is not cheap if an exception 
is caught, I understand.
(It feels a bit like what you wants is tri-logic/SQL type NULL support in 
Groovy, not treating Java/Groovy null differently...)
In fact what I want is a bit like the Objective-C simple but very efficient and 
extremely practical nil behaviour, to which I am used to and which suits me 
immensely.
Agreed, the Java world takes a different approach (without even the safe 
navigation where it originated!); I have tried to embrace that approach a 
couple of times, and always I have found it seriously lacking.
I do not argue that the null-propagating behaviour is always better; on the 
other hand, I do argue that sometimes and for some people it definitely is 
better, and that Groovy should support those times and people just as well as 
it supports the NPE-based approach of Java.
Thanks and all the best,OC
-------- Ursprüngliche Nachricht --------Von: "ocs@ocs" <o...@ocs.cz> Datum: 
14.08.18  17:46  (GMT+00:00) An: dev@groovy.apache.org Betreff: Re: suggestion: 
ImplicitSafeNavigation annotation 
Jochen,

On 14 Aug 2018, at 6:25 PM, Jochen Theodorou <blackd...@gmx.org> wrote:Am 
14.08.2018 um 15:23 schrieb ocs@ocs:
H2,
However, “a+b” should work as one would expect
Absolutely. Me, I very definitely expect that if a happens to be null, the 
result is null too. (With b null it depends on the details of a.plus 
implementation.)

the counter example is null plus String though

Not for me. In my world, if I am adding a string to a non-existent object, I 
very much do expect the result is still a non-existent object. Precisely the 
same as if I has been trying to turn it to lowercase or to count its character 
or anything.
Whilst I definitely do not suggest forcing this POV to others, to me, it seems 
perfectly reasonable and 100 per cent intuitive.
Besides, it actually (and expectably) does work so, if I use the method-syntax 
to be able to use safe navigation:
===254 /tmp> <q.groovy String s=nullprintln "Should be null: 
${s?.plus('foo')}"255 /tmp> /usr/local/groovy-2.4.15/bin/groovy qWARNING: An 
illegal reflective access operation has occurred... ...Should be null: null256 
/tmp> ===
which is perfectly right. Similarly, a hypothetical “null?+'foo'” or 
“@ImplicitSafeNavigation ... null+foo” should return null as well, to keep 
consistent.
(Incidentally, do you — or anyone else — happen to know how to get rid of those 
pesky warnings?)
Thanks and all the best,OC



Reply via email to