[#103680] [Ruby master Bug#17843] Ruby on Rails error[BUG] Segmentation fault at 0x0000000000000110 ruby 3.0.1p64 (2021-04-05 revision 0fb782ee38) [x86_64-darwin15] (#42110) — nayaronfire@...

Issue #17843 has been reported by nayaronfire (kk nayar).

7 messages 2021/05/01

[#103686] [Ruby master Misc#17845] Windows Ruby - ucrt build? — Greg.mpls@...

Issue #17845 has been reported by MSP-Greg (Greg L).

22 messages 2021/05/01

[#103690] [Ruby master Bug#17846] Percent mode changes the output from ERB beyond what is documented — wolf@...

Issue #17846 has been reported by graywolf (Gray Wolf).

8 messages 2021/05/02

[#103724] [Ruby master Feature#17849] Fix Timeout.timeout so that it can be used in threaded Web servers — duerst@...

Issue #17849 has been reported by duerst (Martin D=FCrst).

22 messages 2021/05/05

[#103756] [Ruby master Feature#17853] Add Thread#thread_id — komamitsu@...

Issue #17853 has been reported by komamitsu (Mitsunori Komatsu).

11 messages 2021/05/06

[#103801] [Ruby master Feature#17859] Start IRB when running just `ruby` — deivid.rodriguez@...

Issue #17859 has been reported by deivid (David Rodr=EDguez).

18 messages 2021/05/12

[#103866] [Ruby master Bug#17866] Incompatible changes with Psych 4.0.0 — hsbt@...

Issue #17866 has been reported by hsbt (Hiroshi SHIBATA).

13 messages 2021/05/17

[#103892] [Ruby master Bug#17871] TestGCCompact#test_ast_compacts test failing again — jaruga@...

Issue #17871 has been reported by jaruga (Jun Aruga).

11 messages 2021/05/19

[#103912] [Ruby master Bug#17873] Update of default gems in Ruby 3.1 — hsbt@...

Issue #17873 has been reported by hsbt (Hiroshi SHIBATA).

38 messages 2021/05/20

[#103971] [Ruby master Bug#17880] [BUG] We are killing the stack canary set by `opt_setinlinecache` — jean.boussier@...

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

8 messages 2021/05/22

[#103974] [Ruby master Feature#17881] Add a Module#const_added callback — jean.boussier@...

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

29 messages 2021/05/22

[#104004] [Ruby master Feature#17883] Load bundler/setup earlier to make `bundle exec ruby -r` respect Gemfile — mame@...

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

21 messages 2021/05/24

[#104109] [Ruby master Feature#17930] Add column information into error backtrace — mame@...

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

34 messages 2021/05/31

[ruby-core:104037] [Ruby master Feature#16038] Provide a public WeakMap that compares by equality rather than by identity

From: jean.boussier@...
Date: 2021-05-25 13:51:30 UTC
List: ruby-core #104037
Issue #16038 has been updated by byroot (Jean Boussier).


> Instead of exploiting WeakMap, a dedicated cache library makes more sense.

I'm not sure how one could write such library today without a WeakMap (or other Weak* datastructure) like I'm requesting.

 

----------------------------------------
Feature #16038: Provide a public WeakMap that compares by equality rather than by identity 
https://bugs.ruby-lang.org/issues/16038#change-92175

* Author: byroot (Jean Boussier)
* Status: Open
* Priority: Normal
----------------------------------------
I know `ObjectSpace::WeakMap` isn't really supposed to be used, and that the blessed interface is `WeakRef`. However, I'd like to make a case for a better public WeakMap.

### Usage

As described in [Feature #16035], `WeakMap` is useful for deduplicating "value objects". A typical use case is as follows:

```ruby
class Position
  REGISTRY = {}
  private_constant :REGISTRY

  class << self
    def new(*)
      instance = super
      REGISTRY[instance] ||= instance
    end
  end

  attr_reader :x, :y, :z

  def initialize(x, y, z)
    @x = x
    @y = y
    @z = z
    freeze
  end

  def hash
    self.class.hash ^
      x.hash >> 1 ^
      y.hash >> 2 ^
      y.hash >> 3
  end

  def ==(other)
    other.is_a?(Position) &&
      other.x == x &&
      other.y == y &&
      other.z == z
  end
  alias_method :eql?, :==
end

p Position.new(1, 2, 3).equal?(Position.new(1, 2, 3))
```

That's pretty much the pattern [I used in Rails to deduplicate database metadata and save lots of memory](https://github.com/rails/rails/blob/f3c68c59ed57302ca54f4dfad0e91dbff426962d/activerecord/lib/active_record/connection_adapters/deduplicable.rb).

The big downside here is that these value objects can't be GCed anymore, so this pattern is not viable in many case.

### Why not use WeakRef

A couple of reasons. First, when using this pattern, the goal is to reduce memory usage, so having one extra `WeakRef` for every single value object is a bit counter productive. 

Then it's a bit annoying to work with, as you have to constantly check wether the reference is still alive, and/or rescue `WeakRef::RefError`.

Often, these two complications make the tradeoff not worth it.

### Ruby 2.7

Since [Feature #13498] `WeakMap` is a bit more usable as you can now use an interned string as the unique key, e.g.

```ruby
class Position
  REGISTRY = ObjectSpace::WeakMap.new
  private_constant :REGISTRY

  class << self
    def new(*)
      instance = super
      REGISTRY[instance.unique_id] ||= instance
    end
  end

  attr_reader :x, :y, :z, :unique_id

  def initialize(x, y, z)
    @x = x
    @y = y
    @z = z
    @unique_id = -"#{self.class}-#{x},#{y},#{z}"
    freeze
  end

  def hash
    self.class.hash ^
      x.hash >> 1 ^
      y.hash >> 2 ^
      y.hash >> 3
  end

  def ==(other)
    other.is_a?(Position) &&
      other.x == x &&
      other.y == y &&
      other.z == z
  end
  alias_method :eql?, :==
end

p Position.new(1, 2, 3).equal?(Position.new(1, 2, 3))
```

That makes the pattern much easier to work with than dealing with `WeakRef`, but there is still that an extra instance.

### Proposal

What would be ideal would be a `WeakMap` that works by equality, so that the first snippet could simply replace `{}` by `WeakMap.new`. 

Changing `ObjectSpace::WeakMap`'s behavior would cause issues, and I see two possibilities:

  - The best IMO would be to have a new top level `::WeakMap` be the equality based map, and have `ObjectSpace::WeakMap` remain as a semi-private interface for backing up `WeakRef`.
  - Or alternatively, `ObjectSpace::WeakMap` could have a `compare_by_equality` method (inverse of `Hash#compare_by_identity`) to change its behavior post instantiation.

I personally prefer the first one.




-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:[email protected]?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>

In This Thread

Prev Next