A Ruby class is never closed

Is it true that a Ruby class definition is never closed? Even after
using the ‘end’ keyword, the class is available for some dynamic
operations?

Hi,

That’s generally true. You can reopen a class at any time (even the
built-in ones) or modify it through metaprogramming.

However, you can freeze a class to prevent modifications:

class A
def f
puts 1
end
end

reopen class

class A
def g
puts 2
end
end

freeze class

A.freeze

raises an error

class A
def g
puts 2
end
end

This means I can add a method anytime and anywhere in the project? Is
there something similar to a Sealed Class? A class that cannot be
instantiated.

What you do mean? A sealed class like in C# which doesn’t allow
subclasses? Or the singleton pattern where a class can only be
instantiated once?

You can actually do both. For a sealed/final class you can use the
“inherited” hook which gets called every time a new class is derived
from this class. If it raises an error, the class is “sealed” (the
question is if this makes sense).

class A
def self.inherited subclass
raise “class #{subclass} cannot be derived from sealed class
#{self}”
end
end

this doesn’t work

class B < A; end

For the singleton pattern, there’s the singleton module in the standard
library.

On Thu, Aug 16, 2012 at 10:48 AM, Rubyist R.
[email protected]wrote:

How to unfreeze it again?

One way is:

A = A.dup

Although this will warn you:

(irb):23: warning: already initialized constant A

Jan E. писал 16.08.2012 21:59:

For the singleton pattern, there’s the singleton module in the
standard
library.

For the singleton pattern, there are singleton methods in standard
Ruby.

Singleton = Object.new
class << Singleton
def get_var
42
end
end

Singleton.get_var # => 42

On Thu, Aug 16, 2012 at 12:59 PM, Jan E. [email protected] wrote:

def self.inherited subclass

Posted via http://www.ruby-forum.com/.

I can’t think of any reason you would want to do this, but I don’t think
you can ever force this sort of situation. e.g. if I decided that I
wanted to subclass it, I could just do this

class << A
remove_method :inherited
end

I’d look very skeptically at any piece of code which did had such a
hook,
though.

I think he basically wants to have a class that can never ever again be
changed.

As far as I know, this is not possible in ruby.

You can do that, but why would you want to?

Instead of having a clean class definition in a separate file, you’d
need to include this is a kind of “initializing script”. Not very
pretty.

Also the “class” method doesn’t tell you anything useful, and
inheritance isn’t possible.

So I’d rather call that a hack than an actual implementation.

On Aug 27, 2012, at 01:47 , Robert K. [email protected]
wrote:

On Sat, Aug 25, 2012 at 11:36 PM, Marc H. [email protected] wrote:

I think he basically wants to have a class that can never ever again be
changed.

As far as I know, this is not possible in ruby.

In what ways can you still change a frozen class?

class X; freeze; end
X = X.dup
class X; def y; end; end # works fine

In what ways will ruby ever actually stop us from doing something we
want to do?

private isn’t private… frozen never lasts…

The people looking for these assurances have to be educated that it just
isn’t something that is worthwhile trying here.

On Sat, Aug 25, 2012 at 11:36 PM, Marc H. [email protected]
wrote:

I think he basically wants to have a class that can never ever again be
changed.

As far as I know, this is not possible in ruby.

In what ways can you still change a frozen class?

Cheers

robert

On Aug 27, 2012, at 02:25 , Robert K. [email protected]
wrote:

In what ways can you still change a frozen class?

class X; freeze; end
X = X.dup

The constant reassignment will prompt a warning.

Oh come one. You know as well as I do how to avoid the warning. That’s
not the point.

class X; def y; end; end # works fine

You are not actually modifying the original class X. Instead you
create a copy and modify that.

So what? How is that relevant? The thread is about how to make a locked
down system that isn’t trivially thwarted. Guess what… it was
trivially thwarted.

The people looking for these assurances have to be educated that it just isn’t
something that is worthwhile trying here.

Well, at least particular measures help others recognize that it is a
bad idea what they are trying (i.e. doing the dup reassign trick you
present above can be done but will prompt a warning).

Again. Not the point. You’re being (intentionally?) obtuse… It doesn’t
matter how recognizable it is… if the OP wants a locked down system,
ruby is NOT the place to attempt it.

On Mon, Aug 27, 2012 at 10:58 AM, Ryan D. [email protected]
wrote:

class X; freeze; end
X = X.dup

The constant reassignment will prompt a warning.

