Feature #3222
closedCan bignums have singleton class & methods?
Description
=begin
Fixing up the rubyspecs led me to the following:
bn = 1 << 100
class << bn
def foo
42
end
end
=> TypeError: can't define singleton method "foo" for Bignum¶
bn.define_singleton_method(:foo){42}
=> TypeError: can't define singleton method "foo" for Bignum¶
On the other hand...
module Bar
def foo
42
end
end
class << bn
include Bar
end
bn.foo # => 42
If Ruby won't allow singleton methods for Bignum, then shouldn't it disallow access to the singleton class completely?
See also issue #601
=end
Updated by shyouhei (Shyouhei Urabe) over 14 years ago
=begin
Seems like a bug to me.
=end
Updated by mame (Yusuke Endoh) over 14 years ago
- Assignee set to matz (Yukihiro Matsumoto)
- Target version changed from 1.9.2 to 2.0.0
=begin
Hi,
I think this is not a bug.
It is still possible to define method to Bignum by redefining
singleton_method_added first:
x = (1 << 64)
def x.singleton_method_added(x)
end
def x.foo
p 1
end
x.foo #=> 1
Matz actually fixed #601, but he was not keen to fix this kind
of issue. [ruby-dev:36778]
In fact, the above loophole is indicated by matz himself.
I agree that Ruby should disallow access to the singleton class
completely, but I don't know if it is easy or not.
Anyway, we should discuss this matter towards 1.9.3 or later.
I move this ticket to Feature tracker.
--
Yusuke Endoh mame@tsg.ne.jp
=end
Updated by shyouhei (Shyouhei Urabe) almost 14 years ago
- Status changed from Open to Assigned
=begin
=end
Updated by ko1 (Koichi Sasada) almost 12 years ago
- Description updated (diff)
How about "Freeze" all of Bignum instance?
It is big change, but I believe no impact on it.
Related ticket:
[ruby-dev:46081] [ruby-trunk - Feature #6936][Assigned] Forbid singleton class and instance variabls for float
(how to add related ticket into redmine system?)
Updated by Eregon (Benoit Daloze) almost 12 years ago
ko1 (Koichi Sasada) wrote:
How about "Freeze" all of Bignum instance?
It is big change, but I believe no impact on it.
It makes sense to me to have them frozen, but I think we would need to freeze all Numeric instances as well for consistency (currently, Fixnum, Rational and Complex can have ivars).
Updated by ko1 (Koichi Sasada) almost 12 years ago
(2012/10/27 22:20), Eregon (Benoit Daloze) wrote:
It makes sense to me to have them frozen, but I think we would need to freeze all Numeric instances as well for consistency (currently, Fixnum, Rational and Complex can have ivars).
Float is frozen because of introduction of Flonum technique.
I think Fixnum should be also frozen.
I'm not sure about complex and rational. I don't think inconsistent
because we can make your own Numeric classes (and we can't force it
frozen). But I have no objection.
I want to ask real users of Numeric classes.
--
// SASADA Koichi at atdot dot net
Updated by matz (Yukihiro Matsumoto) almost 12 years ago
- Assignee changed from matz (Yukihiro Matsumoto) to ko1 (Koichi Sasada)
Accepted.
Matz.
Updated by ko1 (Koichi Sasada) almost 12 years ago
(2012/10/27 23:25), matz (Yukihiro Matsumoto) wrote:
Issue #3222 has been updated by matz (Yukihiro Matsumoto).
Assignee changed from matz (Yukihiro Matsumoto) to ko1 (Koichi Sasada)
Accepted.
Should I commit Fixnum and Bignum freezing patch (*1)?
*1: http://www.atdot.net/sp/view/4qjkcm/readonly
I got several errors on test-all caused by Fixnum freezing (no effect on
Bignum freezing at test-all). I want to make clear that Fixnum can be
frozen or not (Ruby programmers expect Fixnum is mutable?).
[ 3393/11368] TestEval#test_instance_eval_block_basic = 0.00 s
- Error:
test_instance_eval_block_basic(TestEval):
RuntimeError: can't modify frozen Fixnum
/mnt/sdb1/ruby/trunk/test/ruby/test_eval.rb:133:ininstance_variable_set' /mnt/sdb1/ruby/trunk/test/ruby/test_eval.rb:133:in
block in forall_TYPE'
/mnt/sdb1/ruby/trunk/test/ruby/test_eval.rb:132:ineach' /mnt/sdb1/ruby/trunk/test/ruby/test_eval.rb:132:in
forall_TYPE'
/mnt/sdb1/ruby/trunk/test/ruby/test_eval.rb:191:in `test_instance_eval_block_basic'[ 3398/11368] TestEval#test_instance_eval_string_basic = 0.00 s
2) Error:
test_instance_eval_string_basic(TestEval):
RuntimeError: can't modify frozen Fixnum
/mnt/sdb1/ruby/trunk/test/ruby/test_eval.rb:133:ininstance_variable_set' /mnt/sdb1/ruby/trunk/test/ruby/test_eval.rb:133:in
block in forall_TYPE'
/mnt/sdb1/ruby/trunk/test/ruby/test_eval.rb:132:ineach' /mnt/sdb1/ruby/trunk/test/ruby/test_eval.rb:132:in
forall_TYPE'
/mnt/sdb1/ruby/trunk/test/ruby/test_eval.rb:163:in `test_instance_eval_string_basic'[ 6110/11368] TestMarshal#test_fixnum_ivar = 0.00 s
3) Error:
test_fixnum_ivar(TestMarshal):
RuntimeError: can't modify frozen Fixnum
/mnt/sdb1/ruby/trunk/test/ruby/marshaltestlib.rb:186:inremove_instance_variable' /mnt/sdb1/ruby/trunk/test/ruby/marshaltestlib.rb:186:in
block in test_fixnum_ivar'
/mnt/sdb1/ruby/trunk/test/ruby/marshaltestlib.rb:186:ininstance_eval' /mnt/sdb1/ruby/trunk/test/ruby/marshaltestlib.rb:186:in
ensure in test_fixnum_ivar'
/mnt/sdb1/ruby/trunk/test/ruby/marshaltestlib.rb:186:in `test_fixnum_ivar'[ 6111/11368] TestMarshal#test_fixnum_ivar_self = 0.00 s
4) Error:
test_fixnum_ivar_self(TestMarshal):
RuntimeError: can't modify frozen Fixnum
/mnt/sdb1/ruby/trunk/test/ruby/marshaltestlib.rb:194:inremove_instance_variable' /mnt/sdb1/ruby/trunk/test/ruby/marshaltestlib.rb:194:in
block in test_fixnum_ivar_self'
/mnt/sdb1/ruby/trunk/test/ruby/marshaltestlib.rb:194:ininstance_eval' /mnt/sdb1/ruby/trunk/test/ruby/marshaltestlib.rb:194:in
ensure in test_fixnum_ivar_self'
/mnt/sdb1/ruby/trunk/test/ruby/marshaltestlib.rb:194:in `test_fixnum_ivar_self'[ 6695/11368] TestObject#test_freeze_immediate = 0.00 s
5) Failure:
test_freeze_immediate(TestObject) [/mnt/sdb1/ruby/trunk/test/ruby/test_object.rb:65]:
expected but was
.
The following log is from rubyspec.
A singleton class has class Bignum as the superclass of a Bignum instance ERROR
TypeError: can't define singleton
/mnt/sdb1/ruby/trunk/spec/rubyspec/language/singleton_class_spec.rb:79:insingleton_class' /mnt/sdb1/ruby/trunk/spec/rubyspec/language/singleton_class_spec.rb:79:in
block (3 levels) in <top (required)>'
/mnt/sdb1/ruby/trunk/spec/rubyspec/language/singleton_class_spec.rb:4:in `<top (required)>'
Kernel#instance_variables immediate values returns the correct array if an instance variable is added ERROR
RuntimeError: can't modify frozen Fixnum
/mnt/sdb1/ruby/trunk/spec/rubyspec/core/kernel/instance_variables_spec.rb:23:ininstance_variable_set' /mnt/sdb1/ruby/trunk/spec/rubyspec/core/kernel/instance_variables_spec.rb:23:in
block (4 levels) in <top (required)>'
/mnt/sdb1/ruby/trunk/spec/rubyspec/core/kernel/instance_variables_spec.rb:4:in `<top (required)>'
Kernel#taint has no effect on immediate values ERROR
RuntimeError: can't modify frozen Fixnum
/mnt/sdb1/ruby/trunk/spec/rubyspec/core/kernel/taint_spec.rb:37:intaint' /mnt/sdb1/ruby/trunk/spec/rubyspec/core/kernel/taint_spec.rb:37:in
block (3 levels) in <top (required)>'
/mnt/sdb1/ruby/trunk/spec/rubyspec/core/kernel/taint_spec.rb:36:ineach' /mnt/sdb1/ruby/trunk/spec/rubyspec/core/kernel/taint_spec.rb:36:in
block (2 levels) in <top (required)>'
/mnt/sdb1/ruby/trunk/spec/rubyspec/core/kernel/taint_spec.rb:4:in `<top (required)>'
Kernel#untrusted? has no effect on immediate values ERROR
RuntimeError: can't modify frozen Fixnum
/mnt/sdb1/ruby/trunk/spec/rubyspec/core/kernel/untrusted_spec.rb:21:inuntrust' /mnt/sdb1/ruby/trunk/spec/rubyspec/core/kernel/untrusted_spec.rb:21:in
block (3 levels) in <top (required)>'
/mnt/sdb1/ruby/trunk/spec/rubyspec/core/kernel/untrusted_spec.rb:4:in `<top (required)>'
Module#attr_accessor allows creating an attr_accessor on an immediate class ERROR
RuntimeError: can't modify frozen Fixnum
/mnt/sdb1/ruby/trunk/spec/rubyspec/core/module/attr_accessor_spec.rb:36:inblock (2 levels) in <top (required)>' /mnt/sdb1/ruby/trunk/spec/rubyspec/core/module/attr_accessor_spec.rb:4:in
<top (required)>'
Module#attr_reader allows for adding an attr_reader to an immediate ERROR
RuntimeError: can't modify frozen Fixnum
/mnt/sdb1/ruby/trunk/spec/rubyspec/core/module/attr_reader_spec.rb:32:ininstance_variable_set' /mnt/sdb1/ruby/trunk/spec/rubyspec/core/module/attr_reader_spec.rb:32:in
block (2 levels) in <top (required)>'
/mnt/sdb1/ruby/trunk/spec/rubyspec/core/module/attr_reader_spec.rb:4:in `<top (required)>'
Module#attr_writer allows for adding an attr_writer to an immediate ERROR
RuntimeError: can't modify frozen Fixnum
/mnt/sdb1/ruby/trunk/spec/rubyspec/core/module/attr_writer_spec.rb:32:inblock (2 levels) in <top (required)>' /mnt/sdb1/ruby/trunk/spec/rubyspec/core/module/attr_writer_spec.rb:4:in
<top (required)>'
String#% taints result for %s when argument is tainted ERROR
RuntimeError: can't modify frozen Float
/mnt/sdb1/ruby/trunk/spec/rubyspec/core/string/modulo_spec.rb:654:intaint' /mnt/sdb1/ruby/trunk/spec/rubyspec/core/string/modulo_spec.rb:654:in
block (2 levels) in <top (required)>'
/mnt/sdb1/ruby/trunk/spec/rubyspec/core/string/modulo_spec.rb:4:in `<top (required)>'
Thanks,
Koichi
--
// SASADA Koichi at atdot dot net
Updated by Eregon (Benoit Daloze) almost 12 years ago
ko1 (Koichi Sasada) wrote:
(2012/10/27 22:20), Eregon (Benoit Daloze) wrote:
It makes sense to me to have them frozen, but I think we would need to freeze all Numeric instances as well for consistency (currently, Fixnum, Rational and Complex can have ivars).
Float is frozen because of introduction of Flonum technique.
I think Fixnum should be also frozen.I'm not sure about complex and rational. I don't think inconsistent
because we can make your own Numeric classes (and we can't force it
frozen). But I have no objection.
I think it's to custom Numeric subclasses authors to chose for them to be frozen or not,
but I think having all core Numeric subclasses instances frozen would make sense.
These are anyway already immutable for their functionality,
it seems weird to allow some kind of changes like singleton methods and ivars.
But you're right, as Rational and Complex are composed of other types,
it seems less important for them to follow Fixnum/Bignum/Float (and BigDecimal?).
However, freezing Fixnum would likely affect more code (notably because their instances are supposed to be unique in MRI).
So theoretically numeric primitives should always be totally immutable, but on the other hand I like having them as full-fledged objects (that is I dislike having an object/type distinction) and freezing them reduces freedom.
class Fixnum; def fib; @fib ||= (self-1).fib + (self-2).fib; end; end; [0,1].each { |i| i.instance_eval { @fib = i } }
=> [0, 1]
42.fib
=> 267914296
This is fun but evil ...
Updated by ko1 (Koichi Sasada) almost 12 years ago
(2012/10/28 6:45), Eregon (Benoit Daloze) wrote:
class Fixnum; def fib; @fib ||= (self-1).fib + (self-2).fib; end; end; [0,1].each { |i| i.instance_eval { @fib = i } }
=> [0, 1]
42.fib
=> 267914296This is fun but evil ...
I completely agree with that. I've forgot such pleasure!!
--
// SASADA Koichi at atdot dot net
Updated by Anonymous almost 12 years ago
Hi,
In message "Re: [ruby-core:48497] Re: [ruby-trunk - Feature #3222] Can bignums have singleton class & methods?"
on Sun, 28 Oct 2012 05:33:45 +0900, SASADA Koichi ko1@atdot.net writes:
|> Accepted.
|
|Should I commit Fixnum and Bignum freezing patch (*1)?
|
|*1: http://www.atdot.net/sp/view/4qjkcm/readonly
|
|I got several errors on test-all caused by Fixnum freezing (no effect on
|Bignum freezing at test-all). I want to make clear that Fixnum can be
|frozen or not (Ruby programmers expect Fixnum is mutable?).
Ah, some programs might expect modifying instance variables of fixnums.
But I think you can ignore such programs for most of the case. Try it.
matz.
Updated by ko1 (Koichi Sasada) almost 12 years ago
(2012/10/28 8:13), Yukihiro Matsumoto wrote:
Ah, some programs might expect modifying instance variables of fixnums.
But I think you can ignore such programs for most of the case. Try it.
Roger, boss.
--
// SASADA Koichi at atdot dot net
Updated by ko1 (Koichi Sasada) almost 12 years ago
- Status changed from Assigned to Closed
- % Done changed from 0 to 100
This issue was solved with changeset r37348.
Marc-Andre, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.
- bignum.c (bignew_1): Bignum instances are frozen.
Feature #3222 - include/ruby/ruby.h: Fixnum instances are also frozen.
- class.c (singleton_class_of): check Bignum before
singleton cheking. - test/ruby/test_bignum.rb: add a test.
- test/ruby/test_fixnum.rb: ditto.
- test/ruby/marshaltestlib.rb, test/ruby/test_eval.rb,
test/ruby/test_object.rb: catch up above changes.