From dev-return-5204-archive-asf-public=cust-asf.ponee.io@groovy.apache.org Tue Aug 14 15:07:32 2018 Return-Path: X-Original-To: archive-asf-public@cust-asf.ponee.io Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by mx-eu-01.ponee.io (Postfix) with SMTP id 3910818067A for ; Tue, 14 Aug 2018 15:07:31 +0200 (CEST) Received: (qmail 9521 invoked by uid 500); 14 Aug 2018 13:07:30 -0000 Mailing-List: contact dev-help@groovy.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@groovy.apache.org Delivered-To: mailing list dev@groovy.apache.org Received: (qmail 9451 invoked by uid 99); 14 Aug 2018 13:07:29 -0000 Received: from pnap-us-west-generic-nat.apache.org (HELO spamd2-us-west.apache.org) (209.188.14.142) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 14 Aug 2018 13:07:29 +0000 Received: from localhost (localhost [127.0.0.1]) by spamd2-us-west.apache.org (ASF Mail Server at spamd2-us-west.apache.org) with ESMTP id 3DE801A28F5 for ; Tue, 14 Aug 2018 13:07:29 +0000 (UTC) X-Virus-Scanned: Debian amavisd-new at spamd2-us-west.apache.org X-Spam-Flag: NO X-Spam-Score: 4.499 X-Spam-Level: **** X-Spam-Status: No, score=4.499 tagged_above=-999 required=6.31 tests=[HTML_MESSAGE=2, KAM_LAZY_DOMAIN_SECURITY=1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, RCVD_IN_SORBS_WEB=1.5] autolearn=disabled Received: from mx1-lw-us.apache.org ([10.40.0.8]) by localhost (spamd2-us-west.apache.org [10.40.0.9]) (amavisd-new, port 10024) with ESMTP id m7ThMai6agvO for ; Tue, 14 Aug 2018 13:07:26 +0000 (UTC) Received: from smtp1.czechia.com (smtp1.czechia.com [217.198.120.36]) by mx1-lw-us.apache.org (ASF Mail Server at mx1-lw-us.apache.org) with ESMTPS id 531DD5F300 for ; Tue, 14 Aug 2018 13:07:26 +0000 (UTC) Received: from [10.0.0.141] (12.10.broadband11.iol.cz [90.178.10.12]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: ocs@ocs.cz) by smtp1.czechia.com (Postfix) with ESMTPSA id D766E2009CDC1 for ; Tue, 14 Aug 2018 15:07:18 +0200 (CEST) From: "ocs@ocs" Content-Type: multipart/alternative; boundary="Apple-Mail=_12F52A9D-FD00-4EE7-AE37-A38EBB8A73E9" Mime-Version: 1.0 (Mac OS X Mail 11.4 \(3445.8.2\)) Subject: Re: suggestion: ImplicitSafeNavigation annotation Date: Tue, 14 Aug 2018 15:07:18 +0200 References: <48D11642-A54E-4B6C-B4A8-75A8591AB319@ocs.cz> To: dev@groovy.apache.org In-Reply-To: Message-Id: <5A51B8C3-E8FC-49D9-B6F3-A6D18BA77DE7@ocs.cz> X-Mailer: Apple Mail (2.3445.8.2) --Apple-Mail=_12F52A9D-FD00-4EE7-AE37-A38EBB8A73E9 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=utf-8 Andres, > On 14 Aug 2018, at 2:31 PM, Andres Almiray wrote: > This is a good example of a feature that can be experimented with as = an external AST transformation, there's no need to add it to core just = yet. Not quite, alas. I am experimenting with it for years; it sort of works, = but is far from easy or reliable. To implement the non-NPE null-propagating behaviour solely at the ASTT = side is extremely difficult; you have to cope with all the expressions = explicitly, you have to manage a number of ugly special and side cases = (e.g., AttributeExpression overrides safe as read-only and trying to set = it on throws; an attempt to set the safe attribute for a super.whatever = causes a verify error; null?.is(null) does not work reasonably, etc...) For the moment, the best solution =E2=80=94 far as I have been able to = ascertain =E2=80=94 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(foo)) = explicitly; (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=3Dtrue for = get/setProperty, guarding explicitly against the known problematic cases = (e.g., super.getProperty). For all I know, this probably would not work properly with = @CompileStatic (which I do not use at all myself, but others do = frequently). 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. > Advantages of such approach: > - faster development/release cycle. > - can target specific Groovy version to begin with. > - may break compatibility until feature works as expected. Completely agreed; that's why I am suggesting this only after I used the = ASTT/metaclass approach for years =E2=80=94 and also when a major = version with lots of potential compatibility breaks is about to come = soon anyway. > Adding this feature to core in an early stage (conception) is too = early IMHO. > Remember that @TailCall started life as an external AST xform, it was = added to core when it became mature enough :-) Quite: what I am suggesting is that it's the right time now to add it to = core, alleviating the need of the [*] hacks :) Thanks and all the best, OC > ------------------------------------------- > Java Champion; Groovy Enthusiast > JCP EC Associate Seat > http://andresalmiray.com > http://www.linkedin.com/in/aalmiray = > -- > What goes up, must come down. Ask any system administrator. > There are 10 types of people in the world: Those who understand = binary, and those who don't. > To understand recursion, we must first understand recursion. >=20 > On Tue, Aug 14, 2018 at 1:28 PM, ocs@ocs > wrote: > Gentlemen, >=20 > some NPE-related problems of today brought me to re-interate one of my = older suggestions. >=20 > We have the so-called =E2=80=9Csafe navigation=E2=80=9D[*], which in = some cases allows a null to be propagated out of an expression instead = of throwing a NPE. At the moment, it can be triggered for a particular = sub-expression (like property/method-call and, as of 3, newly also = indexing) using a question mark (e.g., =E2=80=9Cfoo?.bar()=E2=80=9D or = =E2=80=9Cfoo?[bar]=E2=80=9D). >=20 > Do please correct me if I am wrong, but far as I know, there still are = expressions which do not allow the =E2=80=9Csafe mode=E2=80=9D, e.g., = arithmetic (=E2=80=9Ca+b=E2=80=9D etc). Furthermore, there are cases = when one simply wants a bigger block of code to contain only = null-propagating expressions and never NPE; in such case, using the = question mark syntax is both inconvenient and error-prone (for it is = very easy to forget one of the lot of question marks needed in such a = code, and then get an uncaught unwanted NPE). >=20 > For these reasons, I would suggest adding a new annotation, whose name = might be e.g., =E2=80=9CImplicitSafeNavigation=E2=80=9D; it would simply = force a null-propagation to be implicitly and automatically used for = *all* expressions in the annotated scope, i.e., NPE would never be = thrown for them; for example: >=20 > =3D=3D=3D > @ImplicitSafeNavigation class Foo { > static foo(a,b,c,d,e) { > a.bar+b*c[d]< } > } > assert null =3D=3D Foo.foo(null,null,null,null,null) > =3D=3D=3D >=20 > I wonder whether this enhancement would be possible to implement in = some forthcoming Groovy release? Myself, I believe it would help = tremendously. >=20 > If feasible, then it is for a further discussion whether in the scope = of this annotation > (a) a safe-navigation syntax (=E2=80=9Cfoo?.bar=E2=80=9D) should be = ignored as superfluous; > (b) or, whether in this scope it should reverse the behaviour to = trigger an NPE anyway; > (c) or, whether it should be ignored as (a), and aside of that it = would be worth the effort (and technically possible) to add another = syntax to force NPE over a particular sub-expression (e.g., = =E2=80=9Cfoo!.bar=E2=80=9D). >=20 > Thanks and all the best, > OC >=20 > [*] The name might not be quite apt, for propagating a null is not = inherently safer than NPEing; those are simply two different approaches, = both of which serve best in different circumstances. A better name would = be something like =E2=80=9Cnull-propagating=E2=80=9D or =E2=80=9Cnon-NPE=E2= =80=9D mode, I guess. Myself, I don't think we should change the name = though, for all are used to it. >=20 >=20 --Apple-Mail=_12F52A9D-FD00-4EE7-AE37-A38EBB8A73E9 Content-Transfer-Encoding: quoted-printable Content-Type: text/html; charset=utf-8 Andres,

