groovy-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "ocs@ocs" <...@ocs.cz>
Subject Re: suggestion: ImplicitSafeNavigation annotation
Date Thu, 16 Aug 2018 02:40:14 GMT
Irrelevant, for both of those are the very same Groovy False :)

> On 15 Aug 2018, at 11:24 PM, mg <mgbiz@arscreat.com> wrote:
> 
> Sorry, bad/incorrect example, should read: Do you expect/want
> 
> true && null == null  // null == UNKNOWN
> 
> or
> 
> true && null == false // Groovy-truth-null
> 
> ?
> 
> 
> 
> -------- Ursprüngliche Nachricht --------
> Von: "ocs@ocs" <ocs@ocs.cz>
> Datum
> 
> -------- Ursprüngliche Nachricht --------
> Von: mg <mgbiz@arscreat.com>
> Datum: 15.08.18 13:07 (GMT+00:00)
> An: dev@groovy.apache.org
> Betreff: Re: suggestion: ImplicitSafeNavigation annotation
> 
> Another question: How do you see boolean operations including null bein handled ? Classical
would be to again have most operations return null. Or should null be interpreted as false
here ?
> 
> E.g.
> true || null == null
> or
> true || null == false
> ?
> 
> 
> 
> -------- Ursprüngliche Nachricht --------
> Von: "ocs@ocs" <ocs@ocs.cz>
> Datum: 15.08.18 03:18 (GMT+00:00)
> An: dev@groovy.apache.org
> Betreff: Re: suggestion: ImplicitSafeNavigation annotation
> 
> mg,
> 
>> On 15 Aug 2018, at 3:26 AM, mg <mgbiz@arscreat.com <mailto:mgbiz@arscreat.com>>
wrote:
>> 
>> Fair enough (I am typing this on my smartphone on vacation, so keep samples small;
also (your) more complex code samples are really hard to read in my mail reader). It still
seems to be a big paradigm change
> 
> I might be missing something of importance here, but I can't see any paradigm change;
not even the slightest shift.
> 
> The only change suggested is that one could — in the extent of one needs that, which
would self-evidently differ for different people — decide whether the “safe” behaviour
is explicitly triggered by using the question-mark syntax, or whether it is implicit.
> 
>> since regular Java/Groovy programs typically have very little null values
> 
> The very existence of ?. and ?[] suggests it is not quite the case — otherwise, nobody
would ever bother designing and implementing them.
> 
>> so am not convinced this is worth the effort (and as Jochen pointed out, there will
still be cases where null will just be converted to "null").
> 
> Are there? Given my limited knowledge, I know of none such. “null?.plus('foo')” yields
a null, and so — for a consistency sake — very definitely should also “null?+'foo'”
and “@ImplicitSafeNavigation ... null+foo”, had they existed.
> 
>> What I would suggest instead is considering to introduce nil, sql_null, empty, ...
as type agnostic constants in addition to the existing null in Groovy. That way you could
use e.g. nil in your code, which by definition exhibits your expected behavior, but it would
make the usage more explicit, and one would not need to switch/bend the existing null semantics...
> 
> That's a nice idea; alas, so that it is viable, one would also have to be able to set
up which kind of null is to be returned from expressions like “aMap['unknownkey']“ or
“list.find { never-matches }” etc.
> 
> Thus, instead of my “@ImplicitSafeNavigation(true)” you would have to use something
like “@DefaultNullClass(nil)” — and instead of “@ImplicitSafeNavigation(false)”
you would need something like “@DefaultNullClass(null)”.
> 
> Along with that, you would need a way to return “the current default null” instead
of just null; there would be a real problem with a legacy code which returns null (but should
return “the current default null” instead), and so forth.
> 
> That all said, it definitely is an interesting idea worth checking; myself, though, I
do fear it would quickly lead to a real mess (unlike my suggestion, which is considerably
less flexible, but at the same moment, very simple and highly intuitive).
> 
> Thanks and all the best,
> OC
> 
>> -------- Ursprüngliche Nachricht --------
>> Von: "ocs@ocs" <ocs@ocs.cz <mailto:ocs@ocs.cz>>
>> Datum: 15.08.18 00:53 (GMT+00:00)
>> An: dev@groovy.apache.org <mailto:dev@groovy.apache.org>
>> Betreff: Re: suggestion: ImplicitSafeNavigation annotation
>> 
>> mg,
>> 
>>> On 15 Aug 2018, at 1:33 AM, mg <mgbiz@arscreat.com <mailto:mgbiz@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" <ocs@ocs.cz <mailto:ocs@ocs.cz>>
>>> Datum: 14.08.18 23:14 (GMT+00:00)
>>> An: dev@groovy.apache.org <mailto:dev@groovy.apache.org>
>>> Betreff: Re: suggestion: ImplicitSafeNavigation annotation
>>> 
>>> mg,
>>> 
>>>> On 14 Aug 2018, at 11:36 PM, mg <mgbiz@arscreat.com <mailto:mgbiz@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" <ocs@ocs.cz <mailto:ocs@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 <blackdrag@gmx.org <mailto:blackdrag@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
>>>> 
>>>> 
>>>> 
>>> 
>> 
> 


Mime
View raw message