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.dupThe 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