ruby-core@ruby-lang.org archive (unofficial mirror)
 help / color / mirror / Atom feed
* [ruby-core:121184] [Ruby master Feature#21160] Local return from proc
@ 2025-02-26 23:31 JustJosh (Joshua Stowers) via ruby-core
  2025-02-27  0:04 ` [ruby-core:121185] " ufuk (Ufuk Kayserilioglu) via ruby-core
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: JustJosh (Joshua Stowers) via ruby-core @ 2025-02-26 23:31 UTC (permalink / raw)
  To: ruby-core; +Cc: JustJosh (Joshua Stowers)

Issue #21160 has been reported by JustJosh (Joshua Stowers).

----------------------------------------
Feature #21160: Local return from proc
https://bugs.ruby-lang.org/issues/21160

* Author: JustJosh (Joshua Stowers)
* Status: Open
----------------------------------------
When writing DSL-style helper methods, I often store block arguments as procs to use as callbacks.
Using `return` in a proc will return from the context it was created in, which is unsuitable in the following example.
Since procs cannot be converted to lambdas, I end up using `next` to return a value from them early.

Example:
``` ruby
fulfills_promise :generate_large_image do |image_data|
  next false if image_data.nil?

  puts 'Saving image..'
  # etc.
end
```

This works but confuses most readers.

I propose introducing an alias for it that is more appropriate for this use case.
Perhaps `pass` or `continue`?

It's worth noting that `return` would work with `fulfills_promise :foo, -> (bar) do`, though it detracts a bit from a DSL's expressiveness.




-- 
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] 5+ messages in thread

* [ruby-core:121185] [Ruby master Feature#21160] Local return from proc
  2025-02-26 23:31 [ruby-core:121184] [Ruby master Feature#21160] Local return from proc JustJosh (Joshua Stowers) via ruby-core
@ 2025-02-27  0:04 ` ufuk (Ufuk Kayserilioglu) via ruby-core
  2025-02-27  0:47 ` [ruby-core:121186] " JustJosh (Joshua Stowers) via ruby-core
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: ufuk (Ufuk Kayserilioglu) via ruby-core @ 2025-02-27  0:04 UTC (permalink / raw)
  To: ruby-core; +Cc: ufuk (Ufuk Kayserilioglu)

Issue #21160 has been updated by ufuk (Ufuk Kayserilioglu).


`next` isn't necessarily the correct thing to use here, `break` is:
```ruby
foo = fulfills_promise :generate_large_image do |image_data|
  break false if image_data.nil?

  puts 'Saving image..'
  # etc.
end

foo #=> false
```

And the name exactly conveys the concept of breaking out of the block, in my opinion.

For example:
```ruby
result = (1..100).each do |num|
  break num if num > 3
  puts num
end

puts "Got result #{result}"
```
will print
```
1
2
3
Got result 4

----------------------------------------
Feature #21160: Local return from proc
https://bugs.ruby-lang.org/issues/21160#change-112120

* Author: JustJosh (Joshua Stowers)
* Status: Open
----------------------------------------
When writing DSL-style helper methods, I often store block arguments as procs to use as callbacks.
Using `return` in a proc will return from the context it was created in, which is unsuitable in the following example.
Since procs cannot be converted to lambdas, I end up using `next` to return a value from them early.

Example:
``` ruby
fulfills_promise :generate_large_image do |image_data|
  next false if image_data.nil?

  puts 'Saving image..'
  # etc.
end
```

This works but confuses most readers.

I propose introducing an alias for it that is more appropriate for this use case.
Perhaps `pass` or `continue`?

It's worth noting that `return` would work with `fulfills_promise :foo, -> (bar) do`, though it detracts a bit from a DSL's expressiveness.




-- 
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] 5+ messages in thread