On 14 Aug 2018, at 2:31 PM, = Andres Almiray <aalmiray@gmail.com> wrote:
This is a good example of a = feature that can be experimented with as an external AST transformation, = there's no need to add it to core just = yet.

Not = quite, alas. I am experimenting with it for years; it sort = of works, but is far from easy or reliable.

To implement the non-NPE null-propagating = behaviour solely at the ASTT side is extremely difficult; you have to = cope with all the expressions explicitly, you have to manage a number of = ugly special and side cases (e.g., AttributeExpression overrides = safe as read-only and trying to set it on throws; an attempt to set the = safe attribute for a super.whatever causes a verify error; = null?.is(null) does not work reasonably, etc...)

For the moment, the best solution =E2=80=94 far as = I have been able to ascertain =E2=80=94 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(foo)) explicitly;

(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=3Dtrue for = get/setProperty, guarding explicitly against the known problematic cases = (e.g., super.getProperty).

For all I = know, this probably would not work properly with @CompileStatic = (which I do not use at all myself, but others do = frequently).

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.

Advantages of such = approach:
 - faster development/release = cycle.
 - can target specific Groovy version = to begin with.
 - may break compatibility = until feature works as expected.

Completely agreed; that's why I am suggesting this = only after I used the ASTT/metaclass approach for = years =E2=80=94 and also when a major version with lots of potential = compatibility breaks is about to come soon anyway.

Adding this feature to core in an = early stage (conception) is too early = IMHO.
Remember that = @TailCall started life as an external AST xform, it was added to core = when it became mature enough :-)

