[#114062] [Ruby master Bug#19751] Ruby 3.2.2 Fails to Compile from Source — "martin_vahi (Martin Vahi) via ruby-core" <ruby-core@...>

Issue #19751 has been reported by martin_vahi (Martin Vahi).

9 messages 2023/07/01

[#114064] [Ruby master Feature#19752] Allow `--backtrace-limit` to appear in RUBYOPT — "tomstuart (Tom Stuart) via ruby-core" <ruby-core@...>

SXNzdWUgIzE5NzUyIGhhcyBiZWVuIHJlcG9ydGVkIGJ5IHRvbXN0dWFydCAoVG9tIFN0dWFydCku

8 messages 2023/07/01

[#114070] [Ruby master Bug#19753] IO::Buffer#get_string can't handle negative offset — "noteflakes (Sharon Rosner) via ruby-core" <ruby-core@...>

Issue #19753 has been reported by noteflakes (Sharon Rosner).

10 messages 2023/07/03

[#114072] [Ruby master Bug#19754] `IO::Buffer#get_string` raises unsuitable exception for too large offset — "nobu (Nobuyoshi Nakada) via ruby-core" <ruby-core@...>

Issue #19754 has been reported by nobu (Nobuyoshi Nakada).

7 messages 2023/07/03

[#114074] [Ruby master Feature#19755] Module#class_eval and Binding#eval use caller location by default — "byroot (Jean Boussier) via ruby-core" <ruby-core@...>

Issue #19755 has been reported by byroot (Jean Boussier).

15 messages 2023/07/03

[#114080] [Ruby master Bug#19756] URI::HTTP.build does not accept a host of `_gateway`, but `URI.parse` will. — "postmodern (Hal Brodigan) via ruby-core" <ruby-core@...>

Issue #19756 has been reported by postmodern (Hal Brodigan).

9 messages 2023/07/04

[#114168] [Ruby master Misc#19766] DevMeeting-2023-08-24 — "mame (Yusuke Endoh) via ruby-core" <ruby-core@...>

Issue #19766 has been reported by mame (Yusuke Endoh).

9 messages 2023/07/13

[#114222] [Ruby master Misc#19772] API Naming for YARP compiler — "jemmai (Jemma Issroff) via ruby-core" <ruby-core@...>

Issue #19772 has been reported by jemmai (Jemma Issroff).

31 messages 2023/07/17

[#114276] [Ruby master Bug#19784] String#delete_prefix! problem — "inversion (Yura Babak) via ruby-core" <ruby-core@...>

Issue #19784 has been reported by inversion (Yura Babak).

10 messages 2023/07/25

[#114309] [Ruby master Feature#19787] Add Enumerable#uniq_map, Enumerable::Lazy#uniq_map, Array#uniq_map and Array#uniq_map! — "joshuay03 (Joshua Young) via ruby-core" <ruby-core@...>

Issue #19787 has been reported by joshuay03 (Joshua Young).

7 messages 2023/07/29

[#114319] [Ruby master Feature#19790] Optionally write Ruby crash reports into a file rather than STDERR — "byroot (Jean Boussier) via ruby-core" <ruby-core@...>

SXNzdWUgIzE5NzkwIGhhcyBiZWVuIHJlcG9ydGVkIGJ5IGJ5cm9vdCAoSmVhbiBCb3Vzc2llciku

13 messages 2023/07/31

[ruby-core:114226] [Ruby master Feature#19764] Introduce defp keyword for defining overloadable, pattern matched methods

From: "baweaver (Brandon Weaver) via ruby-core" <ruby-core@...>
Date: 2023-07-18 05:48:03 UTC
List: ruby-core #114226
Issue #19764 has been updated by baweaver (Brandon Weaver).


Going to go through a few points here, sorry for the long reply.

### Taking - A gem implementation

I had hacked this behavior together at one point with `Taking`: https://github.com/baweaver/taking

```ruby
Point = Struct.new(:x, :y)

def handle_responses(...) = case Taking.from(...)
  in Point[x, 10 => y]
    Point[x, y + 1]
  in 1, 2, 3
    :numbers
  in 'a', 'b'
    :strings
  in :a, :b
    :symbols
  in x: 0, y: 0
    :origin
  in x: 0, y: (10..)
    :north
  else
    false
end

# Array-like

handle_responses(1,2,3)
# => :numbers
handle_responses('a', 'b')
# => :strings
handle_responses(:a, :b)
# => :symbols
handle_responses(:nope?)
# => false

# Hash-like

handle_responses(x: 0, y: 0)
# => :origin
handle_responses(x: 0, y: 15)
# => :north
handle_responses(x: 10, y: 15)
# => :false

# Deconstructable Object

handle_responses(Point[1, 10])
# => Point[1, 11]
```

### Precedent with Rescue

That said I could see a case for replicating the way `rescue` works currently, as it does establish a precedence:

```ruby
def some_method(args)
  # body
rescue
  # handling code
end
```

I can see a case for doing that for pattern matching, amending the previous examples above:

```ruby
def handle_responses
in Point[x, 10 => y]
  Point[x, y + 1]
in 1, 2, 3
  :numbers
in 'a', 'b'
  :strings
in :a, :b
  :symbols
in x: 0, y: 0
  :origin
in x: 0, y: (10..)
  :north
else
  false
end
```

### Potential Issues and Pitfalls

Now while I generally _like_ the idea there are a number of problems that this might present we must cover to be fair to the language. There are a _lot_ of questions here, and not all of them need to be answered to justify such a feature, but would need to be answered insofar as implementations are concerned for core folks, and these certainly are not comprehensive.

#### Args vs Body

What happens if someone uses the top level or uses the regular arguments syntax?:

```ruby
def some_method(a, b, c)
  # body ???
in pattern
end
```

Should pattern take precedence, or the top body? Should we even allow method arguments in the case there are patterns applied? Let's say we don't have arguments to the method in these cases and someone writes a method body outside of an `in pattern` right above the first one, what should we do then?

#### Super

How would we handle `super` with this? Argument forwarding and signatures could become very interesting here, especially if Sorbet or Steep get involved.

#### Typing

Speaking of, it would be real fun to make Sorbet and Steep play nicely with this. It'd pretty well crash the syntax as it exists today and require a decent amount of work to support.

#### Rescue

Would assume that this would remain top level and apply to every branch like so:

```ruby
def some_method
in pattern
  # ...
rescue something
  # ...
end
```

#### Absurdity

What happens if we don't handle every case? What if there's no `else`? Should that raise an exception for an unhandled case?

At least with static languages the absurdity clause (all inputs must be handled) it's easier to guarantee. In Ruby this would be a decent bit harder to do so perhaps just raising exceptions on unhandled is the easiest.

#### Signatures

What happens if you use a mix of positional and keyword arguments? Pattern matching also has find patterns (`*, arg, *`) that might not translate cleanly. How do we translate those into arguments?

Perhaps in this case we don't and we pass it with `...` much like the above, but then that brings up more fun with the next area.

#### Performance

This would be hard to optimize, and probably to JIT. It's possible but essentially with the above you end up with forwarding all arguments instead of a very restricted set you know you'd need.

----

Anyways, not saying don't do it, but this would be quite a task to really sort out all the ways it could be (ab)used and all the edge cases. 

----------------------------------------
Feature #19764: Introduce defp keyword for defining overloadable, pattern matched methods
https://bugs.ruby-lang.org/issues/19764#change-103912

* Author: zeke (Zeke Gabrielse)
* Status: Open
* Priority: Normal
----------------------------------------
Pattern matching has become one of my favorite features of Ruby, if not my favorite. It changed the way I write and express my thoughts through clean, maintainable code. And I'd like to use it *more*.

I propose a new keyword, `defp`, for defining a method which applies pattern matching to its arguments.

```ruby
defp call(String => s unless s in /^[a-z]/)
  puts "string: #{s.inspect} (capitalized)"
end

defp call(String => s)
  puts "string: #{s.inspect}"
end

defp call(Hash(foo:, bar:) => h)
  puts "hash: #{h.inspect}"
end

defp call(**nil)
  puts "no keyword args"
end

call("Example") # => string: "Example" (capitalized)
call("test")    # => string: "test"
call(foo: 1, bar: 2) 
# => hash: { :foo => 1, :bar => 2 }
```

Internally, this could be represented as the following `case..in` pseudocode:

```ruby
def call(...)
  case ...
  in String => s unless s in /foo/
    puts "string: #{s.inspect} (not foo)"
  in String => s
    puts "string: #{s.inspect}"
  in Hash(foo:, bar:) => h
    puts "hash: #{h.inspect}"
  in **nil
    puts "no keyword args"
  else
    raise NoMatchingMethod
  end
end
```

As you could imagine, this could be used to refactor a lot of code, making the developer's intent much clearer. From [complex methods that use `case` statements](https://github.com/rails/rails/blob/593893c901f87b4ed205751f72df41519b4d2da3/actionpack/lib/action_dispatch/routing/url_for.rb#L173-L193) for taking varied arguments (I'm sure all our code bases contain such `case` statements), to defining smaller, simpler methods that handle particular argument patterns.

In addition, not only can this improve code quality, but it brings in method overloads, and it also adds a way to define more typing to the language -- something that RBS has tried to do, to mixed reactions -- but in a more Ruby-like way that Rubyists are already learning *and loving*.

Thoughts?

Original idea by Victor Shepelev: https://zverok.space/blog/2023-05-05-ruby-types.html

Further discussion: https://news.ycombinator.com/item?id=35834351



-- 
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/postorius/lists/ruby-core.ml.ruby-lang.org/

In This Thread

Prev Next