Feature #3222

Can bignums have singleton class & methods?

Added by Marc-Andre Lafortune almost 4 years ago. Updated over 1 year ago.

[ruby-core:29891]
Status:Closed
Priority:Normal
Assignee:Koichi Sasada
Category:core
Target version:2.0.0

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.definesingletonmethod(: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


Related issues

Related to ruby-trunk - Bug #601: an instance of Bignum can have singleton methods Closed 09/25/2008
Related to ruby-trunk - Feature #6936: Forbid singleton class and instance variabls for float Closed 08/27/2012

Associated revisions

Revision 37348
Added by Koichi Sasada over 1 year ago

  • bignum.c (bignew_1): Bignum instances are frozen. Feature #3222
  • include/ruby/ruby.h: Fixnum instances are also frozen.
  • class.c (singletonclassof): 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/testeval.rb, test/ruby/testobject.rb: catch up above changes.

History

#1 Updated by Shyouhei Urabe almost 4 years ago

=begin
Seems like a bug to me.
=end

#2 Updated by Yusuke Endoh almost 4 years ago

  • Assignee set to 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
singletonmethodadded first:

x = (1 << 64)
def x.singletonmethodadded(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.
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

#3 Updated by Shyouhei Urabe over 3 years ago

  • Status changed from Open to Assigned

=begin

=end

#4 Updated by Koichi Sasada over 1 year 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-trunk - Feature #6936][Assigned] Forbid singleton class and instance variabls for float

(how to add related ticket into redmine system?)

#5 Updated by Benoit Daloze over 1 year 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).

#6 Updated by Koichi Sasada over 1 year 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

#7 Updated by Yukihiro Matsumoto over 1 year ago

  • Assignee changed from Yukihiro Matsumoto to Koichi Sasada

Accepted.

Matz.

#8 Updated by Koichi Sasada over 1 year 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#testinstanceevalblockbasic = 0.00 s
1) Error:
testinstanceevalblockbasic(TestEval):
RuntimeError: can't modify frozen Fixnum
/mnt/sdb1/ruby/trunk/test/ruby/testeval.rb:133:in instance_variable_set'
/mnt/sdb1/ruby/trunk/test/ruby/test_eval.rb:133:in
block in forall
TYPE'
/mnt/sdb1/ruby/trunk/test/ruby/testeval.rb:132:in each'
/mnt/sdb1/ruby/trunk/test/ruby/test_eval.rb:132:in
forall
TYPE'
/mnt/sdb1/ruby/trunk/test/ruby/testeval.rb:191:in `testinstanceevalblock_basic'

[ 3398/11368] TestEval#testinstanceevalstringbasic = 0.00 s
2) Error:
testinstanceevalstringbasic(TestEval):
RuntimeError: can't modify frozen Fixnum
/mnt/sdb1/ruby/trunk/test/ruby/testeval.rb:133:in instance_variable_set'
/mnt/sdb1/ruby/trunk/test/ruby/test_eval.rb:133:in
block in forall
TYPE'
/mnt/sdb1/ruby/trunk/test/ruby/testeval.rb:132:in each'
/mnt/sdb1/ruby/trunk/test/ruby/test_eval.rb:132:in
forall
TYPE'
/mnt/sdb1/ruby/trunk/test/ruby/testeval.rb:163:in `testinstanceevalstring_basic'

[ 6110/11368] TestMarshal#testfixnumivar = 0.00 s
3) Error:
testfixnumivar(TestMarshal):
RuntimeError: can't modify frozen Fixnum
/mnt/sdb1/ruby/trunk/test/ruby/marshaltestlib.rb:186:in remove_instance_variable'
/mnt/sdb1/ruby/trunk/test/ruby/marshaltestlib.rb:186:in
block in testfixnumivar'
/mnt/sdb1/ruby/trunk/test/ruby/marshaltestlib.rb:186:in instance_eval'
/mnt/sdb1/ruby/trunk/test/ruby/marshaltestlib.rb:186:in
ensure in testfixnumivar'
/mnt/sdb1/ruby/trunk/test/ruby/marshaltestlib.rb:186:in `testfixnumivar'

[ 6111/11368] TestMarshal#testfixnumivarself = 0.00 s
4) Error:
test
fixnumivarself(TestMarshal):
RuntimeError: can't modify frozen Fixnum
/mnt/sdb1/ruby/trunk/test/ruby/marshaltestlib.rb:194:in remove_instance_variable'
/mnt/sdb1/ruby/trunk/test/ruby/marshaltestlib.rb:194:in
block in testfixnumivarself'
/mnt/sdb1/ruby/trunk/test/ruby/marshaltestlib.rb:194:in instance_eval'
/mnt/sdb1/ruby/trunk/test/ruby/marshaltestlib.rb:194:in
ensure in test
fixnumivarself'
/mnt/sdb1/ruby/trunk/test/ruby/marshaltestlib.rb:194:in `testfixnumivar_self'

