Freezing Variable Assignment

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

···

On Tue, 7 Dec 2004 12:07:32 +0900, itsme213 <itsme213@hotmail.com> wrote:
--
Austin Ziegler * halostatue@gmail.com
               * Alternate: austin@halostatue.ca

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.

"Austin Ziegler" <halostatue@gmail.com> 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? And is
there is a standard Ruby term to describe the object state that includes
  (a) the object state described by "@"-style named instance variables,
  (b) the object state underlying arr[1], arr[2], arr[3]... ,
  (c) the object state underlying hash[:foo], hash[:bar]...
  (d) any other form of object state,
  ... I would like to learn about it. I have used the term "instance
variable" for this, intending something more broad than "@"-prefixed char*s.
Otoh, if having a term to describe such broder object state is not necessary

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

···

On Tue, 7 Dec 2004 13:44:09 +0900, Austin Ziegler <halostatue@gmail.com> wrote:

On Tue, 7 Dec 2004 12:07:32 +0900, itsme213 <itsme213@hotmail.com> > > > 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 * halostatue@gmail.com
               * Alternate: austin@halostatue.ca

"Florian Gross" <flgr@ccan.de> wrote in message
news:31mf3tF3ebu1mU3@individual.net...

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.

Perhaps.

Though it's hard to say "object x has states a, b" when you mean "object x
has instance variables a, b". Or "object x has states 1, 2, 3" when you
mean "object x has indexed variables (indices?) 1, 2, 3".

Object#each_instance_variable ?
Object#each_state ?
Object#each_slot ?

It's not a big deal, but a common term would be nice.

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

···

On Tue, 7 Dec 2004 23:52:36 +0900, itsme213 <itsme213@hotmail.com> wrote:

"Austin Ziegler" <halostatue@gmail.com> 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?

--
Austin Ziegler * halostatue@gmail.com
               * Alternate: austin@halostatue.ca

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 :@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

···

On Wed, 8 Dec 2004 00:40:15 +0900, Nicholas Van Weerdenburg <vanweerd@gmail.com> wrote:

On Tue, 7 Dec 2004 13:44:09 +0900, Austin Ziegler > <halostatue@gmail.com> wrote:

On Tue, 7 Dec 2004 12:07:32 +0900, itsme213 >> <itsme213@hotmail.com> wrote:

--
Austin Ziegler * halostatue@gmail.com
               * Alternate: austin@halostatue.ca

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?

No, it isn't. It is very easy to say that "object x has a state
of instance variables @a and @b" or "object x has a state of indexes
1, 2, and 3". Frankly, I don't think that a common term is useful or
necessary. Array and Hash objects are fundamentals; everything else
uses instance variables.

-austin

···

On Thu, 9 Dec 2004 01:32:33 +0900, itsme213 <itsme213@hotmail.com> wrote:

"Florian Gross" <flgr@ccan.de> wrote in message
news:31mf3tF3ebu1mU3@individual.net...

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.

Perhaps.

Though it's hard to say "object x has states a, b" when you mean
"object x has instance variables a, b". Or "object x has states 1,
2, 3" when you mean "object x has indexed variables (indices?) 1,
2, 3".

--
Austin Ziegler * halostatue@gmail.com
               * Alternate: austin@halostatue.ca

Hi --

"Florian Gross" <flgr@ccan.de> wrote in message
news:31mf3tF3ebu1mU3@individual.net...

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.

Perhaps.

Though it's hard to say "object x has states a, b" when you mean "object x
has instance variables a, b". Or "object x has states 1, 2, 3" when you
mean "object x has indexed variables (indices?) 1, 2, 3".

Object#each_instance_variable ?
Object#each_state ?
Object#each_slot ?

It's not a big deal, but a common term would be nice.

I don't think there is one that really covers it, though. I tend to
agree with Austin that finding such a term is a solution in search of
a problem (I've never found it unclear to refer to instance variables
as instance variables, array elements as array elements, hash
key/value pairs as hash key/value pairs, etc., rather than trying to
tie it all together) -- but also, consider what Ruby objects can do,
and the ways they are known:

    obj = Object.new
    def obj.(x)
      rand(100)
    end

What is obj's state, as reflected in its indices? Let's ask it:

   irb(main):006:0> obj[1]
   => 64
   irb(main):007:0> obj[2]
   => 57
   irb(main):008:0> obj["hi"]
   => 21

