* [ruby-core:92507] [Ruby trunk Feature#15814] Capturing variable in case-when branches
[not found] <redmine.issue-15814.20190501042430@ruby-lang.org>
@ 2019-05-01 4:24 ` unihedron
2019-05-01 4:25 ` [ruby-core:92508] " unihedron
` (3 subsequent siblings)
4 siblings, 0 replies; 5+ messages in thread
From: unihedron @ 2019-05-01 4:24 UTC (permalink / raw)
To: ruby-core
Issue #15814 has been reported by unihedron (Unihedron 0).
----------------------------------------
Feature #15814: Capturing variable in case-when branches
https://bugs.ruby-lang.org/issues/15814
* Author: unihedron (Unihedron 0)
* Status: Open
* Priority: Normal
* Assignee:
* Target version:
----------------------------------------
In ruby, when a case-when statement is written, the when branches accepts expressions which will be evaluated to objects, then === is called to check if any of them returns true:
```ruby
case 'a'
when 'abc'
# not matched
when Regexp.new('[abc]')
puts :matched # => matched
end
```
To demonstrate what is being done here, this is a mock:
```ruby
equal_all_mock = Object.new
class << equal_all_mock
def ===(anything) true end
end
# 1
case 'a'
when equal_all_mock
puts :matched # => matched
end
# 2
if equal_all_mock === 'a'
puts :matched # => matched
end
```
Often times when matching for conditional statements, they have values in addition to being truthy or falsey; for example, it is very tempting to write (bugged) code like this (context: parsing 2D robot path instructions):
```ruby
case
when i = '^v<>'.index[code]
x += [0, 0, -1, 1][i]
y += [1, -1, 0, 0][i]
when code = '/\\'[code]
if code == '/'
dx, dy = dy, dx
else
dx, dy = -dy, -dx
end
when code == '#'
dx = -dx
dy = -dy
end
```
This pattern has problems:
1. Using assignment to capture expressions "leaks" the local variable into the current scope, which the case block doesn't lock into a block scope, as it's not a proc
2. Even if the match fails, the expression is still written; `code = '/\\'[code]` in this case may assign nil, of which then `code == '#'` will fail
3. The alternative would be using regex, such as `/\^v<>/` and then using `$&` to fetch match data... but the global variable pattern is said to be discouraged, and while it works in this specific case it doesn't work in others, like if I want to act upon the index of an array search (but not when the search result is nil)
Thus my proposal:
```ruby
case
when '^v<>'.index[code] => i
x += [0, 0, -1, 1][i]
y += [1, -1, 0, 0][i]
when '/\\'[code] => code
if code == '/'
dx, dy = dy, dx
else
dx, dy = -dy, -dx
end
when code == '#'
dx = -dx
dy = -dy
end
```
This is based on the `rescue Exception => e` syntax. The `when expression => i` format could potentially even be extended to:
```
case 'foobar'
when /fo./ => match
p match # => foo
end
```
or with a proc that accepts 0~1 parameters (if it expects one, ruby could feed in the truthy value):
```
case
when '^v<>'.index[code] do |i|
x += [0, 0, -1, 1][i]
y += [1, -1, 0, 0][i]
end
when '/\\'[code] do |code|
if code == '/'
dx, dy = dy, dx
else
dx, dy = -dy, -dx
end
end
when code == '#'
dx = -dx
dy = -dy
end
```
While some cases like these could be replaced by if-else statements I feel like this would be much better as an enhancement on the pattern-matching side. Scala, for example, does have `case x if x % 15 == 0 => { statements }` in its pattern-matching; handy when writing fizzbuzz.
--
https://bugs.ruby-lang.org/
^ permalink raw reply [flat|nested] 5+ messages in thread
* [ruby-core:92508] [Ruby trunk Feature#15814] Capturing variable in case-when branches
[not found] <redmine.issue-15814.20190501042430@ruby-lang.org>
2019-05-01 4:24 ` [ruby-core:92507] [Ruby trunk Feature#15814] Capturing variable in case-when branches unihedron
@ 2019-05-01 4:25 ` unihedron
2019-05-01 4:31 ` [ruby-core:92509] " tad.a.digger
` (2 subsequent siblings)
4 siblings, 0 replies; 5+ messages in thread
From: unihedron @ 2019-05-01 4:25 UTC (permalink / raw)
To: ruby-core
Issue #15814 has been updated by unihedron (Unihedron 0).
Description updated
I messed up brackets.
----------------------------------------
Feature #15814: Capturing variable in case-when branches
https://bugs.ruby-lang.org/issues/15814#change-77868
* Author: unihedron (Unihedron 0)
* Status: Open
* Priority: Normal
* Assignee:
* Target version:
----------------------------------------
In ruby, when a case-when statement is written, the when branches accepts expressions which will be evaluated to objects, then === is called to check if any of them returns true:
```ruby
case 'a'
when 'abc'
# not matched
when Regexp.new('[abc]')
puts :matched # => matched
end
```
To demonstrate what is being done here, this is a mock:
```ruby
equal_all_mock = Object.new
class << equal_all_mock
def ===(anything) true end
end
# 1
case 'a'
when equal_all_mock
puts :matched # => matched
end
# 2
if equal_all_mock === 'a'
puts :matched # => matched
end
```
Often times when matching for conditional statements, they have values in addition to being truthy or falsey; for example, it is very tempting to write (bugged) code like this (context: parsing 2D robot path instructions):
```ruby
case
when i = '^v<>'.index(code)
x += [0, 0, -1, 1][i]
y += [1, -1, 0, 0][i]
when code = '/\\'[code]
if code == '/'
dx, dy = dy, dx
else
dx, dy = -dy, -dx
end
when code == '#'
dx = -dx
dy = -dy
end
```
This pattern has problems:
1. Using assignment to capture expressions "leaks" the local variable into the current scope, which the case block doesn't lock into a block scope, as it's not a proc
2. Even if the match fails, the expression is still written; `code = '/\\'[code]` in this case may assign nil, of which then `code == '#'` will fail
3. The alternative would be using regex, such as `/\^v<>/` and then using `$&` to fetch match data... but the global variable pattern is said to be discouraged, and while it works in this specific case it doesn't work in others, like if I want to act upon the index of an array search (but not when the search result is nil)
Thus my proposal:
```ruby
case
when '^v<>'.index(code) => i
x += [0, 0, -1, 1][i]
y += [1, -1, 0, 0][i]
when '/\\'[code] => code
if code == '/'
dx, dy = dy, dx
else
dx, dy = -dy, -dx
end
when code == '#'
dx = -dx
dy = -dy
end
```
This is based on the `rescue Exception => e` syntax. The `when expression => i` format could potentially even be extended to:
```
case 'foobar'
when /fo./ => match
p match # => foo
end
```
or with a proc that accepts 0~1 parameters (if it expects one, ruby could feed in the truthy value):
```
case
when '^v<>'.index[code] do |i|
x += [0, 0, -1, 1][i]
y += [1, -1, 0, 0][i]
end
when '/\\'[code] do |code|
if code == '/'
dx, dy = dy, dx
else
dx, dy = -dy, -dx
end
end
when code == '#'
dx = -dx
dy = -dy
end
```
While some cases like these could be replaced by if-else statements I feel like this would be much better as an enhancement on the pattern-matching side. Scala, for example, does have `case x if x % 15 == 0 => { statements }` in its pattern-matching; handy when writing fizzbuzz.
--
https://bugs.ruby-lang.org/
^ permalink raw reply [flat|nested] 5+ messages in thread
* [ruby-core:92509] [Ruby trunk Feature#15814] Capturing variable in case-when branches
[not found] <redmine.issue-15814.20190501042430@ruby-lang.org>
2019-05-01 4:24 ` [ruby-core:92507] [Ruby trunk Feature#15814] Capturing variable in case-when branches unihedron
2019-05-01 4:25 ` [ruby-core:92508] " unihedron
@ 2019-05-01 4:31 ` tad.a.digger
2019-05-01 4:34 ` [ruby-core:92510] " nobu
2019-05-01 8:03 ` [ruby-core:92511] " unihedron
4 siblings, 0 replies; 5+ messages in thread
From: tad.a.digger @ 2019-05-01 4:31 UTC (permalink / raw)
To: ruby-core
Issue #15814 has been updated by tad (Tadashi Saito).
What is the relationship with #14912 that already committed?
----------------------------------------
Feature #15814: Capturing variable in case-when branches
https://bugs.ruby-lang.org/issues/15814#change-77869
* Author: unihedron (Unihedron 0)
* Status: Open
* Priority: Normal
* Assignee:
* Target version:
----------------------------------------
In ruby, when a case-when statement is written, the when branches accepts expressions which will be evaluated to objects, then === is called to check if any of them returns true:
```ruby
case 'a'
when 'abc'
# not matched
when Regexp.new('[abc]')
puts :matched # => matched
end
```
To demonstrate what is being done here, this is a mock:
```ruby
equal_all_mock = Object.new
class << equal_all_mock
def ===(anything) true end
end
# 1
case 'a'
when equal_all_mock
puts :matched # => matched
end
# 2
if equal_all_mock === 'a'
puts :matched # => matched
end
```
Often times when matching for conditional statements, they have values in addition to being truthy or falsey; for example, it is very tempting to write (bugged) code like this (context: parsing 2D robot path instructions):
```ruby
case
when i = '^v<>'.index(code)
x += [0, 0, -1, 1][i]
y += [1, -1, 0, 0][i]
when code = '/\\'[code]
if code == '/'
dx, dy = dy, dx
else
dx, dy = -dy, -dx
end
when code == '#'
dx = -dx
dy = -dy
end
```
This pattern has problems:
1. Using assignment to capture expressions "leaks" the local variable into the current scope, which the case block doesn't lock into a block scope, as it's not a proc
2. Even if the match fails, the expression is still written; `code = '/\\'[code]` in this case may assign nil, of which then `code == '#'` will fail
3. The alternative would be using regex, such as `/\^v<>/` and then using `$&` to fetch match data... but the global variable pattern is said to be discouraged, and while it works in this specific case it doesn't work in others, like if I want to act upon the index of an array search (but not when the search result is nil)
Thus my proposal:
```ruby
case
when '^v<>'.index(code) => i
x += [0, 0, -1, 1][i]
y += [1, -1, 0, 0][i]
when '/\\'[code] => code
if code == '/'
dx, dy = dy, dx
else
dx, dy = -dy, -dx
end
when code == '#'
dx = -dx
dy = -dy
end
```
This is based on the `rescue Exception => e` syntax. The `when expression => i` format could potentially even be extended to:
```
case 'foobar'
when /fo./ => match
p match # => foo
end
```
or with a proc that accepts 0~1 parameters (if it expects one, ruby could feed in the truthy value):
```
case
when '^v<>'.index[code] do |i|
x += [0, 0, -1, 1][i]
y += [1, -1, 0, 0][i]
end
when '/\\'[code] do |code|
if code == '/'
dx, dy = dy, dx
else
dx, dy = -dy, -dx
end
end
when code == '#'
dx = -dx
dy = -dy
end
```
While some cases like these could be replaced by if-else statements I feel like this would be much better as an enhancement on the pattern-matching side. Scala, for example, does have `case x if x % 15 == 0 => { statements }` in its pattern-matching; handy when writing fizzbuzz.
--
https://bugs.ruby-lang.org/
^ permalink raw reply [flat|nested] 5+ messages in thread
* [ruby-core:92510] [Ruby trunk Feature#15814] Capturing variable in case-when branches
[not found] <redmine.issue-15814.20190501042430@ruby-lang.org>
` (2 preceding siblings ...)
2019-05-01 4:31 ` [ruby-core:92509] " tad.a.digger
@ 2019-05-01 4:34 ` nobu
2019-05-01 8:03 ` [ruby-core:92511] " unihedron
4 siblings, 0 replies; 5+ messages in thread
From: nobu @ 2019-05-01 4:34 UTC (permalink / raw)
To: ruby-core
Issue #15814 has been updated by nobu (Nobuyoshi Nakada).
Description updated
That is the exactly same feature which I proposed yeas ago and was rejected.
----------------------------------------
Feature #15814: Capturing variable in case-when branches
https://bugs.ruby-lang.org/issues/15814#change-77870
* Author: unihedron (Unihedron 0)
* Status: Open
* Priority: Normal
* Assignee:
* Target version:
----------------------------------------
In ruby, when a case-when statement is written, the when branches accepts expressions which will be evaluated to objects, then === is called to check if any of them returns true:
```ruby
case 'a'
when 'abc'
# not matched
when Regexp.new('[abc]')
puts :matched # => matched
end
```
To demonstrate what is being done here, this is a mock:
```ruby
equal_all_mock = Object.new
class << equal_all_mock
def ===(anything) true end
end
# 1
case 'a'
when equal_all_mock
puts :matched # => matched
end
# 2
if equal_all_mock === 'a'
puts :matched # => matched
end
```
Often times when matching for conditional statements, they have values in addition to being truthy or falsey; for example, it is very tempting to write (bugged) code like this (context: parsing 2D robot path instructions):
```ruby
case
when i = '^v<>'.index(code)
x += [0, 0, -1, 1][i]
y += [1, -1, 0, 0][i]
when code = '/\\'[code]
if code == '/'
dx, dy = dy, dx
else
dx, dy = -dy, -dx
end
when code == '#'
dx = -dx
dy = -dy
end
```
This pattern has problems:
1. Using assignment to capture expressions "leaks" the local variable into the current scope, which the case block doesn't lock into a block scope, as it's not a proc
2. Even if the match fails, the expression is still written; `code = '/\\'[code]` in this case may assign nil, of which then `code == '#'` will fail
3. The alternative would be using regex, such as `/\^v<>/` and then using `$&` to fetch match data... but the global variable pattern is said to be discouraged, and while it works in this specific case it doesn't work in others, like if I want to act upon the index of an array search (but not when the search result is nil)
Thus my proposal:
```ruby
case
when '^v<>'.index(code) => i
x += [0, 0, -1, 1][i]
y += [1, -1, 0, 0][i]
when '/\\'[code] => code
if code == '/'
dx, dy = dy, dx
else
dx, dy = -dy, -dx
end
when code == '#'
dx = -dx
dy = -dy
end
```
This is based on the `rescue Exception => e` syntax. The `when expression => i` format could potentially even be extended to:
```ruby
case 'foobar'
when /fo./ => match
p match # => foo
end
```
or with a proc that accepts 0~1 parameters (if it expects one, ruby could feed in the truthy value):
```ruby
case
when '^v<>'.index[code] do |i|
x += [0, 0, -1, 1][i]
y += [1, -1, 0, 0][i]
end
when '/\\'[code] do |code|
if code == '/'
dx, dy = dy, dx
else
dx, dy = -dy, -dx
end
end
when code == '#'
dx = -dx
dy = -dy
end
```
While some cases like these could be replaced by if-else statements I feel like this would be much better as an enhancement on the pattern-matching side. Scala, for example, does have `case x if x % 15 == 0 => { statements }` in its pattern-matching; handy when writing fizzbuzz.
--
https://bugs.ruby-lang.org/
^ permalink raw reply [flat|nested] 5+ messages in thread
* [ruby-core:92511] [Ruby trunk Feature#15814] Capturing variable in case-when branches
[not found] <redmine.issue-15814.20190501042430@ruby-lang.org>
` (3 preceding siblings ...)
2019-05-01 4:34 ` [ruby-core:92510] " nobu
@ 2019-05-01 8:03 ` unihedron
4 siblings, 0 replies; 5+ messages in thread
From: unihedron @ 2019-05-01 8:03 UTC (permalink / raw)
To: ruby-core
Issue #15814 has been updated by unihedron (Unihedron 0).
#14912 is more thought-out and seems to have made good progress, my regret is I didn't come upon it when trying to search for duplicate issues. #14709 seems to have a collection of case studies and really interesting discussions, but "if we were going to add pattern matching in Ruby, we should add it with better syntax" which #14912 seems to address. Unfortunately I can't seem to close this ticket, even after having written this.
----------------------------------------
Feature #15814: Capturing variable in case-when branches
https://bugs.ruby-lang.org/issues/15814#change-77871
* Author: unihedron (Unihedron 0)
* Status: Open
* Priority: Normal
* Assignee:
* Target version:
----------------------------------------
In ruby, when a case-when statement is written, the when branches accepts expressions which will be evaluated to objects, then === is called to check if any of them returns true:
```ruby
case 'a'
when 'abc'
# not matched
when Regexp.new('[abc]')
puts :matched # => matched
end
```
To demonstrate what is being done here, this is a mock:
```ruby
equal_all_mock = Object.new
class << equal_all_mock
def ===(anything) true end
end
# 1
case 'a'
when equal_all_mock
puts :matched # => matched
end
# 2
if equal_all_mock === 'a'
puts :matched # => matched
end
```
Often times when matching for conditional statements, they have values in addition to being truthy or falsey; for example, it is very tempting to write (bugged) code like this (context: parsing 2D robot path instructions):
```ruby
case
when i = '^v<>'.index(code)
x += [0, 0, -1, 1][i]
y += [1, -1, 0, 0][i]
when code = '/\\'[code]
if code == '/'
dx, dy = dy, dx
else
dx, dy = -dy, -dx
end
when code == '#'
dx = -dx
dy = -dy
end
```
This pattern has problems:
1. Using assignment to capture expressions "leaks" the local variable into the current scope, which the case block doesn't lock into a block scope, as it's not a proc
2. Even if the match fails, the expression is still written; `code = '/\\'[code]` in this case may assign nil, of which then `code == '#'` will fail
3. The alternative would be using regex, such as `/\^v<>/` and then using `$&` to fetch match data... but the global variable pattern is said to be discouraged, and while it works in this specific case it doesn't work in others, like if I want to act upon the index of an array search (but not when the search result is nil)
Thus my proposal:
```ruby
case
when '^v<>'.index(code) => i
x += [0, 0, -1, 1][i]
y += [1, -1, 0, 0][i]
when '/\\'[code] => code
if code == '/'
dx, dy = dy, dx
else
dx, dy = -dy, -dx
end
when code == '#'
dx = -dx
dy = -dy
end
```
This is based on the `rescue Exception => e` syntax. The `when expression => i` format could potentially even be extended to:
```ruby
case 'foobar'
when /fo./ => match
p match # => foo
end
```
or with a proc that accepts 0~1 parameters (if it expects one, ruby could feed in the truthy value):
```ruby
case
when '^v<>'.index[code] do |i|
x += [0, 0, -1, 1][i]
y += [1, -1, 0, 0][i]
end
when '/\\'[code] do |code|
if code == '/'
dx, dy = dy, dx
else
dx, dy = -dy, -dx
end
end
when code == '#'
dx = -dx
dy = -dy
end
```
While some cases like these could be replaced by if-else statements I feel like this would be much better as an enhancement on the pattern-matching side. Scala, for example, does have `case x if x % 15 == 0 => { statements }` in its pattern-matching; handy when writing fizzbuzz.
--
https://bugs.ruby-lang.org/
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2019-05-01 8:03 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
[not found] <redmine.issue-15814.20190501042430@ruby-lang.org>
2019-05-01 4:24 ` [ruby-core:92507] [Ruby trunk Feature#15814] Capturing variable in case-when branches unihedron
2019-05-01 4:25 ` [ruby-core:92508] " unihedron
2019-05-01 4:31 ` [ruby-core:92509] " tad.a.digger
2019-05-01 4:34 ` [ruby-core:92510] " nobu
2019-05-01 8:03 ` [ruby-core:92511] " unihedron
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 read-only IMAP folder(s) and NNTP newsgroup(s).