class X; def y; end; end # works fine

You are not actually modifying the original class X. Instead you
create a copy and modify that.

The people looking for these assurances have to be educated that it just isn’t
something that is worthwhile trying here.

Well, at least particular measures help others recognize that it is a
bad idea what they are trying (i.e. doing the dup reassign trick you
present above can be done but will prompt a warning).

Cheers

robert

On Mon, Aug 27, 2012 at 10:05 PM, Ryan D. [email protected]
wrote:

As far as I know, this is not possible in ruby.

In what ways can you still change a frozen class?

class X; freeze; end
X = X.dup

Please read again: Marc talked about a class which can never be
changed. A frozen class is actually such a class AFAIK. Hence I
asked (Marc) what modifications to a frozen class would be possible (I
could have overlooked something). So far I haven’t seen any.

The constant reassignment will prompt a warning.

Oh come one. You know as well as I do how to avoid the warning. That’s not the
point.

class X; def y; end; end # works fine

You are not actually modifying the original class X. Instead you
create a copy and modify that.

So what? How is that relevant? The thread is about how to make a locked down
system that isn’t trivially thwarted. Guess what… it was trivially thwarted.

Well, you may find the point subtle but the class you assign to X the
second time is not the same as the one which was assigned the first
time. The important bit here is that they do not share identity even
though they can be accessed via the same constant (but at different
times). This has serious implications especially if there are
instances around of class #1: If you ask them for their class and try
to modify it, the program will fail (unless there are some
modifications possible which I have overlooked - see above).

irb(main):001:0> class X;def f;1 end end
=> nil
irb(main):002:0> o = X.new
=> #<X:0x2027d434>
irb(main):003:0> o.f
=> 1
irb(main):004:0> X.freeze
=> X
irb(main):005:0> X = X.dup
(irb):5: warning: already initialized constant X
=> X
irb(main):006:0> class X; def f;2 end end
=> nil
irb(main):007:0> X.new.f
=> 2
irb(main):008:0> o.f
=> 1
irb(main):009:0> o.class.class_eval { def f; 3 end }
RuntimeError: can’t modify frozen Class
from (irb):9:in block in irb_binding' from (irb):9:in class_eval’
from (irb):9
from /usr/local/bin/irb19:12:in `’
irb(main):010:0> o.f
=> 1
irb(main):011:0> o.class
=> X
irb(main):012:0> o.class.equal? X
=> false

The people looking for these assurances have to be educated that it just isn’t
something that is worthwhile trying here.

Well, at least particular measures help others recognize that it is a
bad idea what they are trying (i.e. doing the dup reassign trick you
present above can be done but will prompt a warning).

Again. Not the point. You’re being (intentionally?) obtuse… It doesn’t matter
how recognizable it is…

Please spare your ad hominems.

if the OP wants a locked down system, ruby is NOT the place to attempt it.

Note, that the message which started this thread read:

Is it true that a Ruby class definition is never closed? Even after
using the ‘end’ keyword, the class is available for some dynamic
operations?

This is not about a “locked down system” but the question whether Ruby
classes can always and under all circumstances be changed. Freezing
is a way to prevent such change. So, yes, as long as a class is not
frozen it can be changed almost at will (super class will never
change). But once it’s frozen no modifications are possible that I am
aware of.

Cheers

robert

On Aug 27, 2012, at 14:03 , Robert K. [email protected]
wrote:

Well, you may find the point subtle but the class you assign to X the
second time is not the same as the one which was assigned the first
time. The important bit here is that they do not share identity even
though they can be accessed via the same constant (but at different
times). This has serious implications especially if there are
instances around of class #1: If you ask them for their class and try
to modify it, the program will fail (unless there are some
modifications possible which I have overlooked - see above).

gem install change_class

o.class = SomeOtherClass

done

A really simple way to ensure a class doesn’t get modified:

class Foo
def Foo.method_added(name)
raise “This class is closed for modification”
end
end

class Foo
def testing
end
end

On 28 August 2012 14:18, Josh R. [email protected] wrote:

end
end

Almost.

class Foo
def Foo.method_added(name)
raise “This class is closed for modification”
end
end

class Foo
class << self
undef method_added
def method_added m
end
end
def testing
end
end


Matthew K., B.Sc (CompSci) (Hons)
http://matthew.kerwin.net.au/
ABN: 59-013-727-651

“You’ll never find a programming language that frees
you from the burden of clarifying your ideas.” - xkcd