Freezing Variable Assignment

Discussion in 'Ruby' started by Nicholas Van Weerdenburg, Dec 6, 2004.

  1. Hi,

    Is there a feature to freeze variable assignment?

    e.g.
    a="hello"
    a.assignfreeze
    a="goodbye" # ===> generates exception

    Or, in a related vein, a type freeze, so that only similar objects can be added.

    I realize that constants offer assignment freezing to a certain degree.

    The reason I ask, is that I stepped over-top of some framework
    variables today, and it was hard to find out what was going on. Where
    as ruby protects keywords, it would be nice if frameworks or custom
    domain specific languages could do the same.

    Thanks,
    Nick
    Nicholas Van Weerdenburg, Dec 6, 2004
    #1
    1. Advertising

  2. Hi --

    On Mon, 6 Dec 2004, Nicholas Van Weerdenburg wrote:

    > Hi,
    >
    > Is there a feature to freeze variable assignment?
    >
    > e.g.
    > a="hello"
    > a.assignfreeze
    > a="goodbye" # ===> generates exception


    I tend to think this would be a pretty radical reconceptualization of
    how variable identifiers relate to objects, rather than just a
    feature. At the very least it would probably have to be something
    like:

    freeze_identifier:)a)

    as opposed to sending a message to the object referenced by 'a'. (In
    your example you'd be sending the message 'assignfreeze' to the string
    "hello".)

    > Or, in a related vein, a type freeze, so that only similar objects can be added.


    You'd have to define 'type' and/or 'similar object', which isn't
    always easy :)


    David

    --
    David A. Black
    David A. Black, Dec 6, 2004
    #2
    1. Advertising

  3. On Mon, 6 Dec 2004 11:51:55 +0900, Nicholas Van Weerdenburg
    <> wrote:
    > Is there a feature to freeze variable assignment?
    >
    > e.g.
    > a="hello"
    > a.assignfreeze
    > a="goodbye" # ===> generates exception


    No, but you might be able to do something with WeakRef (weakref.rb)
    or some other proxy class and freezing that.

    class Var
    def initialize(value)
    @value = value
    @const = false
    end

    def const!
    @const = true
    end

    def const?
    @const
    end

    attr_accessor :value
    def value=(value)
    raise "Var #{@value.inspect} is constant." if const?
    @value = value
    end

    def class
    @value.class
    end

    def id
    @value.__id__
    end

    def method_missing(sym, *args)
    @value.send(sym, *args)
    end

    def inspect
    @value.inspect
    end
    end

    a = Var.new("hello")
    a.value = "goodbye"
    a.class
    a.const!
    a.value = "yo!"

    > Or, in a related vein, a type freeze, so that only similar objects
    > can be added.


    Define "similar objects". What if I want a variable to be only an
    IO? Should I restrict it to items which inherit from IO? If so, I
    lose the ability to transparently use StringIO or ZLib::GzipWriter
    (or GzipReader) objects. This gets to the heart of why static typing
    is generally a bad idea -- it makes classes less extensible, and
    when you have static typing enforced by the language, there's almost
    always ways to escape out of it with no protection from the compiler
    involved (e.g., pointers).

    > I realize that constants offer assignment freezing to a certain
    > degree.
    >
    > The reason I ask, is that I stepped over-top of some framework
    > variables today, and it was hard to find out what was going on.
    > Where as ruby protects keywords, it would be nice if frameworks or
    > custom domain specific languages could do the same.


    What do you mean, specifically? Did you reopen the classes in the
    framework, or something? If the framework put variables in such a
    way as to make it easy for you to overwrite something that shouldn't
    have been, then I think that it's a bug in the framework, not in
    your code. In some ways, Transaction::Simple is a framework, and I
    have deliberately made it "hard" to step on Transaction::Simple
    variables.

    On Mon, 6 Dec 2004 12:22:35 +0900, itsme213 <>
    wrote:
    > "Nicholas Van Weerdenburg" <> wrote in message
    >> Is there a feature to freeze variable assignment?
    >>
    >> e.g.
    >> a="hello"
    >> a.assignfreeze
    >> a="goodbye" # ===> generates exception

    > I like this, specially if it also covers instance variables. I
    > think Ruby's current freeze is a special case, in which all
    > instance variables of the given object are frozen.


    Um. Not really. Only the direct replacement of those objects is
    frozen.

    a = Struct.new("Effable", :a, :b).new
    a.a = "abcdef"
    a.b = %w(a b c d e f)
    a.freeze
    a.a = "ghijkl" # raises error
    a.a.gsub!(/a/, 'z') # no error
    a.b[0] = 'z' # no error

    Freeze isn't necessarily recursive.

    > It's in the same vein that I think Observable should target a
    > instance variable (an attribute, more generally) of an object,
    > rather than an entire object.


    Why?

    -austin
    --
    Austin Ziegler *
    * Alternate:
    Austin Ziegler, Dec 6, 2004
    #3
  4. Austin Ziegler wrote:
    > On Mon, 6 Dec 2004 11:51:55 +0900, Nicholas Van Weerdenburg
    > <> wrote:

    ...
    >>It's in the same vein that I think Observable should target a
    >>instance variable (an attribute, more generally) of an object,
    >>rather than an entire object.

    >
    >
    > Why?


    It's useful in GUI code, where each control, field, etc. is wired up to
    one or more attrs in the window instance, and other related windows can
    be wired up to those attrs too, to keep their state synchronized. See,
    for instance, foxtails on raa, which uses FXRuby and observable (also on
    raa). That observable lib (which should have been called
    observable-attr) is just what Nicholas described: it makes attrs observable.
    Joel VanderWerf, Dec 6, 2004
    #4
  5. Nicholas Van Weerdenburg

    Eric Hodel Guest

    On 06 Dec 2004, at 07:32, itsme213 wrote:

    >
    > "Austin Ziegler" <> wrote in message
    >> a = Struct.new("Effable", :a, :b).new
    >> a.a = "abcdef"
    >> a.b = %w(a b c d e f)
    >> a.freeze
    >> a.a = "ghijkl" # raises error
    >> a.a.gsub!(/a/, 'z') # no error
    >> a.b[0] = 'z' # no error
    >>
    >> Freeze isn't necessarily recursive.

    >
    > Correct. All instance variables of the object are frozen, not the
    > objects
    > they refer to.


    No, the instance variables are not frozen, the instance 'a' of Effable
    is.

    #a= modifies a, which is disallowed because a is frozen.

    You cannot freeze variables, just objects.

    a = "foo"
    a.freeze
    a = "bar"
    Eric Hodel, Dec 6, 2004
    #5
  6. On Tue, 7 Dec 2004 07:12:37 +0900, itsme213 <> wrote:
    > "Eric Hodel" <> wrote
    >>> Correct. All instance variables of the object are frozen, not
    >>> the objects they refer to.

    >> No, the instance variables are not frozen, the instance 'a' of
    >> Effable is.
    >>
    >> #a= modifies a, which is disallowed because a is frozen.
    >>
    >> You cannot freeze variables, just objects.
    >>
    >> a = "foo"
    >> a.freeze
    >> a = "bar"

    > I respecfully but heartily disagree. Ruby freezes objects by
    > freezing their instance variables. The latter is the fundamental
    > operation.


    You may disagree, but you'd be incorrect.

    irb(main):008:0> class << a
    irb(main):009:1> def matz
    irb(main):010:2> "matz"
    irb(main):011:2> end
    irb(main):012:1> end
    TypeError: can't modify frozen object
    from (irb):9

    (Assuming the same Effable that has been discussed to this point.)

    The object referred to by 'a' is frozen, not the instance variables
    of said object.

    The fundamental operation is *freezing the object*.

    > @a = "foo"
    > self.freeze
    > @a = "bar"
    >
    > Ruby just happens to treat local variables differently. There is
    > no fundamental reason to do so.


    Sure there is, and it's precisely because variables are simply
    labels, but instance variables are part of the state of the object.

    -austin
    --
    Austin Ziegler *
    * Alternate:
    Austin Ziegler, Dec 6, 2004
    #6
  7. On Mon, 6 Dec 2004 14:32:12 +0900, Joel VanderWerf
    <> wrote:
    > Austin Ziegler wrote:
    > > On Mon, 6 Dec 2004 11:51:55 +0900, Nicholas Van Weerdenburg
    > > <> wrote:
    > >>It's in the same vein that I think Observable should target a
    > >>instance variable (an attribute, more generally) of an object,
    > >>rather than an entire object.

    > > Why?

    > It's useful in GUI code, where each control, field, etc. is wired up to
    > one or more attrs in the window instance, and other related windows can
    > be wired up to those attrs too, to keep their state synchronized. See,
    > for instance, foxtails on raa, which uses FXRuby and observable (also on
    > raa). That observable lib (which should have been called
    > observable-attr) is just what Nicholas described: it makes attrs observable.


    That makes sense, and it seems that the observable-attr is the right
    thing for what he needs there.

    -austin
    --
    Austin Ziegler *
    * Alternate:
    Austin Ziegler, Dec 6, 2004
    #7
  8. Nicholas Van Weerdenburg

    Eric Hodel Guest

    On 06 Dec 2004, at 14:12, itsme213 wrote:

    >> You cannot freeze variables, just objects.
    >>
    >> a = "foo"
    >> a.freeze
    >> a = "bar"

    >
    > I respecfully but heartily disagree. Ruby freezes objects by freezing
    > their
    > instance variables. The latter is the fundamental operation.


    variable.c disagrees with you:

    VALUE
    rb_ivar_set(obj, id, val)
    VALUE obj;
    ID id;
    VALUE val;
    {
    if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4)
    rb_raise(rb_eSecurityError, "Insecure: can't modify instance
    variable");
    if (OBJ_FROZEN(obj)) rb_error_frozen("object");

    > a = "foo" # makes the variable a refer to the object "foo"
    >
    > a.freeze # makes the instance variables of the object "foo" frozen.
    >
    > Try this:
    >
    > @a = "foo"
    > self.freeze
    > @a = "bar"


    No, self is frozen, not @a. Your example is no different than the one
    using Effable.

    @a = "foo" # self.instance_variable_set "@a", "foo"
    self.freeze
    @b = "bar" # self.instance_variable_set "@b", "bar", raises because
    self is frozen.
    Eric Hodel, Dec 7, 2004
    #8
  9. Nicholas Van Weerdenburg

    Jim Weirich Guest

    > On 06 Dec 2004, at 14:12, itsme213 wrote:
    > > I respecfully but heartily disagree. Ruby freezes objects by freezing
    > > their instance variables. The latter is the fundamental operation.


    On Monday 06 December 2004 07:47 pm, Eric Hodel wrote:
    > variable.c disagrees with you:


    You guys are talking past each other ...

    Itsme213: "Ruby freezes objects by freezing their instance variables"

    Weirich Translation: When a Ruby object is frozen, the binding of its
    instances variable names to values are made unchangeable (i.e. frozen).

    Eric points to variable.c, which implements the policy annunciated by itsme.
    And David correctly points out that the simple view of only looking at the
    instance variables does not paint the whole picture (e.g. freezing arrays).

    But as far as classes implemented in Ruby (as opposed to classes implemented
    in C), the viewpoint is pretty right on.

    --
    -- Jim Weirich http://onestepback.org
    -----------------------------------------------------------------
    "Beware of bugs in the above code; I have only proved it correct,
    not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)
    Jim Weirich, Dec 7, 2004
    #9
  10. Hi --

    On Tue, 7 Dec 2004, Jim Weirich wrote:

    > > On 06 Dec 2004, at 14:12, itsme213 wrote:
    > > > I respecfully but heartily disagree. Ruby freezes objects by freezing
    > > > their instance variables. The latter is the fundamental operation.

    >
    > On Monday 06 December 2004 07:47 pm, Eric Hodel wrote:
    > > variable.c disagrees with you:

    >
    > You guys are talking past each other ...
    >
    > Itsme213: "Ruby freezes objects by freezing their instance variables"
    >
    > Weirich Translation: When a Ruby object is frozen, the binding of its
    > instances variable names to values are made unchangeable (i.e. frozen).


    David's previous statement on this: "One of the consequences of
    [calling a.freeze] (though not the only consequence) is that a's
    instance variables bindings are frozen." :)

    > Eric points to variable.c, which implements the policy annunciated by itsme.
    > And David correctly points out that the simple view of only looking at the
    > instance variables does not paint the whole picture (e.g. freezing arrays).
    >
    > But as far as classes implemented in Ruby (as opposed to classes implemented
    > in C), the viewpoint is pretty right on.


    But that, in turn, is because Kernel#freeze freezes an object's state,
    and state for non-builtins is generally (always?) a matter of instance
    variables. That's why I disagree with itsme213 that instance
    variables are a good model for how to treat local variables. (Not
    that that matters, really; if it's a good idea to be able to freeze
    local variable bindings [I'm not convinced it is], it doesn't have to
    depend on analogy with Kernel#freeze.)

    One could perhaps reason that a Binding "has" local variables, in
    somewhat the same way that an object "has" instance variables, and
    that there should be some way to freeze those bindings too (i.e., the
    bindings in a Binding). The cases are not exactly parallel, though,
    since a Binding can also have instance variables.... But it might be
    an alternative way to approach it.


    David

    --
    David A. Black
    David A. Black, Dec 7, 2004
    #10
  11. On Tue, 7 Dec 2004 12:07:32 +0900, itsme213 <>
    wrote:
    >> Eric points to variable.c, which implements the policy
    >> annunciated by itsme. And David correctly points out that the
    >> simple view of only looking at the instance variables does not
    >> paint the whole picture (e.g. freezing arrays).

    > I was talking about the pure object model part of Ruby. In such a
    > pure object model, a[1] and a[2] are instance variables (some
    > Smalltalk descriptions calls these 'indexed instance variables' as
    > opposed to 'named instance variables'). How something is optimized
    > in C is a different matter.


    Ruby isn't Smalltalk.

    In a Hash, foo['bar'] and foo['baz'] are not instance variables of
    the Hash. They are indexed items to the Hash, for certain, but they
    aren't instance variables in the least.

    Frankly, I think your view of freezing is one that is not one that
    is useful in considering Ruby at all.

    I don't think that freezing bindings is at all useful, and before I
    could even think of supporting something this drastic, I'd need to
    see use cases that couldn't be worked around in other ways.

    > In any case, consider my postings as a point of view; it is a
    > clean and potentially useful one. The part about local variables
    > was not central to me; I was just looking for a bit more
    > uniformity in treatment of all variable bindings, even temporary
    > (local) ones. It makes things like dynamic binding more uniform to
    > implement.


    I don't see any uniformity in freezing bindings.

    -austin
    --
    Austin Ziegler *
    * Alternate:
    Austin Ziegler, Dec 7, 2004
    #11
  12. On Tue, 7 Dec 2004 13:44:09 +0900, Austin Ziegler <> wrote:
    > On Tue, 7 Dec 2004 12:07:32 +0900, itsme213 <>
    >
    >
    > wrote:
    > >> Eric points to variable.c, which implements the policy
    > >> annunciated by itsme. And David correctly points out that the
    > >> simple view of only looking at the instance variables does not
    > >> paint the whole picture (e.g. freezing arrays).

    > > I was talking about the pure object model part of Ruby. In such a
    > > pure object model, a[1] and a[2] are instance variables (some
    > > Smalltalk descriptions calls these 'indexed instance variables' as
    > > opposed to 'named instance variables'). How something is optimized
    > > in C is a different matter.

    >
    > Ruby isn't Smalltalk.
    >
    > In a Hash, foo['bar'] and foo['baz'] are not instance variables of
    > the Hash. They are indexed items to the Hash, for certain, but they
    > aren't instance variables in the least.
    >
    > Frankly, I think your view of freezing is one that is not one that
    > is useful in considering Ruby at all.
    >
    > I don't think that freezing bindings is at all useful, and before I
    > could even think of supporting something this drastic, I'd need to
    > see use cases that couldn't be worked around in other ways.
    >
    > > In any case, consider my postings as a point of view; it is a
    > > clean and potentially useful one. The part about local variables
    > > was not central to me; I was just looking for a bit more
    > > uniformity in treatment of all variable bindings, even temporary
    > > (local) ones. It makes things like dynamic binding more uniform to
    > > implement.

    >
    > I don't see any uniformity in freezing bindings.
    >
    >
    >
    > -austin
    > --
    > Austin Ziegler *
    > * Alternate:
    >
    >


    I think immutability is usually a good thing from a design point of
    view, so I can see a general need to have more freezing options. When
    trying to extend old, bad Java code, I do some minor refactoring- 1.
    kill singletons, 2. make primary business objects immutable, and 3.
    add good logging (poor man's design-by-contract/testing). This makes
    the code understandable enough that some more aggressive refactoring
    can be done in the absense of a test suite, and well as enable some
    component level testing to be added, since it's now easier to seperate
    some of the concerns in the code (gui for application logic in a swing
    application, for instance). The point being the essential importance
    of immutability and being be able to control it from a contractual
    perspective.

    And is there anyway to may attributes private so that subclasses can't
    see them? IIRC, this is possible feature of Rite. This would remove
    some of the need, since immutability is enforced by invisibility.

    BTW- Is freezing bindings simply a delayed constant? Or is there more to it?

    Also, is there anything such as a deep freeze of an object graph? I'm
    guessing not, since that would something hard to generalize easily (I
    think of all the Java serializatoin performance problems where it
    turned out that the data was pulling the application code along with
    it).

    Thanks,
    Nick
    Nicholas Van Weerdenburg, Dec 7, 2004
    #12
  13. On Tue, 7 Dec 2004 23:52:36 +0900, itsme213 <> wrote:
    > "Austin Ziegler" <> wrote in message
    > > In a Hash, foo['bar'] and foo['baz'] are not instance variables of
    > > the Hash. They are indexed items to the Hash, for certain, but they
    > > aren't instance variables in the least.

    > If there is a standard Ruby term to describe what it is? Is "indexed items
    > to the Hash" part of the Ruby model of what constitutes object state?


    Simply "object state." Alternatively "members of the [Collection]".
    They aren't instance variables, though, since that has a very specific
    and precise meaning in Ruby.

    -austin
    --
    Austin Ziegler *
    * Alternate:
    Austin Ziegler, Dec 7, 2004
    #13
  14. On Wed, 8 Dec 2004 00:40:15 +0900, Nicholas Van Weerdenburg
    <> wrote:
    > On Tue, 7 Dec 2004 13:44:09 +0900, Austin Ziegler
    > <> wrote:
    >> On Tue, 7 Dec 2004 12:07:32 +0900, itsme213
    >> <> wrote:
    >>>> Eric points to variable.c, which implements the policy
    >>>> annunciated by itsme. And David correctly points out that the
    >>>> simple view of only looking at the instance variables does not
    >>>> paint the whole picture (e.g. freezing arrays).
    >>> I was talking about the pure object model part of Ruby. In such
    >>> a pure object model, a[1] and a[2] are instance variables (some
    >>> Smalltalk descriptions calls these 'indexed instance variables'
    >>> as opposed to 'named instance variables'). How something is
    >>> optimized in C is a different matter.

    >> Ruby isn't Smalltalk.


    >> In a Hash, foo['bar'] and foo['baz'] are not instance variables
    >> of the Hash. They are indexed items to the Hash, for certain, but
    >> they aren't instance variables in the least.


    >> Frankly, I think your view of freezing is one that is not one
    >> that is useful in considering Ruby at all.


    >> I don't think that freezing bindings is at all useful, and before
    >> I could even think of supporting something this drastic, I'd need
    >> to see use cases that couldn't be worked around in other ways.


    >>> In any case, consider my postings as a point of view; it is a
    >>> clean and potentially useful one. The part about local variables
    >>> was not central to me; I was just looking for a bit more
    >>> uniformity in treatment of all variable bindings, even temporary
    >>> (local) ones. It makes things like dynamic binding more uniform
    >>> to implement.

    >> I don't see any uniformity in freezing bindings.


    > I think immutability is usually a good thing from a design point
    > of view, so I can see a general need to have more freezing
    > options.


    Why? Convince me, because as someone who has done my share of design
    work, I don't see immmutability as a positive on most things. On
    primary key references, yes (e.g., a customer's identification
    number should never change or be changed in any way), immutability
    is good. But as a general rule? Immutability isn't necessarily what
    you want.

    (As a point of note, in my Ruby, I don't think that I've *ever* used
    #freeze. In the billing design work that I did, none of it depended
    upon immutability of the objects -- the only immutable things in my
    code and design were *constants*.)

    The "need" for immutability is very, erm, mutable and can be worked
    around with various design decisions.

    > When trying to extend old, bad Java code, I do some minor
    > refactoring- 1. kill singletons, 2. make primary business objects
    > immutable, and 3. add good logging (poor man's design-by-contract/
    > testing). This makes the code understandable enough that some more
    > aggressive refactoring can be done in the absense of a test suite,
    > and well as enable some component level testing to be added, since
    > it's now easier to seperate some of the concerns in the code (gui
    > for application logic in a swing application, for instance). The
    > point being the essential importance of immutability and being be
    > able to control it from a contractual perspective.


    You assert the value of immutability, but you haven't actually
    demonstrated the value. I'm really not trying to be difficult here,
    but what sort of immutability to you mean in Java -- and why do you
    then need it in Ruby? I find that most of the time when people say
    that they want particular features in Ruby they do so because
    they're not *thinking* in Ruby, but in other languages that they
    have to deal with on a daily basis to pay the bills. I know I do it,
    from time to time, with C++ now that I'm making my money from that.

    > And is there anyway to may attributes private so that subclasses
    > can't see them? IIRC, this is possible feature of Rite. This would
    > remove some of the need, since immutability is enforced by
    > invisibility.


    Um. What do you mean by "attributes"? If you mean that which is
    generated by attr_accessor, then:

    class A
    attr_accessor :foo
    private :foo, :foo=
    end # => A
    class B < A; end # => nil
    B.new.foo = :bar
    # => NoMethodError: private method `foo=' called for
    # #<B:0x2b52c38>

    If you mean instance variables, no, and that wouldn't work anyway --
    it would simply be a source of errors.

    class A
    attr_accessor :foo
    private_var :mad:foo
    end

    class B < A
    def foo=(x)
    @foo = x
    end
    end

    Logically, this shouldn't cause a problem, because even if @foo in A
    is private, then B should still be able to have it's own @foo.

    Maybe there's a way around this -- and this could be potentially
    very useful -- with something like:

    module A
    def foo=(x)
    @<foo> = x
    end
    end

    If Ruby mangles @<foo> to be something like @__A_foo__, then you can
    refer to @<foo> safely in a module without worrying about bumping
    into instance variables belonging to the class.

    > BTW- Is freezing bindings simply a delayed constant? Or is there
    > more to it?


    I don't know what itsme really wants, because I think that the idea
    of making variable bindings -- instance or otherwise -- frozen is a
    bad idea. Freezing an object freezes that object's state -- which
    includes assignment to instance variables, certainly, but also
    inclues adding singleton methods, modifying the singleton object,
    extending the object, etc.

    > Also, is there anything such as a deep freeze of an object graph?
    > I'm guessing not, since that would something hard to generalize
    > easily (I think of all the Java serializatoin performance problems
    > where it turned out that the data was pulling the application
    > code along with it).


    No, there isn't such built into Ruby. You could write one, but I
    don't think it's a good idea.

    -austin
    --
    Austin Ziegler *
    * Alternate:
    Austin Ziegler, Dec 7, 2004
    #14
  15. On Wed, 8 Dec 2004 01:06:53 +0900, Austin Ziegler <> wrote:
    >
    > > I think immutability is usually a good thing from a design point
    > > of view, so I can see a general need to have more freezing
    > > options.

    >
    > Why? Convince me, because as someone who has done my share of design
    > work, I don't see immmutability as a positive on most things. On
    > primary key references, yes (e.g., a customer's identification
    > number should never change or be changed in any way), immutability
    > is good. But as a general rule? Immutability isn't necessarily what
    > you want.
    >
    > (As a point of note, in my Ruby, I don't think that I've *ever* used
    > #freeze. In the billing design work that I did, none of it depended
    > upon immutability of the objects -- the only immutable things in my
    > code and design were *constants*.)
    >
    > The "need" for immutability is very, erm, mutable and can be worked
    > around with various design decisions.
    >


    I agree- good interface design effectively creates immutable classes
    if desired. But that can be an issue because the object may only
    desire immutability later in its lifecycle, or too certain clients.

    Also, good design is an ideal case. In a large project, things can
    become ugly and to be able to enforce a high-degree of control via
    immutable objects can be beneficial, IMHO. Good design requires good
    contracts to enforce it.

    There are three things that make up an immutable object so far in our
    discussion:
    1. frozen objects
    -this could also be done with good interface design for
    certain cases. other alternatives to freeze would be useful to know-
    wrap/delegate, undeffing, etc.
    2. frozen attributes (assignmentFreeze)
    -mostly appplies to inheritence, so private instance variables
    would help here.
    3. frozen value objects (referred to objects of a certain type)
    -not really discussed yet, but seems important as without it,
    freeze is only slushy.

    And of course the question, why do you need it.

    It's hard to describe the benefits of immutables in a short example,
    but I think it's similar in nature to global variables- with
    mutables, edits can be done in many places, leading to bugs as well as
    maintenance issues.

    That's why I mentioned singletons. They often raise the desire for
    immutables since they facilitate uncontrolled access and program flow-
    if you can't get to something, you can't change it. With singletons,
    there is often too much coupling, which makes the issue of mutability
    more pronounced. It's too easy for isolated pieces of code to break
    with appropriate responsibility and assume too much knowledge of the
    domain object.

    For instance, in an asset manager:
    asset=AssetManager.getAsset("id=1")
    asset.value="10"
    Being embedded in gui code.

    With the singleton, this kind of code can be sprinkled throughout the
    code. Bad design, sure. But this is often an issue where there is
    gui-app logic bindings in different dialogs, tables, etc.

    Of course, a better domain class can help.

    class Asset
    def initialize name, location, value
    @name=name
    @location=location
    @value=value
    end
    attr_reader :name, :location, :value
    end

    This is essentially what I do with Java- creating interfaces that
    present an immutable interface to the domain object. But that doesn't
    work with duck typing. So in Ruby, it needs to be part of the class
    interface, and the problem with that is that I may need to have more
    write access to an object early in it's lifecycle. I suppose wrappers
    or delegates are an option here, and that's not too hard to implement
    in a nice way given Ruby's nature. Or even undefing methods. Any
    suggestions welcome.

    As a side note though, even with freezing, the above business object
    is not immutable...
    a=Asset.new "laptop", "home", 500
    a.location << " is where the heart is" # regardless of a being frozen or not.

    If an object should protect it's invariant nature, then it would be
    nice for ruby to provide some capability for immutable value objects-
    maybe something like:

    value_reader :name, :location, :value # returns defensive copies

    Some on the concept of value objects vs. reference objects:
    http://c2.com/cgi/wiki?ValueObject
    http://c2.com/cgi/wiki?ValueObjectsShouldBeImmutable

    >
    > You assert the value of immutability, but you haven't actually
    > demonstrated the value. I'm really not trying to be difficult here,
    > but what sort of immutability to you mean in Java -- and why do you
    > then need it in Ruby? I find that most of the time when people say
    > that they want particular features in Ruby they do so because
    > they're not *thinking* in Ruby, but in other languages that they
    > have to deal with on a daily basis to pay the bills. I know I do it,
    > from time to time, with C++ now that I'm making my money from that.
    >


    I'm still learning to "think" in Ruby for sure, but the essence of the
    need comes from non-trivial systems without a perfect design.

    Removing singletons and making certain domain objects immutable is
    somewhat like putting aspects of the "Law of Demeter" into place.
    http://c2.com/cgi/wiki?LawOfDemeter

    Another way of thinking about is in terms of object lifecycle- if it
    becomes immutable at some point, there is less to worry about. In a
    large system, I would freeze and object just prior to releasing into
    the "wild"- e.g. outside the boundaries of my subsystem.

    > > And is there anyway to may attributes private so that subclasses
    > > can't see them? IIRC, this is possible feature of Rite. This would
    > > remove some of the need, since immutability is enforced by
    > > invisibility.

    >
    > Um. What do you mean by "attributes"? If you mean that which is
    > generated by attr_accessor, then:
    >
    > class A
    > attr_accessor :foo
    > private :foo, :foo=
    > end # => A
    > class B < A; end # => nil
    > B.new.foo = :bar
    > # => NoMethodError: private method `foo=' called for
    > # #<B:0x2b52c38>
    >


    I meant the case where the instance variable @foo is accessed in side
    the class B.

    > If you mean instance variables, no, and that wouldn't work anyway --
    > it would simply be a source of errors.
    >
    > class A
    > attr_accessor :foo
    > private_var :mad:foo
    > end
    >


    private_var is a concept?

    >
    > class B < A
    > def foo=(x)
    > @foo = x
    > end
    > end
    >
    > Logically, this shouldn't cause a problem, because even if @foo in A
    > is private, then B should still be able to have it's own @foo.
    >
    > Maybe there's a way around this -- and this could be potentially
    > very useful -- with something like:
    >
    > module A
    > def foo=(x)
    > @<foo> = x
    > end
    > end
    >
    > If Ruby mangles @<foo> to be something like @__A_foo__, then you can
    > refer to @<foo> safely in a module without worrying about bumping
    > into instance variables belonging to the class.
    >
    > > BTW- Is freezing bindings simply a delayed constant? Or is there
    > > more to it?

    >
    > I don't know what itsme really wants, because I think that the idea
    > of making variable bindings -- instance or otherwise -- frozen is a
    > bad idea. Freezing an object freezes that object's state -- which
    > includes assignment to instance variables, certainly, but also
    > inclues adding singleton methods, modifying the singleton object,
    > extending the object, etc.
    >


    I think private variables would alleviate much of the need. That would
    allow a better contract for inheritence, and that was largely the
    interest in my first post.

    Other issues requiring freezing probably point to an interface that
    exposes too many internals - e.g. use of attr_accessor or a class that
    has too much responsibility or is simply too big. There is still the
    issue of value objects. Any thoughts on that?

    http://c2.com/cgi/wiki?ValueObject
    http://c2.com/cgi/wiki?ValueObjectsShouldBeImmutable

    > > Also, is there anything such as a deep freeze of an object graph?
    > > I'm guessing not, since that would something hard to generalize
    > > easily (I think of all the Java serializatoin performance problems
    > > where it turned out that the data was pulling the application
    > > code along with it).

    >
    > No, there isn't such built into Ruby. You could write one, but I
    > don't think it's a good idea.
    >


    Agreed- unless needed for a particular case.

    Regards,
    Nick
    Nicholas Van Weerdenburg, Dec 7, 2004
    #15
  16. itsme213 wrote:

    > I was talking about the pure object model part of Ruby. In such a pure
    > object model, a[1] and a[2] are instance variables (some Smalltalk
    > descriptions calls these 'indexed instance variables' as opposed to 'named
    > instance variables'). How something is optimized in C is a different matter.


    Please call this Object state ("as in a[1] and a[2] are part of Object
    state" / "@foo is part of Object state") instead. It's a more general
    term and seems to already be well-established.
    Florian Gross, Dec 7, 2004
    #16
  17. Nicholas Van Weerdenburg wrote:

    > I think immutability is usually a good thing from a design point of
    > view, so I can see a general need to have more freezing options. When
    > trying to extend old, bad Java code, I do some minor refactoring- 1.
    > kill singletons, 2. make primary business objects immutable, and 3.
    > add good logging (poor man's design-by-contract/testing). This makes
    > the code understandable enough that some more aggressive refactoring
    > can be done in the absense of a test suite, and well as enable some
    > component level testing to be added, since it's now easier to seperate
    > some of the concerns in the code (gui for application logic in a swing
    > application, for instance). The point being the essential importance
    > of immutability and being be able to control it from a contractual
    > perspective.
    >
    > And is there anyway to may attributes private so that subclasses can't
    > see them? IIRC, this is possible feature of Rite. This would remove
    > some of the need, since immutability is enforced by invisibility.


    Rite will do non-inherited instance variables via @_foo AFAIK. But I
    think this is only for avoiding name clashes, not for absolute security
    against modification. (Just think about .instance_eval and so on -- Ruby
    doesn't usually forbid you from doing bad things -- instead it tries to
    tell you that the thing is wrong and that you should think twice before
    using it.)

    > Also, is there anything such as a deep freeze of an object graph? I'm
    > guessing not, since that would something hard to generalize easily (I
    > think of all the Java serializatoin performance problems where it
    > turned out that the data was pulling the application code along with
    > it).


    I think this would only make sense when combined with a deep clone. It
    would be nice to have GC's object graph traversal functionality exposed.
    It is a good thing to have something like that available generally.

    matz, are you listening?
    Florian Gross, Dec 7, 2004
    #17
  18. Nicholas Van Weerdenburg wrote:

    > Is there a feature to freeze variable assignment?
    >
    > e.g.
    > a="hello"
    > a.assignfreeze
    > a="goodbye" # ===> generates exception
    >
    > Or, in a related vein, a type freeze, so that only similar objects can be added.


    The proposed Syntax confuses the object a variable is referring to with
    the variable itself. It would likely be assign_freeze :var instead.
    But I don't think this is general enough to include it directly in Ruby.

    Let me suggest an idea for a revised request instead: Request a way of
    specifying a callback for local variable assignment. trace_var already
    can be used for doing that with global variables. It would be a
    generalization to also allow this with local ones. The interface would
    be this:

    trace_var:)string) do |arg|
    raise(TypeError, "Can't assign #{arg.inspect} to variable 'string'," +
    " because it is not a String.") unless arg.is_a?(String)
    end

    Using that you could implement assign_freeze() by yourself. But please
    make sure to think about performance issues. It might be a good idea to
    implement it and benchmark it and send the patch with statistics to
    ruby-core. Note that slowdown that is only caused by *using* the new
    feature (e. g. does not make old code slower) is not much of an issue.

    Sorry if this sounds like a lot of work, but I think that if you do it
    like that it would be a very nice feature that would be generally useful
    to the community without having too much of a downside. It would allow
    for very powerful meta programming.
    Florian Gross, Dec 7, 2004
    #18
  19. On Wed, 8 Dec 2004 04:57:32 +0900, Florian Gross <> wrote:
    > Nicholas Van Weerdenburg wrote:
    >
    > > Is there a feature to freeze variable assignment?
    > >
    > > e.g.
    > > a="hello"
    > > a.assignfreeze
    > > a="goodbye" # ===> generates exception
    > >
    > > Or, in a related vein, a type freeze, so that only similar objects can be added.

    >
    > The proposed Syntax confuses the object a variable is referring to with
    > the variable itself. It would likely be assign_freeze :var instead.


    Yes. My bad.

    > But I don't think this is general enough to include it directly in Ruby.
    >
    > Let me suggest an idea for a revised request instead: Request a way of
    > specifying a callback for local variable assignment. trace_var already
    > can be used for doing that with global variables. It would be a
    > generalization to also allow this with local ones. The interface would
    > be this:
    >
    > trace_var:)string) do |arg|
    > raise(TypeError, "Can't assign #{arg.inspect} to variable 'string'," +
    > " because it is not a String.") unless arg.is_a?(String)
    > end
    >
    > Using that you could implement assign_freeze() by yourself. But please
    > make sure to think about performance issues. It might be a good idea to
    > implement it and benchmark it and send the patch with statistics to
    > ruby-core. Note that slowdown that is only caused by *using* the new
    > feature (e. g. does not make old code slower) is not much of an issue.
    >
    > Sorry if this sounds like a lot of work, but I think that if you do it
    > like that it would be a very nice feature that would be generally useful
    > to the community without having too much of a downside. It would allow
    > for very powerful meta programming.
    >
    >


    Those are good ideas. Maybe over Christmas I can take my ruby up an
    notch and start working with c files.

    Thanks,
    Nick
    Nicholas Van Weerdenburg, Dec 7, 2004
    #19
  20. Hi,

    In message "Re: Freezing Variable Assignment"
    on Wed, 8 Dec 2004 04:47:31 +0900, Florian Gross <> writes:

    |> Also, is there anything such as a deep freeze of an object graph? I'm
    |> guessing not, since that would something hard to generalize easily (I
    |> think of all the Java serializatoin performance problems where it
    |> turned out that the data was pulling the application code along with
    |> it).
    |
    |I think this would only make sense when combined with a deep clone. It
    |would be nice to have GC's object graph traversal functionality exposed.
    |It is a good thing to have something like that available generally.
    |
    |matz, are you listening?

    Yes, I am. I think it's good to have general purpose object graph
    traverser. But I'm not going to expose GC marker, for it's tailored
    for garbage collection.

    matz.
    Yukihiro Matsumoto, Dec 8, 2004
    #20
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. John Kievlan

    ASP.NET freezing

    John Kievlan, Aug 7, 2003, in forum: ASP .Net
    Replies:
    3
    Views:
    1,512
    John Kievlan
    Aug 7, 2003
  2. =?Utf-8?B?U3RldmVuIEs=?=

    IIS / ASP.NET freezing computer

    =?Utf-8?B?U3RldmVuIEs=?=, Mar 13, 2005, in forum: ASP .Net
    Replies:
    6
    Views:
    484
    Alvin Bruney [ASP.NET MVP]
    Mar 22, 2005
  3. =?Utf-8?B?Sm9obiBXYWxrZXI=?=

    Freezing Datagrid Column Headers

    =?Utf-8?B?Sm9obiBXYWxrZXI=?=, Jan 18, 2006, in forum: ASP .Net
    Replies:
    2
    Views:
    2,949
    =?Utf-8?B?Sm9obiBXYWxrZXI=?=
    Jan 18, 2006
  4. =?Utf-8?B?RGFu?=
    Replies:
    7
    Views:
    1,003
  5. Derek Basch
    Replies:
    8
    Views:
    128
    Ben Morrow
    Aug 12, 2006
Loading...

Share This Page