[ 6695/11368] TestObject#testfreezeimmediate = 0.00 s
5) Failure:
testfreezeimmediate(TestObject) [/mnt/sdb1/ruby/trunk/test/ruby/test_object.rb:65]:
expected but was
.

The following log is from rubyspec.

1)
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/singletonclassspec.rb:79:in singleton_class'
/mnt/sdb1/ruby/trunk/spec/rubyspec/language/singleton_class_spec.rb:79:in
block (3 levels) in '
/mnt/sdb1/ruby/trunk/spec/rubyspec/language/singletonclassspec.rb:4:in `'

2)
Kernel#instancevariables 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
variablesspec.rb:23:in instance_variable_set'
/mnt/sdb1/ruby/trunk/spec/rubyspec/core/kernel/instance_variables_spec.rb:23:in
block (4 levels) in '
/mnt/sdb1/ruby/trunk/spec/rubyspec/core/kernel/instance
variables_spec.rb:4:in `'

3)
Kernel#taint has no effect on immediate values ERROR
RuntimeError: can't modify frozen Fixnum
/mnt/sdb1/ruby/trunk/spec/rubyspec/core/kernel/taintspec.rb:37:in taint'
/mnt/sdb1/ruby/trunk/spec/rubyspec/core/kernel/taint_spec.rb:37:in
block (3 levels) in '
/mnt/sdb1/ruby/trunk/spec/rubyspec/core/kernel/taint
spec.rb:36:in each'
/mnt/sdb1/ruby/trunk/spec/rubyspec/core/kernel/taint_spec.rb:36:in
block (2 levels) in '
/mnt/sdb1/ruby/trunk/spec/rubyspec/core/kernel/taint_spec.rb:4:in `'

4)
Kernel#untrusted? has no effect on immediate values ERROR
RuntimeError: can't modify frozen Fixnum
/mnt/sdb1/ruby/trunk/spec/rubyspec/core/kernel/untrustedspec.rb:21:in untrust'
/mnt/sdb1/ruby/trunk/spec/rubyspec/core/kernel/untrusted_spec.rb:21:in
block (3 levels) in '
/mnt/sdb1/ruby/trunk/spec/rubyspec/core/kernel/untrusted
spec.rb:4:in `'

5)
Module#attraccessor allows creating an attraccessor on an immediate class ERROR
RuntimeError: can't modify frozen Fixnum
/mnt/sdb1/ruby/trunk/spec/rubyspec/core/module/attraccessorspec.rb:36:in block (2 levels) in <top (required)>'
/mnt/sdb1/ruby/trunk/spec/rubyspec/core/module/attr_accessor_spec.rb:4:in
'

6)
Module#attrreader allows for adding an attrreader to an immediate ERROR
RuntimeError: can't modify frozen Fixnum
/mnt/sdb1/ruby/trunk/spec/rubyspec/core/module/attrreaderspec.rb:32:in instance_variable_set'
/mnt/sdb1/ruby/trunk/spec/rubyspec/core/module/attr_reader_spec.rb:32:in
block (2 levels) in '
/mnt/sdb1/ruby/trunk/spec/rubyspec/core/module/attrreaderspec.rb:4:in `'

7)
Module#attrwriter allows for adding an attrwriter to an immediate ERROR
RuntimeError: can't modify frozen Fixnum
/mnt/sdb1/ruby/trunk/spec/rubyspec/core/module/attrwriterspec.rb:32:in block (2 levels) in <top (required)>'
/mnt/sdb1/ruby/trunk/spec/rubyspec/core/module/attr_writer_spec.rb:4:in
'

8)
String#% taints result for %s when argument is tainted ERROR
RuntimeError: can't modify frozen Float
/mnt/sdb1/ruby/trunk/spec/rubyspec/core/string/modulospec.rb:654:in taint'
/mnt/sdb1/ruby/trunk/spec/rubyspec/core/string/modulo_spec.rb:654:in
block (2 levels) in '
/mnt/sdb1/ruby/trunk/spec/rubyspec/core/string/modulo
spec.rb:4:in `'

Thanks,
Koichi

--
// SASADA Koichi at atdot dot net

#9 Updated by Benoit Daloze over 1 year 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 ...

#10 Updated by Koichi Sasada over 1 year 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
=> 267914296

This is fun but evil ...

I completely agree with that. I've forgot such pleasure!!

--
// SASADA Koichi at atdot dot net

#11 Updated by Anonymous over 1 year ago

Hi,

In message "Re: 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.

#12 Updated by Koichi Sasada over 1 year 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

#13 Updated by Koichi Sasada over 1 year 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 (singletonclassof): 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/testeval.rb, test/ruby/testobject.rb: catch up above changes.

Also available in: Atom PDF