mg,
> On 15 Aug 2018, at 1:33 AM, mg <[email protected]> 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" <[email protected]>
> Datum: 14.08.18 23:14 (GMT+00:00)
> An: [email protected]
> Betreff: Re: suggestion: ImplicitSafeNavigation annotation
>
> mg,
>
>> On 14 Aug 2018, at 11:36 PM, mg <[email protected]
>> <mailto:[email protected]>> 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" <[email protected] <mailto:[email protected]>>
>> Datum: 14.08.18 17:46 (GMT+00:00)
>> An: [email protected] <mailto:[email protected]>
>> Betreff: Re: suggestion: ImplicitSafeNavigation annotation
>>
>> Jochen,
>>
>>> On 14 Aug 2018, at 6:25 PM, Jochen Theodorou <[email protected]
>>> <mailto:[email protected]>> 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
>>
>>
>>
>