You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@groovy.apache.org by MG <mg...@arscreat.com> on 2020/08/08 22:38:21 UTC
NV NameAndValue Macros
Hi Paul,
thank you for the link (https://github.com/apache/groovy/pull/1343 )
As far as I could see the NV macros you propose
(https://github.com/apache/groovy/pull/1343/commits/0a3ba697511335a82ec7487998976aacdc8667de)
all create "x0=${x0.foo()}, x1=${x1.foo()}, ..." GString|s, with foo in
[toString, inspect, dump]:
NV ... "x0=$x0, x1=$x1, ..."-GString // toString() called on values;
same as my NVS proposal
NVI ... "x0=${x0.inspect()}, x1=${x1.inspect()}, ..."-GString //
inspect called on values
NVD ... "x0=${x0.dump()}, x1=${x1.dump()}, ..."-GString // dump called
on values
However, the NameAndValue instance creation makes a) the concept very
flexible, and b) elevates it beyond just logging (all examples dry-coded):
a) Examples:
println "path: ${NVL(x, y, z).join('/')}" // arbitrary join
final weirdRegex =
NVL(id,parentFiledReferenceIdentifier,name,humanReadableName).collect {
"($it.name:$it.val)" }.join('|') // arbitrary name-value-string +
arbitrary join
final xml =
"<properties>${NVL(id,parentFiledReferenceIdentifier,name,humanReadableName).collect
{ "<$it.name>$it.val</$it.name>" }.join('')}</properties>" // another
arbitrary name-value-string + arbitrary join (just a quick&dirty example
- please stream properly escaped XML at all times :-) )
b) Examples: I use it for instance to define property collections in
Pojo classes, which other methods then use to drive e.g. the output of
the Pojo in a GUI table (or to create some SQL), e.g.:
List<NameAndValue> getImportantProperties() { NVL(id, name, children) }
List<NameAndValue<String>> getTextProperties() { NVL(firstName,
lastName, description) }
String toXmlString() { "<foo ${importantProperties.collect {
NameAndValue nv ->
$/${xmlAttributeName(nv.name)}="${xmlAttributeVal(nv.val)}"/$ } }>insert
text here...</foo>" }
The NameAndValue<T> class is of course indepent of the NV macro family,
and can also be created explicitly, e.g. (assuming @Newify pattern):
final x = 100
final y = 123.456
final list = [ NameAndValue('first',x), NameAndValue('second',y) ] +
NVL(pos.x, pos.y)
Keeping that use in mind, it could make sense to come up with a shorter
class name for the NameAndValue class...
I would therefore suggest we support both:
// NameAndValue based
NV ... as my NVL before
NVP ... as NV, but first argument is treated as parameter for
NameAndValue instance creation; e.g. NVP(NameAndValue.DUMP, a, b, c) //
create NameAndValueExt instance, which will use dump method in its
toString() method
// GString based
GV or NVS ... your NVI; GV = GStringed-variable(s)
GVI or NVSI ... your NVI
GVD or NVSD ... your NVD
Since "inspect" falls back to "toString", we could also just make GV/NVS
use inspect, and only support GVD/NVSD besides that - then it would make
sense to use "inspect" instead of "toString" in NameAndValue#toString
also...
Cheers,
mg
On 07/08/2020 12:53, Paul King wrote:
> I created a starting set of NV, NVI and NVD macros similar (but
> slightly different) to what mg has described previously. I see that as
> a starting point for discussion.
>
> Something like 'returnIf' wouldn't be hard to add but I'd personally
> prefer to explore enhancing our switch statement first since I think
> that would cover many use cases where I'd be tempted to try 'returnIf'.
>
> Just on switch statements we have Java 13/14 enhanced switch we could
> explore (switch expressions, yields/no breaks) and destructuring like
> python's latest proposal[1] but obviously with our own syntax.
>
>
> Cheers, Paul.
> [1] https://www.python.org/dev/peps/pep-0622/
>
> On Wed, Aug 5, 2020 at 7:53 AM MG <mgbiz@arscreat.com
> <ma...@arscreat.com>> wrote:
>
> Hi Eric,
>
> yea, I got that, that's why I said "In that case a global setting
> might /also/ be useful".
>
> But I doubt that the majority of Groovy users out there who want
> to quickly check if it is macros that make their code break in
> Groovy 4 would know that to do so they just need to "add the macro
> transform class to the disallowed list in CompilerConfiguration";
> to be able to do so would mean one would a) need to know the macro
> transform class exists and what its purpose and exact name is, b)
> how the disallowed list in CompilerConfiguration works (that's the
> easy part), as well as last but not least c) to be sure that doing
> so will not just break part or all of Groovy... ;-)
>
> I think you grossly underestimate the amount of Groovy (internal)
> knowledge you have :-)
>
> Cheers,
> mg
>
>
> On 04/08/2020 18:27, Milles, Eric (TR Technology) wrote:
>>
>> In terms of globally disabling macro methods, you can just add
>> the macro transform class to the disallowed list in
>> CompilerConfiguration. I think Paul is describing a mechanism
>> where an individual macro method is taken out of service.
>>
>> *From:* MG <mg...@arscreat.com> <ma...@arscreat.com>
>> *Sent:* Tuesday, August 4, 2020 9:53 AM
>> *To:* dev@groovy.apache.org <ma...@groovy.apache.org>; Paul
>> King <pa...@asert.com.au> <ma...@asert.com.au>
>> *Subject:* Re: [PROPOSAL]Support conditional return
>>
>> Hi Paul,
>>
>> thanks for clearing that up :-)
>>
>> @unforeseen implications: In that case a global
>> -Dgroovy.macro.enable=false
>> might also be useful, to do a quick check if it is macros that
>> are causing the problem (if we do not have that already).
>>
>> Btw: Do we have a way to hide the macro definitions from e.g.
>> IntelliJ Intellisense, and only show the stub implementation ? I
>> use the NV macros* extensively by now in my code, and what I
>> found is, that always having to select and import the stub class,
>> and not the macro class is a (small) hassle.
>>
>> Cheers,
>> mg
>>
>> *In practice it turns out the NV variety I use the most is NVL,
>> which returns a list of NV instances, so is good for logging
>> multiple variables. At some point in the future there will need
>> to be a discussion what varieties we want to support; my
>> suggestion would be:
>> NV(x) ... single NameAndValue class instance
>> NVL(x0,x1,...) ... list of NameAndValue instances
>> NVS(x0,x1,...) ... "x0=$x0, x1=$x1, ..."-GString
>> (we could also have NVS return an (efficiently built) String, and
>> NVGS return the GString, but I am not sure whether that it is
>> worth it)
>>
>> On 04/08/2020 08:17, Paul King wrote:
>>
>> Hi mg,
>>
>> Just on supplying our own macros, we should do this for
>> Groovy 4. We have been reluctant so far because we have been
>> conservative about unforeseen implications. However, unless
>> we start using them more widely, we aren't going to learn
>> those implications.
>>
>> I'd suggest having them (to start with) in their own optional
>> incubating module (e.g. groovy-macro-samples) and we should
>> come up with a way to disable any one of them, e.g.
>> -Dgroovy.macro.enable.returnIf=false
>> -Dgroovy.macro.enable.NV=true (or whatever).
>>
>> Cheers, Paul.
>>
>> On Wed, Jul 29, 2020 at 10:07 AM MG <mgbiz@arscreat.com
>> <ma...@arscreat.com>> wrote:
>>
>> I like that idea :-)
>> (unless someone has a really convincing argument why not,
>> 100% for
>> sticking with "it" instead of "_"/"$")
>>
>> That would also allow for more flexibility with e.g.
>> regards to the
>> number of methods that are being evaluated, without
>> getting into the
>> problematic area of whether/ how to support this syntax-wise.
>>
>> If there is nothing blocking this, the question is if
>> Groovy should
>> supply a basic version of such a macro (if Groovy is ever
>> planning to
>> supply macros of its own) ?
>>
>> Cheers,
>> mg
>>
>>
>> On 28/07/2020 16:08, Milles, Eric (TR Technology) wrote:
>> > If switch expression or pattern match macro is
>> insufficient, could a macro be written to cover this
>> "conditional return"?
>> >
>> > // "it" could easily be replaced by "_" or "$" as
>> mentioned previously as options
>> > def doSomething(int a) {
>> > returnIf(callB(), a > 6 && it > 10)
>> > returnIf(callC(), a > 5 && it > 20)
>> > returnIf(callD(), a > 4 && it > 30)
>> > }
>> >
>> > vs.
>> >
>> > def doSomething(int a) {
>> > return callB() if (a > 6 && _ > 10)
>> > return callC() if (a > 5 && _ > 20)
>> > return callD() if (a > 4 && _ > 30)
>> > }
>> >
>> > -----Original Message-----
>> > From: Daniel Sun <sunlan@apache.org
>> <ma...@apache.org>>
>> > Sent: Sunday, July 26, 2020 6:23 PM
>> > To: dev@groovy.apache.org <ma...@groovy.apache.org>
>> > Subject: Re: [PROPOSAL]Support conditional return
>> >
>> > Hi Sergei,
>> >
>> > ( Copied from twitter:
>> https://nam02.safelinks.protection.outlook.com/?url=https%3A%2F%2Ftwitter.com%2Fbsideup%2Fstatus%2F1287477595643289601%3Fs%3D20&data=02%7C01%7Ceric.milles%40thomsonreuters.com%7C411c66fda05844d7429908d831bacc9d%7C62ccb8646a1a4b5d8e1c397dec1a8258%7C0%7C0%7C637314025668554080&sdata=vNa3dz0H%2BJAegS9Zb8HW2by0ueceqCKI6qDVFpBpbc4%3D&reserved=0
>> <https://nam02.safelinks.protection.outlook.com/?url=https%3A%2F%2Ftwitter.com%2Fbsideup%2Fstatus%2F1287477595643289601%3Fs%3D20&data=02%7C01%7Ceric.milles%40thomsonreuters.com%7Cd22419dbc45b40d96bf608d8388618f6%7C62ccb8646a1a4b5d8e1c397dec1a8258%7C0%7C0%7C637321496617678018&sdata=NBAn2FtRigVd8UFrZpPt7GdDLdI7kMVh%2BxTl2vNAtK0%3D&reserved=0>
>> )
>> >> But isn't it better with pattern matching? And what is
>> "_" here?
>> > The underscore represents the return value
>> >
>> >> Anyways:
>> >> ```
>> >> return match (_) {
>> >> case { it < 5 }: callC();
>> >> case { it > 10 }: callB();
>> >> case { it != null }: callA();
>> >> default: {
>> >> LOG.debug "returning callD"
>> >> return callD()
>> >> }
>> >> }
>> >> ```
>> > pattern matching may cover some cases of Conditional
>> Return, but it can not cover all. Actually the
>> Conditional Return is more flexible, e.g.
>> >
>> > ```
>> > def chooseMethod(String methodName, Object[] arguments) {
>> > return doChooseMethod(methodName, arguments) if _
>> != null
>> >
>> > for (Class type : [Character.TYPE, Integer.TYPE]) {
>> > return doChooseMethod(methodName,
>> adjustArguments(arguments.clone(), type)) if _ != null
>> > }
>> >
>> > throw new GroovyRuntimeException("$methodName not
>> found") } ```
>> >
>> > Even we could simplify the above code with `return?` if
>> the condition is Groovy truth:
>> > ```
>> > def chooseMethod(String methodName, Object[] arguments) {
>> > return? doChooseMethod(methodName, arguments)
>> >
>> > for (Class type : [Character.TYPE, Integer.TYPE]) {
>> > return? doChooseMethod(methodName,
>> adjustArguments(arguments.clone(), type))
>> > }
>> >
>> > throw new GroovyRuntimeException("$methodName not
>> found") } ```
>> >
>> > Cheers,
>> > Daniel Sun
>> > On 2020/07/26 18:23:41, Daniel Sun <sunlan@apache.org
>> <ma...@apache.org>> wrote:
>> >> Hi mg,
>> >>
>> >>> maybe you can give some real life code where you
>> encounter this on a regular basis ?
>> >> Let's think about the case about choosing method by
>> method name and arguments:
>> >>
>> >> ```
>> >> def chooseMethod(String methodName, Object[] arguments) {
>> >> def methodChosen = doChooseMethod(methodName,
>> arguments)
>> >> if (null != methodChosen) return methodChosen
>> >>
>> >> methodChosen = doChooseMethod(methodName,
>> adjustArguments(arguments.clone(), Character.TYPE))
>> >> if (null != methodChosen) return methodChosen
>> >>
>> >> methodChosen = doChooseMethod(methodName,
>> adjustArguments(arguments.clone(), Integer.TYPE))
>> >> if (null != methodChosen) return methodChosen
>> >>
>> >> throw new GroovyRuntimeException("$methodName not
>> found") } ```
>> >>
>> >> The above code could be simplified as:
>> >> ```
>> >> def chooseMethod(String methodName, Object[] arguments) {
>> >> return? doChooseMethod(methodName, arguments)
>> >>
>> >> return? doChooseMethod(methodName,
>> >> adjustArguments(arguments.clone(), Character.TYPE))
>> >>
>> >> return? doChooseMethod(methodName,
>> >> adjustArguments(arguments.clone(), Integer.TYPE))
>> >>
>> >> throw new GroovyRuntimeException("$methodName not
>> found") } ```
>> >>
>> >> Or a general version:
>> >> ```
>> >> def chooseMethod(String methodName, Object[] arguments) {
>> >> return doChooseMethod(methodName, arguments) if _
>> != null
>> >>
>> >> return doChooseMethod(methodName,
>> >> adjustArguments(arguments.clone(), Character.TYPE)) if
>> _ != null
>> >>
>> >> return doChooseMethod(methodName,
>> >> adjustArguments(arguments.clone(), Integer.TYPE)) if _
>> != null
>> >>
>> >> throw new GroovyRuntimeException("$methodName not
>> found") } ```
>> >>
>> >>
>> >> Cheers,
>> >> Daniel Sun
>> >> On 2020/07/26 17:11:07, MG <mgbiz@arscreat.com
>> <ma...@arscreat.com>> wrote:
>> >>> Hi Daniel,
>> >>>
>> >>> currently I would be +/- 0 on this.
>> >>>
>> >>> Thoughts:
>> >>>
>> >>> 1. I feel I have written this before, but I myself
>> do not encounter the
>> >>> situation where I would need to return the
>> result of a method call
>> >>> only if it meets certain conditions when
>> programming (maybe you can
>> >>> give some real life code where you encounter
>> this on a regular basis ?).
>> >>> 2. If I have more than one return, it typcially is
>> an early out, which
>> >>> depends on the method's input parameters, not on
>> the result of
>> >>> another method call.
>> >>> 3. Since I do a lot of logging / log debugging, I
>> typically assign the
>> >>> return value to a variable, so I can debug-log
>> it before the one
>> >>> return of the method.
>> >>> 4. In fact I have had to refactor code written by
>> other people from
>> >>> multi-return methods to single return, to be
>> able to track down bugs.
>> >>>
>> >>> So overall I am not sure one should enable people to
>> make it easier
>> >>> to write non-single-return methods ;-)
>> >>>
>> >>>
>> >>> Purely syntax wise I would prefer
>> >>> return?
>> >>> for the simple case,
>> >>>
>> >>> and
>> >>>
>> >>> return <something> if <condition>
>> >>> for the more complex one*.
>> >>>
>> >>> I find
>> >>> return(<condition) <something>
>> >>> confusing on what is actually returned.
>> >>>
>> >>> Cheers,
>> >>> mg
>> >>>
>> >>> *Though I wonder if people would not then expect this
>> >>> if-postfix-syntax to also work for e.g. assignments
>> and method calls...
>> >>>
>> >>>
>> >>> On 26/07/2020 16:15, Daniel Sun wrote:
>> >>>> Hi Mario,
>> >>>>
>> >>>> I think you have got the point of the proposal ;-)
>> >>>>
>> >>>> If we prefer the verbose but clear syntax, I
>> think we could introduce `_` to represent the return
>> value for concise shape:
>> >>>>
>> >>>> ```
>> >>>> return callB() if (_ != null && _ > 10)
>> >>>>
>> >>>> // The following code is like lambda expression,
>> which is a bit
>> >>>> more verbose return callB() if (result -> result !=
>> null && result
>> >>>>> 10) ```
>> >>>> Show the `_` usage in your example:
>> >>>> ```
>> >>>> def doSomething(int a) {
>> >>>> return callB() if (a > 6 && _ > 10)
>> >>>> return callC() if (a > 5 && _ > 20)
>> >>>> return callD() if (a > 4 && _ > 30) } ```
>> >>>>
>> >>>> ```
>> >>>> // optional parentheses
>> >>>> def doSomething(int a) {
>> >>>> return callB() if a > 6 && _ > 10
>> >>>> return callC() if a > 5 && _ > 20
>> >>>> return callD() if a > 4 && _ > 30 } ```
>> >>>>
>> >>>> ```
>> >>>> // one more example
>> >>>> def doSomething(int a) {
>> >>>> return callB() if a > 6 && _ > 10
>> >>>> return callC() + callD() if a > 5 && _ > 50 } ```
>> >>>>
>> >>>> BTW, the parentheses behind `if` could be
>> optional.
>> >>>>
>> >>>> Cheers,
>> >>>> Daniel Sun
>> >>>> On 2020/07/26 11:29:39, Mario Garcia
>> <mario.ggar@gmail.com <ma...@gmail.com>> wrote:
>> >>>>> Hi all:
>> >>>>>
>> >>>>> Very interesting topic.
>> >>>>>
>> >>>>> The first idea sprang to mind was the PMD rule in
>> Java saying you
>> >>>>> should have more than one exit point in your methods (
>> >>>>>
>> https://nam02.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpmd.github.io%2Flatest%2Fpmd_rules_java_codestyle.html%23onlyonereturn&data=02%7C01%7Ceric.milles%40thomsonreuters.com%7C411c66fda05844d7429908d831bacc9d%7C62ccb8646a1a4b5d8e1c397dec1a8258%7C0%7C0%7C637314025668554080&sdata=5m%2B5ejCWEicseaUp5wK0UDjHwpfMFht5ptjglZ9IWS4%3D&reserved=0
>> <https://nam02.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpmd.github.io%2Flatest%2Fpmd_rules_java_codestyle.html%23onlyonereturn&data=02%7C01%7Ceric.milles%40thomsonreuters.com%7Cd22419dbc45b40d96bf608d8388618f6%7C62ccb8646a1a4b5d8e1c397dec1a8258%7C0%7C0%7C637321496617688010&sdata=vHsd4PrZTGJxhfAvtPxKLEfAvxiidhOAVvqFthIDHTU%3D&reserved=0>).
>> >>>>> But the reality is that sometimes (more often than
>> not) we are
>> >>>>> forced to break that rule. In fact sometimes we
>> could even argue
>> >>>>> that breaking that rule makes the code clearer (e.g
>> >>>>>
>> https://nam02.safelinks.protection.outlook.com/?url=https%3A%2F%2
>> <https://nam02.safelinks.protection.outlook.com/?url=https%3A%2F%252>
>> >>>>>
>> Fmedium.com%2Fncr-edinburgh%2Fearly-exit-c86d5f0698ba&data=02
>> >>>>> %7C01%7Ceric.milles%40thomsonreuters.com
>> <https://nam02.safelinks.protection.outlook.com/?url=http%3A%2F%2F40thomsonreuters.com%2F&data=02%7C01%7Ceric.milles%40thomsonreuters.com%7Cd22419dbc45b40d96bf608d8388618f6%7C62ccb8646a1a4b5d8e1c397dec1a8258%7C0%7C0%7C637321496617688010&sdata=dVEeA8WhNRImv11c7OIRUDcIyrjq58kF0o%2F5R%2BK6WlU%3D&reserved=0>%7C411c66fda05844d7429908
>> >>>>>
>> d831bacc9d%7C62ccb8646a1a4b5d8e1c397dec1a8258%7C0%7C0%7C637314025
>> >>>>>
>> 668554080&sdata=q8VrgoQDeH85232oyMgQT8WwljNqoUjIc4cS7GGqH5I%3
>> >>>>> D&reserved=0)
>> >>>>>
>> >>>>> Although my initial reaction was to be against the
>> proposal,
>> >>>>> however after doing some coding, I've found that
>> neither elvis
>> >>>>> nor ternary operators makes it easier nor clearer.
>> Here's why I think so. Taking Daniel's example:
>> >>>>>
>> >>>>> ```
>> >>>>> def m() {
>> >>>>> def a = callA()
>> >>>>> if (null != a) return a
>> >>>>>
>> >>>>> def b = callB()
>> >>>>> if (b > 10) return b
>> >>>>>
>> >>>>> def c = callC()
>> >>>>> if (null != c && c < 10) return c
>> >>>>>
>> >>>>> LOGGER.debug('the default value will be returned')
>> >>>>>
>> >>>>> return defaultValue
>> >>>>> }
>> >>>>> ```
>> >>>>> The shortest elvis operator approach I could think
>> of was:
>> >>>>> ```
>> >>>>> def m2() {
>> >>>>> return callA()
>> >>>>> ?: callB().with { it > 10 ? it : null }
>> >>>>> ?: callC().with { null != it && it <10 ?
>> it : null } }
>> >>>>> ```
>> >>>>>
>> >>>>> which to be honest, is ugly to read, whereas
>> Daniel's proposal is just:
>> >>>>>
>> >>>>> ```
>> >>>>> def m() {
>> >>>>> return? callA()
>> >>>>> return(r -> r > 10) callB()
>> >>>>> return(r -> null != r && r < 10) callC()
>> >>>>> return defaultValue
>> >>>>> }
>> >>>>> ```
>> >>>>>
>> >>>>> Once said that, I would say this conditional return
>> could be
>> >>>>> useful only when there are more than two exit
>> points, otherwise
>> >>>>> ternary or elvis operators may be good enough.
>> >>>>>
>> >>>>> So, bottom line, I kinda agree to add conditional
>> return, but I'm
>> >>>>> not sure about the final syntax:
>> >>>>>
>> >>>>> ```
>> >>>>> return(r -> r > 10) callB()
>> >>>>> return callB() [r -> r > 10]
>> >>>>> return callB() if (r -> r > 10)
>> >>>>> ```
>> >>>>>
>> >>>>> Between the three I the one that I like the most is
>> the third one:
>> >>>>>
>> >>>>> ```
>> >>>>> return callB() if (r -> r > 10)
>> >>>>> ```
>> >>>>>
>> >>>>> You can read it in plain english as "return this if
>> this
>> >>>>> condition happens".
>> >>>>>
>> >>>>> Apart from Daniel's use case, using this option
>> could open the
>> >>>>> possibility to use, not only a closure or lambda
>> expression, but
>> >>>>> also a plain expression. A nice side effect could
>> be that
>> >>>>> something like the following code:
>> >>>>>
>> >>>>> ```
>> >>>>> def doSomething(int a) {
>> >>>>> return callB() if a > 6
>> >>>>> return callC() if a > 5
>> >>>>> return callD() if a > 4
>> >>>>> }
>> >>>>> ```
>> >>>>>
>> >>>>> turns out to be a shorter (and in my opinion
>> nicest) way of
>> >>>>> switch case (when you want every branch to return
>> something):
>> >>>>>
>> >>>>> ```
>> >>>>> def doSomething(int a) {
>> >>>>> switch (a) {
>> >>>>> case { it > 6 }: return callB()
>> >>>>> case { it > 5 }: return callC()
>> >>>>> case { it > 4 }: return callD()
>> >>>>> }
>> >>>>> }
>> >>>>> ```
>> >>>>>
>> >>>>> Well, bottom line, I'm +1 Daniel's proposal because
>> I've seen
>> >>>>> some cases where this conditional return could make
>> the code clearer.
>> >>>>>
>> >>>>> Cheers
>> >>>>> Mario
>> >>>>>
>> >>>>> El sáb., 25 jul. 2020 a las 23:55, Paolo Di Tommaso (<
>> >>>>> paolo.ditommaso@gmail.com
>> <ma...@gmail.com>>) escribió:
>> >>>>>
>> >>>>>> It's not much easier a conditional expression (or
>> even the elvis
>> >>>>>> operator)?
>> >>>>>>
>> >>>>>> ```
>> >>>>>> def m() {
>> >>>>>> def r = callSomeMethod()
>> >>>>>> return r != null ? r : theDefaultResult } ```
>> >>>>>>
>> >>>>>>
>> >>>>>> On Sat, Jul 25, 2020 at 8:56 PM Daniel Sun
>> <sunlan@apache.org <ma...@apache.org>> wrote:
>> >>>>>>
>> >>>>>>> Hi all,
>> >>>>>>>
>> >>>>>>> We always have to check the returning
>> value, if it match
>> >>>>>>> some condition, return it. How about simplifying
>> it? Let's see an example:
>> >>>>>>>
>> >>>>>>> ```
>> >>>>>>> def m() {
>> >>>>>>> def r = callSomeMethod()
>> >>>>>>> if (null != r) return r
>> >>>>>>>
>> >>>>>>> return theDefaultResult
>> >>>>>>> }
>> >>>>>>> ```
>> >>>>>>>
>> >>>>>>> How about simplifying the above code as follows:
>> >>>>>>> ```
>> >>>>>>> def m() {
>> >>>>>>> return? callSomeMethod()
>> >>>>>>> return theDefaultResult
>> >>>>>>> }
>> >>>>>>> ```
>> >>>>>>>
>> >>>>>>> Futhermore, we could make the conditional return
>> more general:
>> >>>>>>> ```
>> >>>>>>> def m() {
>> >>>>>>> return(r -> r != null) callSomeMethod() // we
>> could do
>> >>>>>>> more checking, e.g. r > 10
>> >>>>>>> return theDefaultResult
>> >>>>>>> }
>> >>>>>>> ```
>> >>>>>>>
>> >>>>>>> Any thoughts?
>> >>>>>>>
>> >>>>>>> Cheers,
>> >>>>>>> Daniel Sun
>> >>>>>>>
>> >>>
>>
>