[ruby-core:122797] [Ruby Feature#21515] Add `&return` as sugar for `x=my_calculation; return x if x`

Issue #21515 has been reported by nhorton (Noah Horton). ---------------------------------------- Feature #21515: Add `&return` as sugar for `x=my_calculation; return x if x` https://bugs.ruby-lang.org/issues/21515 * Author: nhorton (Noah Horton) * Status: Open ---------------------------------------- Let me preface this by saying I have no marriage to the exact keyword name of `&return`. # Problem It is very common to have an early return in code where you get some initial value and return it if it is non-null. i.e. ``` return my_calculation(input_a, input_b) if my_calculation(input_a, input_b) ``` That form on its own is verbose and one where you need to look at it for a moment to confirm it is the same code on either side of the if. If `my_calculation` is non-trivial at all, it normally gets turned into something with a variable: ``` my_calc = my_calculation(input_a, input_b) return my_calc if my_calc ``` That is now two lines. The worse scenario, however, is if the user did not bother doing that and my_calculation turned out to be expensive (and they did not know it). # Proposal I propose a syntax of `&return my_calculation(input_a, input_b)` where it will evaluate the argument and return it as the result of the method if it is non-nil, otherwise it will continue on. # Alternatives ## Do Nothing There is no way to work around this with rolling your own methods. You can't make a `returnif` method or something yourself since you can't do a return in the caller's scope. ## Different Name The best other name I saw were permutations of `returnif`. The biggest issue I see is the similarity of the following two statements: ``` return if foo returnif foo ``` Those are obviously very, very different statements, but are somewhat similar. However, things like this are common, and the code is still quite distinct on those, so I think it is acceptable. Ultimately, this feels so similar to the safe navigator that using `&` in this context feels appropriate. Thank you all for your consideration. -- https://bugs.ruby-lang.org/

Issue #21515 has been updated by vo.x (Vit Ondruch). Proposal like this always reminds me: https://poignant.guide/book/chapter-3.html How am I supposed to read the `&return my_calculation(input_a, input_b)`. Reading it "and return my calculations from input_a and input_b" does not make sense to me. ---------------------------------------- Feature #21515: Add `&return` as sugar for `x=my_calculation; return x if x` https://bugs.ruby-lang.org/issues/21515#change-114078 * Author: nhorton (Noah Horton) * Status: Open ---------------------------------------- Let me preface this by saying I have no marriage to the exact keyword name of `&return`. # Problem It is very common to have an early return in code where you get some initial value and return it if it is non-null. i.e. ``` return my_calculation(input_a, input_b) if my_calculation(input_a, input_b) ``` That form on its own is verbose and one where you need to look at it for a moment to confirm it is the same code on either side of the if. If `my_calculation` is non-trivial at all, it normally gets turned into something with a variable: ``` my_calc = my_calculation(input_a, input_b) return my_calc if my_calc ``` That is now two lines. The worse scenario, however, is if the user did not bother doing that and my_calculation turned out to be expensive (and they did not know it). # Proposal I propose a syntax of `&return my_calculation(input_a, input_b)` where it will evaluate the argument and return it as the result of the method if it is non-nil, otherwise it will continue on. # Alternatives ## Do Nothing There is no way to work around this with rolling your own methods. You can't make a `returnif` method or something yourself since you can't do a return in the caller's scope. ## Different Name The best other name I saw were permutations of `returnif`. The biggest issue I see is the similarity of the following two statements: ``` return if foo returnif foo ``` Those are obviously very, very different statements, but are somewhat similar. However, things like this are common, and the code is still quite distinct on those, so I think it is acceptable. Ultimately, this feels so similar to the safe navigator that using `&` in this context feels appropriate. Thank you all for your consideration. -- https://bugs.ruby-lang.org/

Issue #21515 has been updated by Earlopain (Earlopain _). I would prefer it like this: ```rb return result if result = my_calculation(input_a, input_b) ``` It doesn't need new syntax and to me at least it is rather intuitive. Unfortunatly this doesn't work today because the return code doesn't see the local that was declared in the if condition. You would have to write it as a multiline if or do `result = nil` above it which kinda defeats the point. ---------------------------------------- Feature #21515: Add `&return` as sugar for `x=my_calculation; return x if x` https://bugs.ruby-lang.org/issues/21515#change-114081 * Author: nhorton (Noah Horton) * Status: Open ---------------------------------------- Let me preface this by saying I have no marriage to the exact keyword name of `&return`. # Problem It is very common to have an early return in code where you get some initial value and return it if it is non-null. i.e. ``` return my_calculation(input_a, input_b) if my_calculation(input_a, input_b) ``` That form on its own is verbose and one where you need to look at it for a moment to confirm it is the same code on either side of the if. If `my_calculation` is non-trivial at all, it normally gets turned into something with a variable: ``` my_calc = my_calculation(input_a, input_b) return my_calc if my_calc ``` That is now two lines. The worse scenario, however, is if the user did not bother doing that and my_calculation turned out to be expensive (and they did not know it). # Proposal I propose a syntax of `&return my_calculation(input_a, input_b)` where it will evaluate the argument and return it as the result of the method if it is non-nil, otherwise it will continue on. # Alternatives ## Do Nothing There is no way to work around this with rolling your own methods. You can't make a `returnif` method or something yourself since you can't do a return in the caller's scope. ## Different Name The best other name I saw were permutations of `returnif`. The biggest issue I see is the similarity of the following two statements: ``` return if foo returnif foo ``` Those are obviously very, very different statements, but are somewhat similar. However, things like this are common, and the code is still quite distinct on those, so I think it is acceptable. Ultimately, this feels so similar to the safe navigator that using `&` in this context feels appropriate. Thank you all for your consideration. -- https://bugs.ruby-lang.org/

Issue #21515 has been updated by nobu (Nobuyoshi Nakada). Why not: ```ruby x = my_calculation(input_a, input_b) and return x ``` ---------------------------------------- Feature #21515: Add `&return` as sugar for `x=my_calculation; return x if x` https://bugs.ruby-lang.org/issues/21515#change-114084 * Author: nhorton (Noah Horton) * Status: Open ---------------------------------------- Let me preface this by saying I have no marriage to the exact keyword name of `&return`. # Problem It is very common to have an early return in code where you get some initial value and return it if it is non-null. i.e. ``` return my_calculation(input_a, input_b) if my_calculation(input_a, input_b) ``` That form on its own is verbose and one where you need to look at it for a moment to confirm it is the same code on either side of the if. If `my_calculation` is non-trivial at all, it normally gets turned into something with a variable: ``` my_calc = my_calculation(input_a, input_b) return my_calc if my_calc ``` That is now two lines. The worse scenario, however, is if the user did not bother doing that and my_calculation turned out to be expensive (and they did not know it). # Proposal I propose a syntax of `&return my_calculation(input_a, input_b)` where it will evaluate the argument and return it as the result of the method if it is non-nil, otherwise it will continue on. # Alternatives ## Do Nothing There is no way to work around this with rolling your own methods. You can't make a `returnif` method or something yourself since you can't do a return in the caller's scope. ## Different Name The best other name I saw were permutations of `returnif`. The biggest issue I see is the similarity of the following two statements: ``` return if foo returnif foo ``` Those are obviously very, very different statements, but are somewhat similar. However, things like this are common, and the code is still quite distinct on those, so I think it is acceptable. Ultimately, this feels so similar to the safe navigator that using `&` in this context feels appropriate. Thank you all for your consideration. -- https://bugs.ruby-lang.org/

Issue #21515 has been updated by masterleep2 (Bill Lipa). Also: my_calculation(input_a, input_b)&.then{return it} ---------------------------------------- Feature #21515: Add `&return` as sugar for `x=my_calculation; return x if x` https://bugs.ruby-lang.org/issues/21515#change-114086 * Author: nhorton (Noah Horton) * Status: Open ---------------------------------------- Let me preface this by saying I have no marriage to the exact keyword name of `&return`. # Problem It is very common to have an early return in code where you get some initial value and return it if it is non-null. i.e. ``` return my_calculation(input_a, input_b) if my_calculation(input_a, input_b) ``` That form on its own is verbose and one where you need to look at it for a moment to confirm it is the same code on either side of the if. If `my_calculation` is non-trivial at all, it normally gets turned into something with a variable: ``` my_calc = my_calculation(input_a, input_b) return my_calc if my_calc ``` That is now two lines. The worse scenario, however, is if the user did not bother doing that and my_calculation turned out to be expensive (and they did not know it). # Proposal I propose a syntax of `&return my_calculation(input_a, input_b)` where it will evaluate the argument and return it as the result of the method if it is non-nil, otherwise it will continue on. # Alternatives ## Do Nothing There is no way to work around this with rolling your own methods. You can't make a `returnif` method or something yourself since you can't do a return in the caller's scope. ## Different Name The best other name I saw were permutations of `returnif`. The biggest issue I see is the similarity of the following two statements: ``` return if foo returnif foo ``` Those are obviously very, very different statements, but are somewhat similar. However, things like this are common, and the code is still quite distinct on those, so I think it is acceptable. Ultimately, this feels so similar to the safe navigator that using `&` in this context feels appropriate. Thank you all for your consideration. -- https://bugs.ruby-lang.org/

Issue #21515 has been updated by lpogic (Łukasz Pomietło). The advantage of the proposed syntax is that it does not require an explicit declaration of an auxiliary variable, like here: ```rb return result if result = my_calculation(input_a, input_b) ``` and here: ```rb x = my_calculation(input_a, input_b) and return x ``` It also does not require creating an extra Proc like here: ```rb my_calculation(input_a, input_b)&.then{return it} ``` Is there any other way to write this without the consequences I mentioned? ---------------------------------------- Feature #21515: Add `&return` as sugar for `x=my_calculation; return x if x` https://bugs.ruby-lang.org/issues/21515#change-114117 * Author: nhorton (Noah Horton) * Status: Open ---------------------------------------- Let me preface this by saying I have no marriage to the exact keyword name of `&return`. # Problem It is very common to have an early return in code where you get some initial value and return it if it is non-null. i.e. ``` return my_calculation(input_a, input_b) if my_calculation(input_a, input_b) ``` That form on its own is verbose and one where you need to look at it for a moment to confirm it is the same code on either side of the if. If `my_calculation` is non-trivial at all, it normally gets turned into something with a variable: ``` my_calc = my_calculation(input_a, input_b) return my_calc if my_calc ``` That is now two lines. The worse scenario, however, is if the user did not bother doing that and my_calculation turned out to be expensive (and they did not know it). # Proposal I propose a syntax of `&return my_calculation(input_a, input_b)` where it will evaluate the argument and return it as the result of the method if it is non-nil, otherwise it will continue on. # Alternatives ## Do Nothing There is no way to work around this with rolling your own methods. You can't make a `returnif` method or something yourself since you can't do a return in the caller's scope. ## Different Name The best other name I saw were permutations of `returnif`. The biggest issue I see is the similarity of the following two statements: ``` return if foo returnif foo ``` Those are obviously very, very different statements, but are somewhat similar. However, things like this are common, and the code is still quite distinct on those, so I think it is acceptable. Ultimately, this feels so similar to the safe navigator that using `&` in this context feels appropriate. Thank you all for your consideration. -- https://bugs.ruby-lang.org/

Issue #21515 has been updated by jeremyevans0 (Jeremy Evans). lpogic (Łukasz Pomietło) wrote in #note-5:
The advantage of the proposed syntax is that it does not require an explicit declaration of an auxiliary variable, like here: ```rb return result if result = my_calculation(input_a, input_b) ``` and here: ```rb x = my_calculation(input_a, input_b) and return x ``` It also does not require creating an extra Proc like here: ```rb my_calculation(input_a, input_b)&.then{return it} ```
Not sure why the local variable declaration would matter, as long as you don't pick one already in use. However, you are incorrect about `my_calculation(input_a, input_b)&.then{return it}` creating a Proc. Using a block does not automatically create a Proc (that would be very slow). Using `&.then{return it}` does not create a Proc: ```ruby def my_calculation(a, b) a == b || nil end def t(a, b) my_calculation(a, b)&.then{return it} proc{} end before = {} after = {} cases = [[1, 1], [1, 2]] GC.start GC.disable cases.each do |a, b| ObjectSpace.count_objects(before) c = t(a, b) ObjectSpace.count_objects(after) # Procs have T_DATA internal type p [a, b, c, after[:T_DATA] - before[:T_DATA]] end ``` Output: ``` [1, 1, true, 0] [1, 2, #<Proc:0x0000011fe401f310 -:7>, 1] ``` ---------------------------------------- Feature #21515: Add `&return` as sugar for `x=my_calculation; return x if x` https://bugs.ruby-lang.org/issues/21515#change-114118 * Author: nhorton (Noah Horton) * Status: Open ---------------------------------------- Let me preface this by saying I have no marriage to the exact keyword name of `&return`. # Problem It is very common to have an early return in code where you get some initial value and return it if it is non-null. i.e. ``` return my_calculation(input_a, input_b) if my_calculation(input_a, input_b) ``` That form on its own is verbose and one where you need to look at it for a moment to confirm it is the same code on either side of the if. If `my_calculation` is non-trivial at all, it normally gets turned into something with a variable: ``` my_calc = my_calculation(input_a, input_b) return my_calc if my_calc ``` That is now two lines. The worse scenario, however, is if the user did not bother doing that and my_calculation turned out to be expensive (and they did not know it). # Proposal I propose a syntax of `&return my_calculation(input_a, input_b)` where it will evaluate the argument and return it as the result of the method if it is non-nil, otherwise it will continue on. # Alternatives ## Do Nothing There is no way to work around this with rolling your own methods. You can't make a `returnif` method or something yourself since you can't do a return in the caller's scope. ## Different Name The best other name I saw were permutations of `returnif`. The biggest issue I see is the similarity of the following two statements: ``` return if foo returnif foo ``` Those are obviously very, very different statements, but are somewhat similar. However, things like this are common, and the code is still quite distinct on those, so I think it is acceptable. Ultimately, this feels so similar to the safe navigator that using `&` in this context feels appropriate. Thank you all for your consideration. -- https://bugs.ruby-lang.org/

Issue #21515 has been updated by lpogic (Łukasz Pomietło). jeremyevans0 (Jeremy Evans) wrote in #note-6:
Not sure why the local variable declaration would matter, as long as you don't pick one already in use.
Because you have to write it twice. And coming up with names can be tedious. Especially for trivial and repetitive patterns like this one. jeremyevans0 (Jeremy Evans) wrote in #note-6:
```ruby def my_calculation(a, b) a == b || nil end
def t(a, b) my_calculation(a, b)&.then{return it} proc{} end
before = {} after = {}
cases = [[1, 1], [1, 2]] GC.start GC.disable cases.each do |a, b| ObjectSpace.count_objects(before) c = t(a, b) ObjectSpace.count_objects(after) # Procs have T_DATA internal type p [a, b, c, after[:T_DATA] - before[:T_DATA]] end ```
Indeed, you are right. Anyway, the "&.then" option does extra work, making it a bit slower: ```rb require 'benchmark' def my_calculation(a, b) a + b end def calculate_with_if x = my_calculation(1, 1); return x if x end def calculate_with_and x = my_calculation(1, 1) and return x end def calculate_with_then my_calculation(1, 1)&.then{ return it } end n = 10_000_000 Benchmark.bmbm do |x| x.report("x = my_calculation(1, 1); return x if x") { n.times{ calculate_with_if } } x.report("x = my_calculation(1, 1) and return x") { n.times{ calculate_with_and } } x.report("my_calculation(1, 1)&.then{ return it }") { n.times{ calculate_with_then } } end ``` ``` user system total real x = my_calculation(1, 1); return x if x 0.954000 0.000000 0.954000 ( 0.947969) x = my_calculation(1, 1) and return x 0.968000 0.000000 0.968000 ( 0.970023) my_calculation(1, 1)&.then{ return it } 2.532000 0.015000 2.547000 ( 2.539123) ``` It's not bad. But I just wanted to know if there was a way that would, like the proposed syntax, avoid this compromise. ---------------------------------------- Feature #21515: Add `&return` as sugar for `x=my_calculation; return x if x` https://bugs.ruby-lang.org/issues/21515#change-114119 * Author: nhorton (Noah Horton) * Status: Open ---------------------------------------- Let me preface this by saying I have no marriage to the exact keyword name of `&return`. # Problem It is very common to have an early return in code where you get some initial value and return it if it is non-null. i.e. ``` return my_calculation(input_a, input_b) if my_calculation(input_a, input_b) ``` That form on its own is verbose and one where you need to look at it for a moment to confirm it is the same code on either side of the if. If `my_calculation` is non-trivial at all, it normally gets turned into something with a variable: ``` my_calc = my_calculation(input_a, input_b) return my_calc if my_calc ``` That is now two lines. The worse scenario, however, is if the user did not bother doing that and my_calculation turned out to be expensive (and they did not know it). # Proposal I propose a syntax of `&return my_calculation(input_a, input_b)` where it will evaluate the argument and return it as the result of the method if it is non-nil, otherwise it will continue on. # Alternatives ## Do Nothing There is no way to work around this with rolling your own methods. You can't make a `returnif` method or something yourself since you can't do a return in the caller's scope. ## Different Name The best other name I saw were permutations of `returnif`. The biggest issue I see is the similarity of the following two statements: ``` return if foo returnif foo ``` Those are obviously very, very different statements, but are somewhat similar. However, things like this are common, and the code is still quite distinct on those, so I think it is acceptable. Ultimately, this feels so similar to the safe navigator that using `&` in this context feels appropriate. Thank you all for your consideration. -- https://bugs.ruby-lang.org/

Issue #21515 has been updated by tompng (tomoya ishida). Instead of adding new syntax to `return` part, how about a new keyword to reference if-predicate part? It can be used for wider range of purposes like this: ~~~ruby return that if @cache[key] puts that if my_calculation x = that + 42 if my_calculation ~~~ I'm not sure if `that` is a good name, `it` might also be good except that it breaks existing code like this: `4.times{p it if it >= 2}`. ---------------------------------------- Feature #21515: Add `&return` as sugar for `x=my_calculation; return x if x` https://bugs.ruby-lang.org/issues/21515#change-114128 * Author: nhorton (Noah Horton) * Status: Open ---------------------------------------- Let me preface this by saying I have no marriage to the exact keyword name of `&return`. # Problem It is very common to have an early return in code where you get some initial value and return it if it is non-null. i.e. ``` return my_calculation(input_a, input_b) if my_calculation(input_a, input_b) ``` That form on its own is verbose and one where you need to look at it for a moment to confirm it is the same code on either side of the if. If `my_calculation` is non-trivial at all, it normally gets turned into something with a variable: ``` my_calc = my_calculation(input_a, input_b) return my_calc if my_calc ``` That is now two lines. The worse scenario, however, is if the user did not bother doing that and my_calculation turned out to be expensive (and they did not know it). # Proposal I propose a syntax of `&return my_calculation(input_a, input_b)` where it will evaluate the argument and return it as the result of the method if it is non-nil, otherwise it will continue on. # Alternatives ## Do Nothing There is no way to work around this with rolling your own methods. You can't make a `returnif` method or something yourself since you can't do a return in the caller's scope. ## Different Name The best other name I saw were permutations of `returnif`. The biggest issue I see is the similarity of the following two statements: ``` return if foo returnif foo ``` Those are obviously very, very different statements, but are somewhat similar. However, things like this are common, and the code is still quite distinct on those, so I think it is acceptable. Ultimately, this feels so similar to the safe navigator that using `&` in this context feels appropriate. Thank you all for your consideration. -- https://bugs.ruby-lang.org/
participants (8)
-
Earlopain (Earlopain _)
-
jeremyevans0 (Jeremy Evans)
-
lpogic
-
masterleep2 (Bill Lipa)
-
nhorton (Noah Horton)
-
nobu (Nobuyoshi Nakada)
-
tompng (tomoya ishida)
-
vo.x (Vit Ondruch)