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 <mg...@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.g...@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://pmd.github.io/latest/pmd_rules_java_codestyle.html#onlyonereturn).
> >> 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://medium.com/ncr-edinburgh/early-exit-c86d5f0698ba)
> >>
> >> 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.ditomm...@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 <sun...@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
> >>>>
> 
> 

Reply via email to