So you add 1 to a integer object which returns a new integer value (it
never modifies the original integer, it “creates” a new one). This new
integer value is then bound to the name “foo”. The previous foo object,
the frozen one, is no long accessable (through the name “foo”).
···
On Sun, 2003-07-06 at 15:32, Aryeh M. Frierdman wrote:
Lets say I am doing design by contract and want to do a call like this:
test=UnitTest::new
foo=1
test.invariant(foo)
foo+=1 # should produce an error and exit
Local variables are not objects, and you can’t freeze them. They contain a
reference to an object, so you can freeze the object they refer to, but not
the variable itself.
In Ruby, Integers are immutable anyway, so 1.freeze is legal but doesn’t
actually do anything.
Thanks for the answers so far but “none” of them actually do what I want.
What I want to do is declare some instance/var/whatever as being invariant
and any attemt to vary it will result in an error. I am convinced their
has to be some generic way to do this without the caller to the "test"
being “aware” that they are asking for it to be froozen. The int example
I gave was only that an example it could of very well been a String,
MyClass, EvilDictator, etc.
Thanks for the answers so far but “none” of them actually do what I want.
What I want to do is declare some instance/var/whatever as being invariant
Well, you should know what you mean by “whatever”
local variables: cannot be frozen, since they don’t belong to an object
and are not an object themselves. They can always be reassigned to point
to another object. Sorry, that’s a Ruby fact of life.
instance variables: are frozen when the object containing them is frozen
class Foo
attr_accessor :x
end
a = Foo.new
a.x = 99
a.freeze
a.x = 100 # TypeError: can’t modify frozen object
and any attemt to vary it will result in an error. I am convinced their
has to be some generic way to do this without the caller to the “test”
being “aware” that they are asking for it to be froozen. The int example
I gave was only that an example it could of very well been a String,
MyClass, EvilDictator, etc.
Taking String as an example:
foo = “hello”
foo.freeze
foo << “x” # Error: object referenced by foo is frozen
foo = “bye” # Not error: foo now references a completely different object
And it can be done at a distance:
def my_test_function(x)
x.freeze
end
foo = “a”
my_test_function(foo)
foo << “b” # Error: object has been frozen
But like I say, local variable “foo” cannot be frozen. I hope that’s clear
enough…
Brian.
···
On Mon, Jul 07, 2003 at 06:53:20AM +0900, Aryeh M. Frierdman wrote:
Thanks for the answers so far but “none” of them actually do what I
want.
What I want to do is declare some instance/var/whatever as being
invariant
and any attemt to vary it will result in an error. I am convinced their
has to be some generic way to do this without the caller to the “test”
being “aware” that they are asking for it to be froozen. The int
example
I gave was only that an example it could of very well been a String,
MyClass, EvilDictator, etc.
Apparently you want two things:
freeze an instance
make an object reference unchangeable
It’s important to not confuse these two issues. The first is a property
of an instance while the latter is a property of an object reference. In
Ruby there are only references. There is no distinction between pointers,
references and values like one might know from C++. And there’s a subtle
difference between C++ references and Ruby references: C++ references
can’t be changed and always refer to the instance they were initialized
with, Ruby references can be changed. Thus Ruby references do have a
little similarity with C++ pointers - but not too much, since pointer
arithmetic is missing.
The first is achieved by doing obj.freeze as you determined correctly,
while the latter is not possible with local references as Brian pointed
out. The closest you can get is to declare a constant (first letter
uppercase) and then get a warning on reassignment like in:
local variables: cannot be frozen, since they don’t belong to an object
and are not an object themselves. They can always be reassigned to point
to another object. Sorry, that’s a Ruby fact of life.
I wonder why this doesn’t work? I didn’t expect it to, but I’m curious.
irb(main):005:0> b = binding
#Binding:0x401d7e7c
irb(main):006:0> eval “y=1”, b
1
irb(main):007:0> eval “y”, b
1
irb(main):008:0> b.freeze
#Binding:0x401d7e7c
irb(main):009:0> eval “y=2”, b
2
Would it be useful to be able to freeze the current binding? Disastrous?
Inefficient?
Thanks for the answers so far but “none” of them actually do what I
want.
What I want to do is declare some instance/var/whatever as being
invariant
and any attemt to vary it will result in an error. I am convinced their
has to be some generic way to do this without the caller to the “test”
being “aware” that they are asking for it to be froozen. The int
example
I gave was only that an example it could of very well been a String,
MyClass, EvilDictator, etc.
Apparently you want two things:
freeze an instance
make an object reference unchangeable
It’s important to not confuse these two issues. The first is a property
of an instance while the latter is a property of an object reference. In
Ruby there are only references. There is no distinction between pointers,
references and values like one might know from C++. And there’s a subtle
difference between C++ references and Ruby references: C++ references
can’t be changed and always refer to the instance they were initialized
with, Ruby references can be changed. Thus Ruby references do have a
little similarity with C++ pointers - but not too much, since pointer
arithmetic is missing.
The first is achieved by doing obj.freeze as you determined correctly,
while the latter is not possible with local references as Brian pointed
out. The closest you can get is to declare a constant (first letter
uppercase) and then get a warning on reassignment like in:
local variables: cannot be frozen, since they don’t belong to an object
and are not an object themselves. They can always be reassigned to
point to another object. Sorry, that’s a Ruby fact of life.
I wonder why this doesn’t work? I didn’t expect it to, but I’m curious.
irb(main):005:0> b = binding
#Binding:0x401d7e7c
irb(main):006:0> eval “y=1”, b
1
irb(main):007:0> eval “y”, b
1
irb(main):008:0> b.freeze
#Binding:0x401d7e7c
irb(main):009:0> eval “y=2”, b
2
Would it be useful to be able to freeze the current binding? Disastrous?
Inefficient?
Being new to ruby I would not know the exact reasons but I susbect that
at the interpreter level a local is implimented as a ptr into a stack frame
vs. a ptr to the free store thus it would be dangerous to freeze a tempurary
object. On second thought this might not be true since how whould you
handle doing garbage collection on a long running method that “free’s” a
local???