Project

General

Profile

Actions

Feature #20786

closed

Flow chaining with "then" keyword

Added by lpogic (Łukasz Pomietło) about 2 months ago. Updated 15 days ago.

Status:
Rejected
Assignee:
-
Target version:
-
[ruby-core:119469]

Description

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:

# 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:

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:

# 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
Actions

Also available in: Atom PDF

Like0
Like0Like0Like0