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