mg, > On 15 Aug 2018, at 1:33 AM, mg <mg...@arscreat.com> wrote: > > 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.
Which is a serious problem. Rarely you want „a whole method be skipped (and return null) if anything inside of it happens to be null“. What you normally want is the null-propagation, e.g., def foo=bar.baz[bax]?:default_value; ... other code ... The other code is always performed and never skipped (unless another exception occurs of course); but the null-propagation makes sure that if bar or bar.baz happens to be a null, then default_value is used. And so forth. > To give a simple example: > > final x = a?.b?.c?.d > > could be written as > > final x = neval { a.b.c.d } Precisely. Do please note that even your simple example did not put a whole method body into neval, but just one sole expression instead. Essentially all expressions — often sub-expressions, wherever things like Elvis are used — would have to be embedded in nevals separately. Which is, alas, far from feasible. > 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... That indeed would not be a problem. > (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) This one possibly would though: I do expect my code to encounter null values often — with some code, they might well be the normal case with a non-null an exception. That's precisely why I do not want NPEs (but the quick, efficient and convenient null-propagation instead) :) Thanks and all the best, OC > -------- 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 >> <mailto: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 <mailto:o...@ocs.cz>> >> Datum: 14.08.18 17:46 (GMT+00:00) >> An: dev@groovy.apache.org <mailto:dev@groovy.apache.org> >> Betreff: Re: suggestion: ImplicitSafeNavigation annotation >> >> Jochen, >> >>> On 14 Aug 2018, at 6:25 PM, Jochen Theodorou <blackd...@gmx.org >>> <mailto: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=null >> println "Should be null: ${s?.plus('foo')}" >> 255 /tmp> /usr/local/groovy-2.4.15/bin/groovy q >> WARNING: An illegal reflective access operation has occurred >> ... ... >> Should be null: null >> 256 /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 >> >> >> >