Feature #16035
closedAllow non-finalizable objects such as Integer, static Symbol etc in ObjectSpace::WeakMap
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) about 5 years ago
42
never be collected. Is it intentional?
Updated by ko1 (Koichi Sasada) about 5 years ago
- Status changed from Open to Feedback
Updated by ko1 (Koichi Sasada) about 5 years ago
- Status changed from Feedback to Assigned
- Assignee set to nobu (Nobuyoshi Nakada)
sorry, value is collectable (my misunderstand).
Updated by matz (Yukihiro Matsumoto) about 5 years ago
I think this is the required behavior for WeakMap
to implement a cache for example. Accepted.
Matz.
Updated by byroot (Jean Boussier) about 5 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) almost 3 years 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) almost 3 years ago
It's fine, even on MRI you'll get that with BigNum:
>> (2**68).equal?(2**68)
=> false
Updated by headius (Charles Nutter) almost 3 years 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) almost 3 years 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.