Project

General

Profile

Actions

Feature #21857

open

Introduce to_proc pattern

Feature #21857: Introduce to_proc pattern

Added by sanfrecce-osaka (Masatoshi Moritsuka) 4 months ago. Updated 11 days ago.

Status:
Assigned
Target version:
-
[ruby-dev:<unknown>]

Description

When object has some logics, we can use &object syntax with Enumerable or Array, etc.

users.any?(&:admin?)

There are some times when I want to write pattern matching similar to the syntax, but currently we either have to write proc or combine pin operator with to_proc, which is a bit verbose.

users in [*, ^(:admin?.to_proc), *]
users in [*, -> (user) { user.admin? }, *]

Therefore, I propose introducing a new pattern into pattern matching.
The pattern matches an object such that pattern.to_proc === object.
This allows us to write code with a familiarity close to the syntax we're accustomed to.

users in [*, &:admin?, *]

Updated by matheusrich (Matheus Richard) 4 months ago Actions #1

Could you add why one would prefer writing users in [*, &:admin?, *] over users.any?(&:admin?)?

Updated by mame (Yusuke Endoh) 4 months ago Actions #2

  • Status changed from Open to Assigned
  • Assignee set to ktsj (Kazuki Tsujimoto)

Updated by sanfrecce-osaka (Masatoshi Moritsuka) 2 months ago Actions #3

Could you add why one would prefer writing users in [*, &:admin?, *] over users.any?(&:admin?)?

Pattern matching can be combined with As pattern to both check whether something matches and bind the matched value to a variable at the same time.
Array#any? would suffice for just checking, but that's the key difference.
In the description of this issue, I also had As pattern in mind as a motivation:

users in [*, &:admin? => admin_user, *]

You might wonder if Array#find would do the job, but there are cases where I want pattern matching to guarantee that a match will always be found:

# admin_user could be nil, and it's not clear that this code expects it to always be found
admin_user = users.find(&:admin?)
# If no match, NoMatchingPatternError is raised, making it clear that this code expects a match to always exist
users => [*, &:admin? => admin_user, *]

Here's an example from code I wrote at work recently:

if statuses.intersection(available_statuses) in ^(:present?.to_proc) => target_statuses
  # any logics using target_statuses
else
  # any logics
end

Without pattern matching, assigning inside an if condition requires parentheses:

if (target_statuses = statuses.intersection(available_statuses)) && target_statuses.present?
  # any logics using target_statuses
else
  # any logics
end

Updated by ktsj (Kazuki Tsujimoto) 11 days ago Actions #4

I understand the motivation, but I'm still not fully convinced that this particular use case is enough to justify introducing dedicated syntax.
There are similar requests as well, such as wanting to match based on respond_to?. It might be more convincing if the proposal included a syntax that could cover those kinds of cases too.

Actions

Also available in: PDF Atom