Freezing Variable Assignment

  • Thread starter Nicholas Van Weerdenburg
  • Start date
A

Austin Ziegler

This is the reason why there are design approaches and even
language features meant to support encapsulating such aliasing
within manageable boundaries while still permitting arbitrary
object graph structures within them. Such things might not be in
Ruby, but that does not make them less worth considering.

To me, the issue is simple. If you want to freeze more than the
references you hold, do the following:

# This is a good argument for a "Mappable" or "Hashable" module
# or perhaps a changed each_with_index for Hash so that it does
# |value, key| instead of |[value, key], pseudo-index|.
module DeepFreeze
def freeze
if self.kind_of?(Hash)
self.each { |k, v| self[k.dup.freeze] = v.dup.freeze }
elsif self.respond_to?:)map)
self.map { |el| el.dup.freeze }
end

self.instance_variables.each do |iv|
self.instance_variable_set(iv,
self.instance_variable_get(iv).dup.freeze)
end
end
end

It isn't completely a deep freeze, as it doesn't completely traverse
the object tree, but that could be added.

-austin
 
D

David A. Black

Hi --

Leaving aside freezing local variables, I am curious what you think of
freezing controlled at the level of (the bindings of) individual Ruby
instance variables, rather than strictly for entire objects. So I can say
things like:

class Home; def freeze ... end; end
myHome.freeze # cannot change door or door-knob, but can re-paint door
myHome.door = otherDoor #=> error
myHome.door.knob = otherKnob #=> error
myHome.door.color = otherColor #=> OK

Today's Object#freeze can be implemented using this, I believe (extended to
deal with special cases for arrays, hashes, etc, and with the fact that
"freeze all instance variables, ... " in Ruby might mean prohibit dynamic
addition of new ivars). The converse is not true i.e. instance-variable
level freeze cannot be implemented using today's Object#freeze, and the
myHome example above is impossible to implement.

It's not impossible -- you just have to do it by other means than
Kernel#freeze. You'd want something called attr_freeze, that did
something like:

module AFreezer
class FreezeError < TypeError # or whatever
end

def attr_freeze(*syms)
c = (class << self; self; end)
syms.each do |sym|
c.class_eval do
define_method("#{sym}=") { raise FreezeError }
end
end
end
end

Then you could do:

class Door
include AFreezer
attr_accessor :knob
def freeze
attr_freeze :knob
end
end

and so on. (I have a longer, working example if you want to see it.)

The fact that what you want to do is freezing-related and yet isn't
going to piggyback on Kernel#freeze need not worry you in the
slightest. Just use other techniques to achieve what you want.


David
 
D

David A. Black

It's not impossible -- you just have to do it by other means than
Kernel#freeze. You'd want something called attr_freeze, that did
something like:

Or, to phrase it less imperatively: You might, for example, use
something called attr_freeze.... (That sentence got abandoned in
mid-rewording process :)


David
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top