One might be tempted to say: well, those aren't "real" indices. But
that's the thing. Ruby is *fundamentally* built on dynamism and
elastic behaviors of this kind. "Real" indices in Ruby (such as array
indices) are what the indices in my example are: calls to a method.
My example is obviously designed as a kind of puzzle -- but real Ruby
objects masquerade as things, assume various behaviors on the fly,
delegate actions to each other, and so forth, all the time.

This is not to say that my object, above, contains 57 no more or less
than the array [57] contains 57. It contains it less -- but the point
is that Ruby is full of ways to make things like that not matter
and/or be very difficult to establish in the first place.

(And does my object contain 57 less than (0..99).to_a does? :slight_smile:

David

···

On Thu, 9 Dec 2004, itsme213 wrote:

--
David A. Black
dblack@wobblini.net

> 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 :@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

···

On Wed, 8 Dec 2004 01:06:53 +0900, Austin Ziegler <halostatue@gmail.com> wrote:

Hi,

···

In message "Re: Freezing Variable Assignment" on Wed, 8 Dec 2004 04:47:31 +0900, Florian Gross <flgr@ccan.de> 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.

"Austin Ziegler" <halostatue@gmail.com>

> Though it's hard to say "object x has states a, b" when you mean
> "object x has instance variables a, b". Or "object x has states 1,
> 2, 3" when you mean "object x has indexed variables (indices?) 1,
> 2, 3".
No, it isn't. It is very easy to say that "object x has a state
of instance variables @a and @b" or "object x has a state of indexes
1, 2, and 3".

To each his own, since "easy" and "hard" are subjective :slight_smile: To me:

"object x has slots @a, @b, 1, 2...5" (assuming "ivars" are unacceptable in
Ruby parlance)
   is better than
"object x has states @a, @b, 1, 2...5"
   which is better, simpler, and more uniform than
"object x has a state of instance variables @a, @b, or a state of indices 1,
2..5"

And I'd prefer (e.g. for generic object graph traversal)
          Object#each_slot or Object#each_generalized_ivar
over Object#each_state
over Object#each_instance_variable, Array#each_index, Hash#each,
#each_key, #each_value
over Object#each_whatever_an_extension_might_do_in_the_future

Frankly, I don't think that a common term is useful or
necessary. Array and Hash objects are fundamentals; everything else
uses instance variables.

String.superclass #=> Object
String.instance_variables #=>

I would find it hard to explain the above using your Hash, Array, and
instance variable. So is there some hidden instance variable ("slot") at
work here? What is special about it? Why is it hidden? Because it is
implemented in C? Like Array and Hash? But we'd then be making
implementation distinctions which I was trying to abstract away.

Most descriptions of an object model choose some term like "slot" or
"instance variable" or something else. I think this would be an improvement
on Ruby's (decent) description of its object model.

All of which is quite far off-topic from variable freezing :slight_smile:

Cheers !

"David A. Black" <dblack@wobblini.net> wrote in message

> It's not a big deal, but a common term would be nice.

I don't think there is one that really covers it, though. I tend to
agree with Austin that finding such a term is a solution in search of
a problem (I've never found it unclear to refer to instance variables
as instance variables, array elements as array elements, hash
key/value pairs as hash key/value pairs, etc., rather than trying to
tie it all together) -- but also, consider what Ruby objects can do,
and the ways they are known:

    obj = Object.new
    def obj.(x)
      rand(100)
    end

What is obj's state, as reflected in its indices? Let's ask it:

   irb(main):006:0> obj[1]
   => 64
   irb(main):007:0> obj[2]
   => 57
   irb(main):008:0> obj["hi"]
   => 21

Ah. Thank you for the example.

One might be tempted to say: well, those aren't "real" indices.

Which is, in a way, what I am about to say. But bear with me ...

You are mixing several quite different and usefully separable concerns:
1. What is the local (stored) state of an object (I've used 'slots' for
this)
2. What other non-local (stored) state can be reached via that local state
(transitive on 'slots')
3. What virtual state can be computed in read-only accessor methods via (2),
constants, etc.
4. What stored state (and hence, virtual state 3) is changed by mutators?
   What if something that looks like a read-accessor actually mutates stored
(local or non-local) state

I've been talking about (1). Freezing an instance variable, were such a
thing defined, would work on (1).

A family of closely related methods like equality (==), hash(), freeze an
_object_, ... would be about (1) and (2), with a need to behave in ways that
are mutually consistent and that are consistent with the relevant parts of
the virtual state visible via (3).

As soon as you have something like ObjectSpace that is accessible
everywhere, (3) essentially becomes the whole object graph.

Your rand() example is about (4).
rand() has to mutate some stored state somewhere (i.e. some variable,
instance, global, class, C-only, ... ). Your obj can reach and modify that
stored state via rand(). I am guessing obj.rand[10] would affect the outcome
of a subsequent obj2.rand[10] i.e. this random number state is cetainly not
local stored state (1) in obj.

So my answer would be: obj has no slots corresponding to [1], [2], ....It
does have some non-local slot (somewhere) that is both read and modified by
obj[i].

Ruby is *fundamentally* built on dynamism and
elastic behaviors of this kind.

I agree. But consider this example:

x = X.new
x.compute #=> 5
x.y.z.mutate 6
x.compute #=> 11
x.freeze
x.y.z.mutate 7 #=> error: can't modify frozen object
# likewise x == x1, x.hash(), someHash, etc.

To even mentally understand what is going on, I (and most others, I suspect)
need some conceptual model of state that covers (1), (2), (3), and (4). At
least a mental model; though one in the code could aid testing. Some uniform
notion of "slot" is helpful for this.

This is not to say that my object, above, contains 57 no more or less
than the array [57] contains 57. It contains it less -- but the point
is that Ruby is full of ways to make things like that not matter
and/or be very difficult to establish in the first place.

I don't know what you mean by 'contains'. In the core model I am talking
about, an object has slots; in each slot is (i.e. the value of a slot is) a
reference to some other object. I think notions such as 'contains' (quite
possibly related to my freeze example above) can be built on top of this
core model.

Your object contains some local slots, none of which refers to the object
57. More relevant, even if some of its local slots did refer to the object
57, that reference is a coincidence, and in no way related to what rand()
does.

Thanks!

[snip]

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.

I'm still not convinced, and I think that the problem that I'm
seeing is that you're assuming that an object's desire for
immutability is a necessary thing. I don't see such. What I'm trying
to draw out from you is a discussion of the design where you feel
that you need this feature to help me understand why this
fundamental change to the language would be a good one (and, by
extension, help others understand that as well). Alternatively, in
such a discussion, we actually figure out what you want to do with
Ruby and how not to modify Ruby so fundamentally by making your
design more "Ruby"-like.

I'm not claiming to be "all that" as a Ruby developer, but I think
that I've managed to get a fair idea of the feel of good Ruby design
over the last two and a half years :slight_smile:

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.

Again, I don't necessarily agree. I think that's an absolute
requirement in Java, but I think that Ruby doesn't really require
that.

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.

I and others pointed out a fundamental problem with #3 and Ruby --
how do you define type? If you're thinking in terms of Java types,
that's definitely the wrong way to think about type in Ruby. An
object's class is not necessarily it's type in Ruby. (See my
discussion at the end of this email about StrictVar.)

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.

Again, I'm not sure that this is a guaranteed situation in Ruby.
Look at Rails -- trying to implement an immutable in a Rails
application would probably break the application. I developed a bug
tracking application in Perl (and will be reimplementing it in Ruby
at some point) and have never had a need for an immutable. In the
C++ and PL/SQL billing and CRM application I worked on a few years
back, I don't recall any immutable objects, or any problems because
we didn't have them.

[snip]

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:

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

Not hard:

  class << Module
    def value_reader(*symbols)
      symbols.each do |sym|
        self.define_method(sym) do ||
          self.instance_variable_get("@{#sym}").dup
        end
      end
    end
  end

Untested air code :slight_smile: You could implement it with
Marshal.load(Marshal.dump(variable-value)) for a deep clone.

I'm not sure that the distinction between value objects and
reference objects is needed -- the distinction isn't present in
Ruby. (Well, it is, but for the most part, it's transparent to you,
the programmer.)

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.

Again, I'm not really sure that this is true for Ruby. I think that
the essence of the need comes from heavyweight Java and EJB designs,
not dynamic languages. As Morpheus said in _The Matrix_, "Free your
mind."

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

I'm willing to engage in a longer discussion on the design you're
seeing for this -- because I think that there are probably other
ways to approach this in a language like Ruby without requiring
changes to the core language that would, IMO, be detrimental.

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.

Why? All I have to do to unfreeze your object is dup it. Why limit
what people who may write on top of your classes can do? Certainly,
don't necessarily trust what they provide back to you without
verification, but I don't see any reason to actually do this.

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.

Right, but Matz has suggested that B should never access @foo
directly, but should try to do so through the foo method. I don't
see a reason to make @foo itself "private" in the sense that Java
and C++ have private variables.

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 :@foo
end

private_var is a concept?

Yes.

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.

I don't think so, actually. I would like to see, as I said, a @<foo>
form (it may be different) so that you have privately decorated
instance variables generated by the Ruby parser so that there's no
collision from modules to classes, but ... that's a minor desire.

In earlier messages, you mentioned a "type freeze" for a variable.
There's no reason you can't do that indirectly:

  class StrictVar
    def initialize(value, &block)
      @value = value
      @cond = block
    end

    def cond=(cond)
      if @cond
        raise ArgumentError
      else
        @cond = cond
      end
    end

    attr_accessor :value
    def value=(val)
      if @cond and @cond.cal(val)
        @value = val
      else
        raise TypeError
      end
    end
  end

That, of course, isn't a complete implementation of the delegate
that you'd want to do for that, but you could do an arbitrary block:

  a = StrictVar.new("a") { |x| x.kind_of?(String) }

Now, the object referred to by StrictVar will only be able to be
Strings.

-austin

···

On Wed, 8 Dec 2004 03:13:07 +0900, Nicholas Van Weerdenburg <vanweerd@gmail.com> wrote:

On Wed, 8 Dec 2004 01:06:53 +0900, Austin Ziegler > <halostatue@gmail.com> wrote:

--
Austin Ziegler * halostatue@gmail.com
               * Alternate: austin@halostatue.ca

Yukihiro Matsumoto wrote:

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

Agreed, the GC already knows how to traverse all the built-in classes (not sure if this is bundled to marking) so maybe that could be factored out. RData classes would still need to provide a method / callback for this in any case so this is still a change that needs pondering. Guess it can wait. :slight_smile:

Thanks for the quick response.

"Austin Ziegler" <halostatue@gmail.com>

Though it's hard to say "object x has states a, b" when you mean
"object x has instance variables a, b". Or "object x has states
1, 2, 3" when you mean "object x has indexed variables
(indices?) 1, 2, 3".

No, it isn't. It is very easy to say that "object x has a state
of instance variables @a and @b" or "object x has a state of
indexes 1, 2, and 3".

To each his own, since "easy" and "hard" are subjective :slight_smile: To me:

  "object x has slots @a, @b, 1, 2...5" (assuming "ivars" are
  unacceptable in Ruby parlance)
is better than
  "object x has states @a, @b, 1, 2...5"
which is better, simpler, and more uniform than
  "object x has a state of instance variables @a, @b, or a state
  of indices 1, 2..5"

And I'd prefer (e.g. for generic object graph traversal)
Object#each_slot or Object#each_generalized_ivar
over Object#each_state
over Object#each_instance_variable, Array#each_index, Hash#each,
#each_key, #each_value
over Object#each_whatever_an_extension_might_do_in_the_future

Yuck. What you're describing isn't Ruby, and tries to combine things
for some ivory tower intellectual wankery as opposed to the
pragmatism that makes Ruby the language most of us have come to
love.

There is no reason to iterate over an object's instance variables as
a standard feature of the language. It is a conceptual *mistake* to
consider instance variables equivalent to the contents of a Hash or
Array. If you absolutely *must* iterate over instance variables in a
generic object, then use #instance_variables combined with
#instance_variable_[gs]et.

An object has state. Whether that state is comprised of multiple
instance variables, other internal state (e.g., Hash or Array
collections), or both is ultimately irrelevant. If I do the
following:

    require 'transaction/simple'
    a = %w(a b c d e f g)
    a.extend(Transaction::Simple)
    a.start_transaction

The object referred to by 'a' has both internal state (the array
values, e.g., self[0..-1]) and several instance variables added by
Transaction::Simple. What is the state of the object? Both the
internal state and the instance variables.

Frankly, I don't think that a common term is useful or necessary.
Array and Hash objects are fundamentals; everything else uses
instance variables.

String.superclass #=> Object
String.instance_variables #=>

I would find it hard to explain the above using your Hash, Array,
and instance variable. So is there some hidden instance variable
("slot") at work here? What is special about it? Why is it hidden?
Because it is implemented in C? Like Array and Hash? But we'd then
be making implementation distinctions which I was trying to
abstract away.

And I'm telling you that what you're doing is a fruitless exercise
for some ideal of purity that *is not Ruby*. A String has state. It
may *also* have instance variables (see Transaction::Simple) that
contribute to its state. But whether implemented in Ruby, C, or
assembly, it seems highly unlikely that anything will ever be done
to expose the internal state implementation of String, when String
is a fundamental object. What would the instance variable of a
Fixnum be? IMO, that's a silly question -- it is a value.

Most descriptions of an object model choose some term like "slot"
or "instance variable" or something else. I think this would be an
improvement on Ruby's (decent) description of its object model.

And I think that it would be a waste of time, effort, and clarity.
This would do nothing more than muddle Ruby's object model for
people who aren't you.

-austin

···

On Thu, 9 Dec 2004 04:22:30 +0900, itsme213 <itsme213@hotmail.com> wrote:
--
Austin Ziegler * halostatue@gmail.com
               * Alternate: austin@halostatue.ca

Hi --

"David A. Black" <dblack@wobblini.net> wrote in message

It's not a big deal, but a common term would be nice.

I don't think there is one that really covers it, though. I tend to
agree with Austin that finding such a term is a solution in search of
a problem (I've never found it unclear to refer to instance variables
as instance variables, array elements as array elements, hash
key/value pairs as hash key/value pairs, etc., rather than trying to
tie it all together) -- but also, consider what Ruby objects can do,
and the ways they are known:

    obj = Object.new
    def obj.(x)
      rand(100)
    end

What is obj's state, as reflected in its indices? Let's ask it:

   irb(main):006:0> obj[1]
   => 64
   irb(main):007:0> obj[2]
   => 57
   irb(main):008:0> obj["hi"]
   => 21

Ah. Thank you for the example.

One might be tempted to say: well, those aren't "real" indices.

Which is, in a way, what I am about to say. But bear with me ...

You are mixing several quite different and usefully separable concerns:
1. What is the local (stored) state of an object (I've used 'slots' for
this)
2. What other non-local (stored) state can be reached via that local state
(transitive on 'slots')
3. What virtual state can be computed in read-only accessor methods via (2),
constants, etc.
4. What stored state (and hence, virtual state 3) is changed by mutators?
  What if something that looks like a read-accessor actually mutates stored
(local or non-local) state

I've been talking about (1). Freezing an instance variable, were such a
thing defined, would work on (1).

A family of closely related methods like equality (==), hash(), freeze an
_object_, ... would be about (1) and (2), with a need to behave in ways that
are mutually consistent and that are consistent with the relevant parts of
the virtual state visible via (3).

As soon as you have something like ObjectSpace that is accessible
everywhere, (3) essentially becomes the whole object graph.

Your rand() example is about (4).
rand() has to mutate some stored state somewhere (i.e. some variable,
instance, global, class, C-only, ... ). Your obj can reach and modify that
stored state via rand(). I am guessing obj.rand[10] would affect the outcome
of a subsequent obj2.rand[10] i.e. this random number state is cetainly not
local stored state (1) in obj.

I don't see how or where any state is stored. Are you talking about
the behavior of the random number generator, and the fact that *it*
isn't in the same state after calling obj.? If so, I definitely do
not consider that part of the state of obj itself.

Basically I've defined obj. as if it were:

   def obj.give_me_a_random_number
     rand(100)
   end

but using and an argument. So calling obj. is just a wrapper
around rand. An integer is returned, but it isn't saved anywhere.

So my answer would be: obj has no slots corresponding to [1], [2], ....It
does have some non-local slot (somewhere) that is both read and modified by
obj[i].

Ruby is *fundamentally* built on dynamism and
elastic behaviors of this kind.

I agree. But consider this example:

x = X.new
x.compute #=> 5
x.y.z.mutate 6
x.compute #=> 11
x.freeze
x.y.z.mutate 7 #=> error: can't modify frozen object
# likewise x == x1, x.hash(), someHash, etc.

To even mentally understand what is going on, I (and most others, I suspect)
need some conceptual model of state that covers (1), (2), (3), and (4). At
least a mental model; though one in the code could aid testing. Some uniform
notion of "slot" is helpful for this.

I'm afraid I don't mentally understand what's going on in your example
:slight_smile: How are #y and #z defined?

This is not to say that my object, above, contains 57 no more or less
than the array [57] contains 57. It contains it less -- but the point
is that Ruby is full of ways to make things like that not matter
and/or be very difficult to establish in the first place.

I don't know what you mean by 'contains'. In the core model I am talking
about, an object has slots; in each slot is (i.e. the value of a slot is) a
reference to some other object. I think notions such as 'contains' (quite
possibly related to my freeze example above) can be built on top of this
core model.

"Contains" in the sense that Array# shows you what's in the
collection, as does Hash#. doesn't always index a collection,
even in built-in classes, and certainly doesn't have to; but my point
was that my object acts as if it were a typical collection, using
to get at elements.

Your object contains some local slots, none of which refers to the object
57. More relevant, even if some of its local slots did refer to the object
57, that reference is a coincidence, and in no way related to what rand()
does.

I'm afraid I'm lost here. My object has neither instance variables
nor stored objects of any kind. Aren't those what you mean by slots?
I'm still not convinced that the conventional terms for these things
stand in need of replacement by a single term -- I prefer that they
not be, in fact -- but I am nonetheless curious exactly what you mean
about this case :slight_smile:

David

···

On Sat, 11 Dec 2004, itsme213 wrote:

--
David A. Black
dblack@wobblini.net

Hi Austin,

Thanks for the inputs and code samples. They are very helpful.

I can see your points regarding the Ruby way of doing things. To go
against that might make the language more awkward. And if something
can be code fairly easily, that may weigh against making it a lanuage
feature. Though on the otherhand, over-extending the core language
makes the code more alien to new users.

To my point of view, providing designs that require language support
for contract and interface management is rather impossible- they are
by definition larger systems polluted by design and coding
compromises. Any example I provide will just look trivial and not
advance the discussion. But maybe you can explain how the ruby-way
works for some of the issues below, or why there are not an issue.

One thing I mentioned was "Good design requires good contracts to
enforce it", and you agreed for Java, but not for Ruby. This is hard
for me to understand, based on my assumption that helping control
coupling and cohesion are inportant in any language.

I can accept duck-typing versus static-typing, in general. The usual
perspectives are type-saftey isn't really important, the polymorphic
benefit of duck typing, and the fact that there is no proven
disadvantage.

But, the larger a system, the more important "contracts" or usage and
interaction generally become. To this point, how do you ensure low
coupling in large Ruby systems?

For me this is both encapsulation and interface control. And this
doesn't necessarily mean typing. Interfaces are not necessarily types-
they are allowed messages. So I don't think this is about duck typing.
It's about interface management, and thus coupling-management. Duck
typing actually helps to a certain degree, but an over-exposed public
interface (even if only implied by the responds_to? capability) is
still problematic.

Immutability also speaks to this- it's an interface contract that says
"read-only", limiting side effects. Having experienced the beauty of
making objects immutable and watching the exceptions flare was a
epiphany for me in Java development. The forced restructuring of the
code was excellent- reduced coupling and increased cohesion. So, as a
design pressure, it was very positive. Of course, a good design would
have avoided the need, but that's like saying well written code
doesn't need tests. It was a useful design pressure that achieved good
goals. I haven't seen anything in Ruby that makes me think that it
might not be a good design pressure in Ruby to enforce low coupling
and high cohesion.

I found this recently, and originally wondered "why another pattern",
but then started to appreciate it's higher level of abstraction.
http://www.c2.com/cgi/wiki?ShieldPattern

"A 'Shield' is a phrase in a program that lets you protect some change
decision behind it. There are all sorts of shields in programming -
that's what programming for robustness is all about, which is why
Shield is a pattern that gets invented over and over in different
forms. DontDistinguishBetweenClassesAndInterfaces is the latest
example. Other examples include subroutines, classes, patterns,
frameworks, and the fact that in Eiffel and Self an attribute access
reads the same as a function call."

Much of the discussion regards not just information hiding, but the
difference between interfaces and encapsulation. To me, it's about
encapsulation/information hiding and protocol hiding/management.
"Shield" is a nice metaphor that encompases both.

Without interfaces, how do you control coupling? Delegates, adapters,
facades, and bridges are all forms of protocol management, so I
suppose that would be a way. But that might get complicated.

Though I suppose that without typed variables, it becomes maybe
awkward to "talk" about
interfaces in code anyhow- it's usually stored with the variable.
Maybe wrappers would be the only solution, since variables are
untyped.

I don't know exactly, but Objective-C protocols may be more analogous
to what I talking about then Java interfaces, since I believe
Objective-C has a SmallTalk-type message dispatch mechanism (aka duck
typing).

This brings to mind a concept I came across recently-
    Lisp is a great hackers language that maybe doesn't serve "pack
programming" so well due to lack of explicitness in certain areas. I
think it may have been from a Paul Graham essay.

On the other hand, maybe the benefit of a dynamic language makes it
easier to recover fro m coupling, making it less important. Or that
the other benefits are so great, that we just need to buckle down with
better design practices. Or that with unit testing, the low-coupling
design pressure is already there so that interface management is not
an issue- if it was, you would have too many problems unit testing. Or
the traditional theory was crap anyway, and didn't really help with
coupling period- design and unit testing are the only really useful
design pressures.

So to sum up- what aspects of Ruby or Ruby programming practice help
enforce low coupling, high cohesion, and non-rigid architectures?

Any inputs appreciated.

Thanks,
Nick

···

On Wed, 8 Dec 2004 13:12:46 +0900, Austin Ziegler <halostatue@gmail.com> wrote:

On Wed, 8 Dec 2004 03:13:07 +0900, Nicholas Van Weerdenburg > <vanweerd@gmail.com> wrote:
> On Wed, 8 Dec 2004 01:06:53 +0900, Austin Ziegler > > <halostatue@gmail.com> wrote:
[snip]
>> 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.

I'm still not convinced, and I think that the problem that I'm
seeing is that you're assuming that an object's desire for
immutability is a necessary thing. I don't see such. What I'm trying
to draw out from you is a discussion of the design where you feel
that you need this feature to help me understand why this
fundamental change to the language would be a good one (and, by
extension, help others understand that as well). Alternatively, in
such a discussion, we actually figure out what you want to do with
Ruby and how not to modify Ruby so fundamentally by making your
design more "Ruby"-like.

I'm not claiming to be "all that" as a Ruby developer, but I think
that I've managed to get a fair idea of the feel of good Ruby design
over the last two and a half years :slight_smile:

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

Again, I don't necessarily agree. I think that's an absolute
requirement in Java, but I think that Ruby doesn't really require
that.

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

I and others pointed out a fundamental problem with #3 and Ruby --
how do you define type? If you're thinking in terms of Java types,
that's definitely the wrong way to think about type in Ruby. An
object's class is not necessarily it's type in Ruby. (See my
discussion at the end of this email about StrictVar.)

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

Again, I'm not sure that this is a guaranteed situation in Ruby.
Look at Rails -- trying to implement an immutable in a Rails
application would probably break the application. I developed a bug
tracking application in Perl (and will be reimplementing it in Ruby
at some point) and have never had a need for an immutable. In the
C++ and PL/SQL billing and CRM application I worked on a few years
back, I don't recall any immutable objects, or any problems because
we didn't have them.

[snip]

> 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:

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

Not hard:

  class << Module
    def value_reader(*symbols)
      symbols.each do |sym|
        self.define_method(sym) do ||
          self.instance_variable_get("@{#sym}").dup
        end
      end
    end
  end

Untested air code :slight_smile: You could implement it with
Marshal.load(Marshal.dump(variable-value)) for a deep clone.

I'm not sure that the distinction between value objects and
reference objects is needed -- the distinction isn't present in
Ruby. (Well, it is, but for the most part, it's transparent to you,
the programmer.)

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

Again, I'm not really sure that this is true for Ruby. I think that
the essence of the need comes from heavyweight Java and EJB designs,
not dynamic languages. As Morpheus said in _The Matrix_, "Free your
mind."

> 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

I'm willing to engage in a longer discussion on the design you're
seeing for this -- because I think that there are probably other
ways to approach this in a language like Ruby without requiring
changes to the core language that would, IMO, be detrimental.

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

Why? All I have to do to unfreeze your object is dup it. Why limit
what people who may write on top of your classes can do? Certainly,
don't necessarily trust what they provide back to you without
verification, but I don't see any reason to actually do this.

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

Right, but Matz has suggested that B should never access @foo
directly, but should try to do so through the foo method. I don't
see a reason to make @foo itself "private" in the sense that Java
and C++ have private variables.

>> 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 :@foo
>> end
> private_var is a concept?

Yes.

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

I don't think so, actually. I would like to see, as I said, a @<foo>
form (it may be different) so that you have privately decorated
instance variables generated by the Ruby parser so that there's no
collision from modules to classes, but ... that's a minor desire.

In earlier messages, you mentioned a "type freeze" for a variable.
There's no reason you can't do that indirectly:

  class StrictVar
    def initialize(value, &block)
      @value = value
      @cond = block
    end

    def cond=(cond)
      if @cond
        raise ArgumentError
      else
        @cond = cond
      end
    end

    attr_accessor :value
    def value=(val)
      if @cond and @cond.cal(val)
        @value = val
      else
        raise TypeError
      end
    end
  end

That, of course, isn't a complete implementation of the delegate
that you'd want to do for that, but you could do an arbitrary block:

  a = StrictVar.new("a") { |x| x.kind_of?(String) }

Now, the object referred to by StrictVar will only be able to be
Strings.

-austin
--
Austin Ziegler * halostatue@gmail.com
               * Alternate: austin@halostatue.ca

What you're describing isn't Ruby, and tries to combine things
for some ivory tower intellectual wankery

Hmmm. I see no need to get abrasive.

There is no reason to iterate over an object's instance variables as
a standard feature of the language.

A quick scan of the Ruby distribution yielded 40 uses of
'instance_variables'. Anything that smacks of reflective programming works
on the underlying object model, which includes access to and iteration over
things like all instance variables, all methods. Of course you know this, so
I may have misunderstood what you meant.

It is a conceptual *mistake* to
consider instance variables equivalent to the contents of a Hash or
Array.

You are welcome to keep this view, and if it ends up being 'the Ruby way'
that's fine too. There is a decent history of work that finds if helpful to
think that all state in a pure object model is held in the slots of objects,
defined by something akin to
    Object # each_slot { | slot_index , slot_value | ... }

This is true at the meta-level, normal object level, and regardless of how
different slots might be implemented and accessed.

An object has state. Whether that state is comprised of multiple
instance variables, other internal state (e.g., Hash or Array
collections), or both is ultimately irrelevant. If I do the
following:

    require 'transaction/simple'
    a = %w(a b c d e f g)
    a.extend(Transaction::Simple)
    a.start_transaction

The object referred to by 'a' has both internal state (the array
values, e.g., self[0..-1]) and several instance variables added by
Transaction::Simple. What is the state of the object? Both the
internal state and the instance variables.

Sure. And if you are comfortable with requiring even further concepts of
'internal state', 'array values', etc. that's fine. I prefer the underlying
object model to say that the state of 'a' is comprised of a bunch of indexed
slots and their values.
    a.each_slot { | slot_index, value | puts slot_index, value }
would give something like
    0 a
    1 b
    2 c
    ....
    6 g
    @a x1
    @b x2
    @c x3

> String.superclass #=> Object
> String.instance_variables #=>

And I'm telling you that what you're doing is a fruitless exercise
for some ideal of purity that *is not Ruby*. A String has state. It
may *also* have instance variables (see Transaction::Simple) that
contribute to its state.
But whether implemented in Ruby, C, or
assembly, it seems highly unlikely that anything will ever be done
to expose the internal state implementation of String, when String
is a fundamental object.

I was talking about the instance variables of String, not _a_ string. So my
question was: if you claim (Ruby's) instance variables, Hash, and Array
serve to explain all object state in Ruby, than please explain how String
knows that its superclass = Object, when String has no instance variables?
(I could ask this of any class X < Object.)

What I outlined requires no new magic here at all, and I'll bet it is the
way most Ruby-ists think of this particular example anyway. Every object has
some predefined *slot* which refers to its class. And this is true
regardless of whether that slot is available as an "@x" instance variable, a
special -99 integer index, a :_my_class hash key, via the Object#superclass
method, or only through C-code.

And I think that it would be a waste of time, effort, and clarity.
This would do nothing more than muddle Ruby's object model for
people who aren't you.

Perhaps, perhaps not. It is hardly intended to dramatically change Ruby,
just to put a simpler and more uniform explanation (and possibly reflective
access methods) around object state.

I suspect this sub-thread is past its useful life :slight_smile:

Thanks!

···

"Austin Ziegler" <halostatue@gmail.com> wrote