Hi Sergei,
( Copied from twitter:
https://twitter.com/bsideup/status/1287477595643289601?s=20 )
> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 (<
> > >> [email protected]>) 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 <[email protected]> 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
> > >>>>
> >
> >
>