* [ruby-core:121186] [Ruby master Feature#21160] Local return from proc
  2025-02-26 23:31 [ruby-core:121184] [Ruby master Feature#21160] Local return from proc JustJosh (Joshua Stowers) via ruby-core
  2025-02-27  0:04 ` [ruby-core:121185] " ufuk (Ufuk Kayserilioglu) via ruby-core
@ 2025-02-27  0:47 ` JustJosh (Joshua Stowers) via ruby-core
  2025-02-27  2:23 ` [ruby-core:121188] " nobu (Nobuyoshi Nakada) via ruby-core
  2025-02-27 17:05 ` [ruby-core:121200] " JustJosh (Joshua Stowers) via ruby-core
  3 siblings, 0 replies; 5+ messages in thread
From: JustJosh (Joshua Stowers) via ruby-core @ 2025-02-27  0:47 UTC (permalink / raw)
  To: ruby-core; +Cc: JustJosh (Joshua Stowers)

Issue #21160 has been updated by JustJosh (Joshua Stowers).


ufuk (Ufuk Kayserilioglu) wrote in #note-1:
> `next` isn't necessarily the correct thing to use here, `break` is:

I've tried `break` without success - I get `LocalJumpError: break from proc-closure`

Here is a more complete example of what I am doing:
```ruby
class Example
  def self.fulfills_promise(promise_name, &block)
    @@promise_callbacks ||= {}
    @@promise_callbacks[promise_name] = block
  end

  def self.fulfill_promise(promise_name, data)
    puts "Fulfilling promise: #{promise_name}"

    callback = @@promise_callbacks[promise_name]

    if callback.call(data)
      puts 'Complete!'
    else
      puts 'Failed!'
    end
  end

  fulfills_promise :generate_large_image do |image_data|
    puts 'Will finalize large image...'
    break false # Indicate something went wrong
    puts 'Finalized!'
    true
  end
end


Example.fulfill_promise(:generate_large_image, 'image data')
```

----------------------------------------
Feature #21160: Local return from proc
https://bugs.ruby-lang.org/issues/21160#change-112121

* Author: JustJosh (Joshua Stowers)
* Status: Open
----------------------------------------
When writing DSL-style helper methods, I often store block arguments as procs to use as callbacks.
Using `return` in a proc will return from the context it was created in, which is unsuitable in the following example.
Since procs cannot be converted to lambdas, I end up using `next` to return a value from them early.

Example:
``` ruby
fulfills_promise :generate_large_image do |image_data|
  next false if image_data.nil?

  puts 'Saving image..'
  # etc.
end
```

This works but confuses most readers.

I propose introducing an alias for it that is more appropriate for this use case.
Perhaps `pass` or `continue`?

It's worth noting that `return` would work with `fulfills_promise :foo, -> (bar) do`, though it detracts a bit from a DSL's expressiveness.




-- 
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] 5+ messages in thread

* [ruby-core:121188] [Ruby master Feature#21160] Local return from proc
  2025-02-26 23:31 [ruby-core:121184] [Ruby master Feature#21160] Local return from proc JustJosh (Joshua Stowers) via ruby-core
  2025-02-27  0:04 ` [ruby-core:121185] " ufuk (Ufuk Kayserilioglu) via ruby-core
  2025-02-27  0:47 ` [ruby-core:121186] " JustJosh (Joshua Stowers) via ruby-core
@ 2025-02-27  2:23 ` nobu (Nobuyoshi Nakada) via ruby-core
  2025-02-27 17:05 ` [ruby-core:121200] " JustJosh (Joshua Stowers) via ruby-core
  3 siblings, 0 replies; 5+ messages in thread
From: nobu (Nobuyoshi Nakada) via ruby-core @ 2025-02-27  2:23 UTC (permalink / raw)
  To: ruby-core; +Cc: nobu (Nobuyoshi Nakada)

Issue #21160 has been updated by nobu (Nobuyoshi Nakada).


Why not rescue `LocalJumpError`?

```ruby
  def self.fulfill_promise(promise_name, data)
    puts "Fulfilling promise: #{promise_name}"

    callback = @@promise_callbacks[promise_name]

    begin
      complete = callback.call(data)
    rescue LocalJumpError => e
      complete = e.exit_value
    end
    if complete
      puts 'Complete!'
    else
      puts 'Failed!'
    end
  end
```

This works with both of `return` and `break` in already released versions of Ruby, and even your DSL does not need to change.
If we were add a new keyword, you would have to wait for the end of this year at least.

----------------------------------------
Feature #21160: Local return from proc
https://bugs.ruby-lang.org/issues/21160#change-112123

* Author: JustJosh (Joshua Stowers)
* Status: Open
----------------------------------------
When writing DSL-style helper methods, I often store block arguments as procs to use as callbacks.
Using `return` in a proc will return from the context it was created in, which is unsuitable in the following example.
Since procs cannot be converted to lambdas, I end up using `next` to return a value from them early.

Example:
``` ruby
fulfills_promise :generate_large_image do |image_data|
  next false if image_data.nil?

  puts 'Saving image..'
  # etc.
end
```

This works but confuses most readers.

I propose introducing an alias for it that is more appropriate for this use case.
Perhaps `pass` or `continue`?

It's worth noting that `return` would work with `fulfills_promise :foo, -> (bar) do`, though it detracts a bit from a DSL's expressiveness.




-- 
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] 5+ messages in thread

* [ruby-core:121200] [Ruby master Feature#21160] Local return from proc
  2025-02-26 23:31 [ruby-core:121184] [Ruby master Feature#21160] Local return from proc JustJosh (Joshua Stowers) via ruby-core
                   ` (2 preceding siblings ...)
  2025-02-27  2:23 ` [ruby-core:121188] " nobu (Nobuyoshi Nakada) via ruby-core
@ 2025-02-27 17:05 ` JustJosh (Joshua Stowers) via ruby-core
  3 siblings, 0 replies; 5+ messages in thread
From: JustJosh (Joshua Stowers) via ruby-core @ 2025-02-27 17:05 UTC (permalink / raw)
  To: ruby-core; +Cc: JustJosh (Joshua Stowers)

Issue #21160 has been updated by JustJosh (Joshua Stowers).


nobu (Nobuyoshi Nakada) wrote in #note-3:
> Why not rescue `LocalJumpError`?

That is definitely a better solution than requiring developers to use `next`.
Thank you for the suggestion.

As I understand it, the reason `break` doesn't work in my example is because the proc is "orphaned."
Ref: https://docs.ruby-lang.org/en/3.3/Proc.html#class-Proc-label-Orphaned+Proc
If an orphan-friendly implementation or alternative to `break` is worth considering, I would be happy to take a shot.


----------------------------------------
Feature #21160: Local return from proc
https://bugs.ruby-lang.org/issues/21160#change-112138

* Author: JustJosh (Joshua Stowers)
* Status: Open
----------------------------------------
When writing DSL-style helper methods, I often store block arguments as procs to use as callbacks.
Using `return` in a proc will return from the context it was created in, which is unsuitable in the following example.
Since procs cannot be converted to lambdas, I end up using `next` to return a value from them early.

Example:
``` ruby
fulfills_promise :generate_large_image do |image_data|
  next false if image_data.nil?

  puts 'Saving image..'
  # etc.
end
```

This works but confuses most readers.

I propose introducing an alias for it that is more appropriate for this use case.
Perhaps `pass` or `continue`?

It's worth noting that `return` would work with `fulfills_promise :foo, -> (bar) do`, though it detracts a bit from a DSL's expressiveness.




-- 
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] 5+ messages in thread

end of thread, other threads:[~2025-02-27 17:06 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-02-26 23:31 [ruby-core:121184] [Ruby master Feature#21160] Local return from proc JustJosh (Joshua Stowers) via ruby-core
2025-02-27  0:04 ` [ruby-core:121185] " ufuk (Ufuk Kayserilioglu) via ruby-core
2025-02-27  0:47 ` [ruby-core:121186] " JustJosh (Joshua Stowers) via ruby-core
2025-02-27  2:23 ` [ruby-core:121188] " nobu (Nobuyoshi Nakada) via ruby-core
2025-02-27 17:05 ` [ruby-core:121200] " JustJosh (Joshua Stowers) 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).