Quite: what I am = suggesting is that it's the right time now to add it to core, = alleviating the need of the [*] hacks :)

Thanks = and all the best,
OC


-------------------------------------------
Java = Champion; Groovy Enthusiast
JCP EC Associate Seat
http://andresalmiray.com
http://www.linkedin.com/in/aalmiray
--
What goes up, must come down. Ask any system = administrator.
There are 10 types of people in the world: = Those who understand binary, and those who don't.
To = understand recursion, we must first understand = recursion.

On Tue, Aug 14, 2018 at 1:28 = PM, ocs@ocs <ocs@ocs.cz> wrote:
Gentlemen,

some NPE-related problems of today brought me to re-interate one of my = older suggestions.

We have the so-called =E2=80=9Csafe navigation=E2=80=9D[*], which in = some cases allows a null to be propagated out of an expression instead = of throwing a NPE. At the moment, it can be triggered for a particular = sub-expression (like property/method-call and, as of 3, newly also = indexing) using a question mark (e.g., =E2=80=9Cfoo?.bar()=E2=80=9D or = =E2=80=9Cfoo?[bar]=E2=80=9D).

Do please correct me if I am wrong, but far as I know, there still are = expressions which do not allow the =E2=80=9Csafe mode=E2=80=9D, e.g., = arithmetic (=E2=80=9Ca+b=E2=80=9D etc). Furthermore, there are cases = when one simply wants a bigger block of code to contain only = null-propagating expressions and never NPE; in such case, using the = question mark syntax is both inconvenient and error-prone (for it is = very easy to forget one of the lot of question marks needed in such a = code, and then get an uncaught unwanted NPE).

For these reasons, I would suggest adding a new annotation, whose name = might be e.g., =E2=80=9CImplicitSafeNavigation=E2=80=9D; it would simply = force a null-propagation to be implicitly and automatically used for = *all* expressions in the annotated scope, i.e., NPE would never be = thrown for them; for example:

=3D=3D=3D
@ImplicitSafeNavigation class Foo {
 static foo(a,b,c,d,e) {
   a.bar+b*c[d]<<e.bax() // just e.g.; would work with = *any* expression which NPEs today
 }
}
assert null =3D=3D Foo.foo(null,null,null,null,null)
=3D=3D=3D

I wonder whether this enhancement would be possible to implement in some = forthcoming Groovy release? Myself, I believe it would help = tremendously.

If feasible, then it is for a further discussion whether in the scope of = this annotation
(a) a safe-navigation syntax (=E2=80=9Cfoo?.bar=E2=80=9D) should be = ignored as superfluous;
(b) or, whether in this scope it should reverse the behaviour to trigger = an NPE anyway;
(c) or, whether it should be ignored as (a), and aside of that it would = be worth the effort (and technically possible) to add another syntax to = force NPE over a particular sub-expression (e.g., =E2=80=9Cfoo!.bar=E2=80=9D= ).

Thanks and all the best,
OC

[*] The name might not be quite apt, for propagating a null is not = inherently safer than NPEing; those are simply two different approaches, = both of which serve best in different circumstances. A better name would = be something like =E2=80=9Cnull-propagating=E2=80=9D or =E2=80=9Cnon-NPE=E2= =80=9D mode, I guess. Myself, I don't think we should change the name = though, for all are used to it.



= --Apple-Mail=_12F52A9D-FD00-4EE7-AE37-A38EBB8A73E9--