Project

General

Profile

Actions

Feature #16035

closed

Allow non-finalizable objects such as Integer, static Symbol etc in ObjectSpace::WeakMap

Added by byroot (Jean Boussier) over 2 years ago. Updated 10 days ago.

Status:
Closed
Priority:
Normal
Target version:
-
[ruby-core:94101]

Description

This goes one step farther than what nobu (Nobuyoshi Nakada) did in https://bugs.ruby-lang.org/issues/13498

With this patch, special objects such as static symbols, integers, etc can be used as either key or values inside WeakMap. They simply don't have a finalizer defined on them.

This is useful if you need to deduplicate value objects, e.g. some minimal use case:

class Money
  REGISTRY = ObjectSpace::WeakMap.new
  private_constant :REGISTRY

  def self.new(amount)
    REGISTRY[amount] ||= super.freeze
  end

  def initialize(amount)
    @amount = amount
  end
end

if Money.new(42).eql?(Money.new(42))
  puts "Same instance"
else
  puts "Different instances"
end

This is a very simple example, but more complex examples can create use a dynamically created symbol as deduplication key, etc.

It also removes one weirdness introduced in the mentioned patch:

wmap = ObjectSpace::WeakMap.new
wmap["foo".to_sym] = Object.new # works fine with dynamic symbols
wmap[:bar] = Object.new # cannot define finalizer for Symbol (ArgumentError)

Proposed patch: https://github.com/ruby/ruby/pull/2313

Updated by ko1 (Koichi Sasada) over 2 years ago

42 never be collected. Is it intentional?

Actions #2

Updated by ko1 (Koichi Sasada) over 2 years ago

  • Status changed from Open to Feedback

Updated by ko1 (Koichi Sasada) over 2 years ago

  • Assignee set to nobu (Nobuyoshi Nakada)
  • Status changed from Feedback to Assigned

sorry, value is collectable (my misunderstand).

Updated by matz (Yukihiro Matsumoto) over 2 years ago

I think this is the required behavior for WeakMap to implement a cache for example. Accepted.

Matz.

Actions #5

Updated by byroot (Jean Boussier) over 2 years ago

  • Status changed from Assigned to Closed

Applied in changeset git|a4a19b114ba94b8f28d5a91aee5d595a516006d5.


Allow non-finalizable objects in ObjectSpace::WeakMap

[feature #16035]

This goes one step farther than what nobu did in [feature #13498]

With this patch, special objects such as static symbols, integers, etc can be used as either key or values inside WeakMap. They simply don't have a finalizer defined on them.

This is useful if you need to deduplicate value objects

Updated by headius (Charles Nutter) 12 days ago

I am behind the times here, but it is worth noting that implementations which cannot guarantee idempotency of fixnum and flonum-ranged Integers and Floats will have trouble implementing the spirit of this change. On JRuby, it is not possible to treat two fixnums created separately as the same object, since the WeakMap implementation needs to compare by object identity and JRuby represents all fixnums and flonums as full objects with their own identities.

Updated by byroot (Jean Boussier) 12 days ago

It's fine, even on MRI you'll get that with BigNum:

>> (2**68).equal?(2**68)
=> false

Updated by headius (Charles Nutter) 12 days ago

byroot (Jean Boussier) True, and this has indeed always been a known behavior difference on JRuby that users just deal with (don't use bare integers as keys, mostly). I really just want to point out that this difference extends to key identity in WeakMap and other identity maps.

Updated by Eregon (Benoit Daloze) 10 days ago

We implemented this correctly in TruffleRuby.
It's a little bit tricky as then indeed some wrapper with custom equals() is needed for primitives:
https://github.com/oracle/truffleruby/commit/e839f3f5887bdd04b855e286e9f74443fbcccf53
That means the exact same semantics as equal? on CRuby.

Actions

Also available in: Atom PDF