* [ruby-core:119469] [Ruby master Feature#20786] Flow chaining with "then" keyword
@ 2024-10-06 14:04 lpogic via ruby-core
2024-10-07 2:18 ` [ruby-core:119471] " nobu (Nobuyoshi Nakada) via ruby-core
2024-10-07 9:39 ` [ruby-core:119474] " lpogic via ruby-core
0 siblings, 2 replies; 3+ messages in thread
From: lpogic via ruby-core @ 2024-10-06 14:04 UTC (permalink / raw)
To: ruby-core; +Cc: lpogic
Issue #20786 has been reported by lpogic (Łukasz Pomietło).
----------------------------------------
Feature #20786: Flow chaining with "then" keyword
https://bugs.ruby-lang.org/issues/20786
* Author: lpogic (Łukasz Pomietło)
* Status: Open
----------------------------------------
Hi,
I would like to propose using the *"then"* keyword to create chained flows.
### Background:
Original idea: https://bugs.ruby-lang.org/issues/20770#change-110056
However, the concept has changed slightly since then. I now assume that rhs is only calculated when lhs is true, which seems more compatible with the current usage of *"then"* keyword.
I would also like to move the discussion here as it may cause unnecessary chaos there.
### Basics:
In the canonical version, *"then"* is used in a *"begin..end"* block to split it into steps.
When the result of the last expression before *"then"* is not *"false"* or *"nil"*, it is passed as an argument to the next step. Otherwise, all subsequent steps are skipped.
The result of the *"begin..end"* block is the result of the last expression, or *"false"*/*"nil"* if any step was skipped.
### Example:
``` ruby
# original code source: https://github.com/ruby/ruby/blob/a6383fbe1628bdaa9ec6a30b3baa60dd7430b461/lib/ipaddr.rb#L181C1-L185C6
def include?(other)
other = coerce_other(other)
return false unless other.family == family
begin_addr <= other.begin_addr && end_addr >= other.end_addr
end
# with chained flow
def include?(other)
begin
coerce_other(other)
then => coerced # then => name is my proposition of argument naming syntax
return false unless coerced.family == family
coerced
then => it
begin_addr <= it.begin_addr && end_addr >= it.end_addr
end
end
```
Please treat the canonical form as a starting point. As further improvements I would see:
- implicit block argument name
- implicit begin
- beginless *"then"*, when lhs is just expression
### Example with futher improvements:
``` ruby
def include?(other)
coerce_other(other)
then
it.family == family ? it : false
then
begin_addr <= it.begin_addr && end_addr >= it.end_addr
end
# or
def include?(other)
coerce_other other then
return false unless it.family == family
begin_addr <= it.begin_addr && end_addr >= it.end_addr
end
end
```
### *"then"* keyword as the pipeline operator:
Under certain conditions, "then" could offer similar capabilities to the pipeline operator of functional languages:
``` ruby
# assuming that "foo" and "bar" never return "false" or "nil"
# instead of writing this:
baz("string", bar(foo(), 2), 5)
# you could write this:
begin foo()
then bar(it, 2)
then baz("string", it, 5)
end
```
--
https://bugs.ruby-lang.org/
______________________________________________
ruby-core mailing list -- ruby-core@ml.ruby-lang.org
To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/
^ permalink raw reply [flat|nested] 3+ messages in thread
* [ruby-core:119471] [Ruby master Feature#20786] Flow chaining with "then" keyword
2024-10-06 14:04 [ruby-core:119469] [Ruby master Feature#20786] Flow chaining with "then" keyword lpogic via ruby-core
@ 2024-10-07 2:18 ` nobu (Nobuyoshi Nakada) via ruby-core
2024-10-07 9:39 ` [ruby-core:119474] " lpogic via ruby-core
1 sibling, 0 replies; 3+ messages in thread
From: nobu (Nobuyoshi Nakada) via ruby-core @ 2024-10-07 2:18 UTC (permalink / raw)
To: ruby-core; +Cc: nobu (Nobuyoshi Nakada)
Issue #20786 has been updated by nobu (Nobuyoshi Nakada).
It looks to conflict inside `if`.
----------------------------------------
Feature #20786: Flow chaining with "then" keyword
https://bugs.ruby-lang.org/issues/20786#change-110088
* Author: lpogic (Łukasz Pomietło)
* Status: Open
----------------------------------------
Hi,
I would like to propose using the *"then"* keyword to create chained flows.
### Background:
Original idea: https://bugs.ruby-lang.org/issues/20770#change-110056
However, the concept has changed slightly since then. I now assume that rhs is only calculated when lhs is true, which seems more compatible with the current usage of *"then"* keyword.
I would also like to move the discussion here as it may cause unnecessary chaos there.
### Basics:
In the canonical version, *"then"* is used in a *"begin..end"* block to split it into steps.
When the result of the last expression before *"then"* is not *"false"* or *"nil"*, it is passed as an argument to the next step. Otherwise, all subsequent steps are skipped.
The result of the *"begin..end"* block is the result of the last expression, or *"false"*/*"nil"* if any step was skipped.
### Example:
``` ruby
# original code source: https://github.com/ruby/ruby/blob/a6383fbe1628bdaa9ec6a30b3baa60dd7430b461/lib/ipaddr.rb#L181C1-L185C6
def include?(other)
other = coerce_other(other)
return false unless other.family == family
begin_addr <= other.begin_addr && end_addr >= other.end_addr
end
# with chained flow
def include?(other)
begin
coerce_other(other)
then => coerced # then => name is my proposition of argument naming syntax
return false unless coerced.family == family
coerced
then => it
begin_addr <= it.begin_addr && end_addr >= it.end_addr
end
end
```
Please treat the canonical form as a starting point. As further improvements I would see:
- implicit block argument name
- implicit begin
- beginless *"then"*, when lhs is just expression
### Example with futher improvements:
``` ruby
def include?(other)
coerce_other(other)
then
it.family == family ? it : false
then
begin_addr <= it.begin_addr && end_addr >= it.end_addr
end
# or
def include?(other)
coerce_other other then
return false unless it.family == family
begin_addr <= it.begin_addr && end_addr >= it.end_addr
end
end
```
### *"then"* keyword as the pipeline operator:
Under certain conditions, "then" could offer similar capabilities to the pipeline operator of functional languages:
``` ruby
# assuming that "foo" and "bar" never return "false" or "nil"
# instead of writing this:
baz("string", bar(foo(), 2), 5)
# you could write this:
begin foo()
then bar(it, 2)
then baz("string", it, 5)
end
```
--
https://bugs.ruby-lang.org/
______________________________________________
ruby-core mailing list -- ruby-core@ml.ruby-lang.org
To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/
^ permalink raw reply [flat|nested] 3+ messages in thread
* [ruby-core:119474] [Ruby master Feature#20786] Flow chaining with "then" keyword
2024-10-06 14:04 [ruby-core:119469] [Ruby master Feature#20786] Flow chaining with "then" keyword lpogic via ruby-core
2024-10-07 2:18 ` [ruby-core:119471] " nobu (Nobuyoshi Nakada) via ruby-core
@ 2024-10-07 9:39 ` lpogic via ruby-core
1 sibling, 0 replies; 3+ messages in thread
From: lpogic via ruby-core @ 2024-10-07 9:39 UTC (permalink / raw)
To: ruby-core; +Cc: lpogic
Issue #20786 has been updated by lpogic (Łukasz Pomietło).
You're right. Thats why I proposed to evaluate rhs conditionally.
The canonical form has a clear *beginning* and *end*, so I assume your comment refers to the beginningless form. Let's look the following example:
``` ruby
foo then bar end
```
The "bar" is evaluated only if "foo" is true, so it does quiet the same what:
``` ruby
if foo then bar end
```
does (except that first form result is *"false"* if *"foo"* returns *"false"*).
Another examples:
``` ruby
# chained flow in condition:
if (foo then baz end) then
bar
end
# chained flow in statement:
if foo
bar then baz end # please note that in the beginless form the expression is required on the left side of the first "then"
end
```
I think the most questionable case is this:
``` ruby
if foo then bar then baz end end
```
So I see 2 solutions:
1) If "if" is used, the first "then" belongs to another flow, so the case is the same as one above.
2) "if" can also be divided into steps, so the case is as follows:
``` ruby
if foo
then
bar
then
baz
end # please note that the second "end" has been removed
```
I'm not sure which one would be better. In any case, the chain flow would allow for a notation like this:
``` ruby
begin
foo
then
bar
then
baz
ready?
then
p "ok"
end
```
instead of this:
``` ruby
if foo
if bar
baz
if ready?
p "ok"
end
end
end
```
There is also the issue of the "else" branch. Can be an alternative path for the last "then" branch or for all:
``` ruby
# the case:
if foo
then bar
then
baz
ready?
then p "ok"
else p "fail"
end
# "else" as an alternative to the last branch:
if foo
if bar
baz
if ready?
p "ok"
else
p "fail"
end
end
end
# "else" as an alternative to all branches:
if foo
if bar
baz
if ready?
p "ok"
else
p "fail"
end
else
p "fail"
end
else
p "fail"
end
```
Finally, I'm not sure if "then" rhs should be evaluated conditionally, as this could sometimes cause problems in applications like the pipeline operator. Maybe use a different keyword for conditionality, e.g. "andthen"? I believe it should be carefully analyzed.
----------------------------------------
Feature #20786: Flow chaining with "then" keyword
https://bugs.ruby-lang.org/issues/20786#change-110091
* Author: lpogic (Łukasz Pomietło)
* Status: Open
----------------------------------------
Hi,
I would like to propose using the *"then"* keyword to create chained flows.
### Background:
Original idea: https://bugs.ruby-lang.org/issues/20770#change-110056
However, the concept has changed slightly since then. I now assume that rhs is only calculated when lhs is true, which seems more compatible with the current usage of *"then"* keyword.
I would also like to move the discussion here as it may cause unnecessary chaos there.
### Basics:
In the canonical version, *"then"* is used in a *"begin..end"* block to split it into steps.
When the result of the last expression before *"then"* is not *"false"* or *"nil"*, it is passed as an argument to the next step. Otherwise, all subsequent steps are skipped.
The result of the *"begin..end"* block is the result of the last expression, or *"false"*/*"nil"* if any step was skipped.
### Example:
``` ruby
# original code source: https://github.com/ruby/ruby/blob/a6383fbe1628bdaa9ec6a30b3baa60dd7430b461/lib/ipaddr.rb#L181C1-L185C6
def include?(other)
other = coerce_other(other)
return false unless other.family == family
begin_addr <= other.begin_addr && end_addr >= other.end_addr
end
# with chained flow
def include?(other)
begin
coerce_other(other)
then => coerced # then => name is my proposition of argument naming syntax
return false unless coerced.family == family
coerced
then => it
begin_addr <= it.begin_addr && end_addr >= it.end_addr
end
end
```
Please treat the canonical form as a starting point. As further improvements I would see:
- implicit block argument name
- implicit begin
- beginless *"then"*, when lhs is just expression
### Example with futher improvements:
``` ruby
def include?(other)
coerce_other(other)
then
it.family == family ? it : false
then
begin_addr <= it.begin_addr && end_addr >= it.end_addr
end
# or
def include?(other)
coerce_other other then
return false unless it.family == family
begin_addr <= it.begin_addr && end_addr >= it.end_addr
end
end
```
### *"then"* keyword as the pipeline operator:
Under certain conditions, "then" could offer similar capabilities to the pipeline operator of functional languages:
``` ruby
# assuming that "foo" and "bar" never return "false" or "nil"
# instead of writing this:
baz("string", bar(foo(), 2), 5)
# you could write this:
begin foo()
then bar(it, 2)
then baz("string", it, 5)
end
```
--
https://bugs.ruby-lang.org/
______________________________________________
ruby-core mailing list -- ruby-core@ml.ruby-lang.org
To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2024-10-07 9:40 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-10-06 14:04 [ruby-core:119469] [Ruby master Feature#20786] Flow chaining with "then" keyword lpogic via ruby-core
2024-10-07 2:18 ` [ruby-core:119471] " nobu (Nobuyoshi Nakada) via ruby-core
2024-10-07 9:39 ` [ruby-core:119474] " lpogic via ruby-core
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).