[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Managing metadata about attribute types

Simon Kitching

11/5/2003 12:38:00 AM

Hi,

I'm porting the Apache Jakarta Commons Digester (written in Java) to
Ruby at the moment. This module processes xml in a rules-based manner.
It is particularly useful for handling complex xml configuration files.

However some of the very nice features of this module depend upon being
able to introspect a class to find what attributes it has, and what
their datatypes are.

Finding attributes on a Ruby class is simple (just look for "attr="
methods). Unfortunately, determining what object types it is valid to
assign to that attribute is not so simple...

I was wondering if there were any other Ruby projects which have faced
this problem and come up with solutions? I would rather steal a solution
than invent one :-)

Example of problem:

Input xml is:
<stock>
<stock-item name="spanner" cost="12.50"/>
<stock-item name="screwdriver" cost="3.80"/>
</stock>

// java
class StockItem {
public void setName(String name) {....}
public void setCost(float cost) {....}
}

# Ruby
class StockItem
attr_accessor :name
attr_accessor :cost
end

In the java version, when the "cost" attribute is encountered in the xml
input, it is seen that the target class has a setCost(float) method, so
the string "12.50" is converted to a float before invoking the setCost
method.

I want to achieve the same effect in the Ruby version. I do *not* want
to effectively invoke this in ruby:
stock_item.cost=('12.50') # string passed


Anyone have any references to "pre-existing art"???

Thanks,

Simon


21 Answers

james@rubyxml.com

11/5/2003 12:47:00 AM

0

Simon Kitching wrote:
> Hi,
>
> I'm porting the Apache Jakarta Commons Digester (written in Java) to
> Ruby at the moment. This module processes xml in a rules-based manner.
> It is particularly useful for handling complex xml configuration files.


Are you familiar with the XMLDigester project listed in the RAA?

http://raa.ruby-lang.org/list.rhtml?name=x...
and
http://www.helenius.dk/ruby...


James Britt



Ryan Pavlik

11/5/2003 1:04:00 AM

0

On Wed, 5 Nov 2003 09:38:16 +0900
Simon Kitching <simon@ecnetwork.co.nz> wrote:

> Hi,

<snip>

> I was wondering if there were any other Ruby projects which have faced
> this problem and come up with solutions? I would rather steal a solution
> than invent one :-)

Yep. I'll take this opportunity to shamelessly plug some modules. I
do this in Mephle. First, I use the StrongTyping module and write new
attr_ functions, so I can do this:

attr_accessor_typed String, :foo, :bar

Now #foo= and #bar= complain if they don't get a String. Even better,
I can use StrongTyping's type querying on foo= and bar= to get what
they take, if I need to.

Next, I use the MetaTags module for actually tagging what attributes
exist:

class_info <<-DOC
!Class: Foo

!attr foo: Foo
!attr bar: Bar: This is an optional description of bar.
DOC
class Foo
:
end

Now I can ask for information about the Foo class and look through the
attributes that way.

It works... I generate UIs from this information... and I'm working on
some tools to eliminate redundancy and required typing.

hth,

--
Ryan Pavlik <rpav@mephle.com>

"Mmm! Power lines and paint chips! My childhood rocks!" - 8BT

Ara.T.Howard

11/5/2003 2:07:00 AM

0

Simon Kitching

11/5/2003 5:17:00 AM

0

Hi Ryan,

Thanks for your reply.

MetaTags (http://raa.ruby-lang.org/list.rhtml?nam...) may be what
I was looking for. I'll try to figure out exactly what it does over the
next few days.

Mephle looks very interesting .. might have to look into it later on.

Regards,

Simon

> Next, I use the MetaTags module for actually tagging what attributes
> exist:
>
> class_info <<-DOC
> !Class: Foo
>
> !attr foo: Foo
> !attr bar: Bar: This is an optional description of bar.
> DOC
> class Foo
> :
> end
>
> Now I can ask for information about the Foo class and look through the
> attributes that way.
>
> It works... I generate UIs from this information... and I'm working on
> some tools to eliminate redundancy and required typing.
>
> hth,


Ryan Pavlik

11/5/2003 9:15:00 AM

0

On Wed, 5 Nov 2003 14:16:53 +0900
Simon Kitching <simon@ecnetwork.co.nz> wrote:

> Hi Ryan,
>
> Thanks for your reply.
>
> MetaTags (http://raa.ruby-lang.org/list.rhtml?nam...) may be what
> I was looking for. I'll try to figure out exactly what it does over the
> next few days.

Hope you find it useful. You may still want to couple it with
strongtyping, as this provides a really convenient way to do what you
want (check desired types), but you can do it with metatags alone.

I've thought about doing this, in fact, for "documenting" builtin
classes and their methods before. You shouldn't have a problem
modifying the existing method_info or class_info tagsets to handle
this.

> Mephle looks very interesting .. might have to look into it later on.

It's another can of worms. I should have an app or two that uses it
coming out soon, though.

ttyl,

--
Ryan Pavlik <rpav@mephle.com>

"Do not question wizards, for they are quick to
turn you into a toad." - 8BT

Robert Klemme

11/5/2003 9:25:00 AM

0


"Simon Kitching" <simon@ecnetwork.co.nz> schrieb im Newsbeitrag
news:1067992395.2514.549.camel@PCSIMON.ecnnz.ecnetwork.co.nz...
> Hi,
>
> I'm porting the Apache Jakarta Commons Digester (written in Java) to
> Ruby at the moment. This module processes xml in a rules-based manner.
> It is particularly useful for handling complex xml configuration files.
>
> However some of the very nice features of this module depend upon being
> able to introspect a class to find what attributes it has, and what
> their datatypes are.
>
> Finding attributes on a Ruby class is simple (just look for "attr="
> methods).

That's not the best way. Better do "obj.instance_variables".

> Unfortunately, determining what object types it is valid to
> assign to that attribute is not so simple...

It's impossible.

> I was wondering if there were any other Ruby projects which have faced
> this problem and come up with solutions? I would rather steal a solution
> than invent one :-)

Then why not postprocess the output of YAML on dumping and convert the XML
to YAML on reading?

Regards

robert

Simon Kitching

11/6/2003 1:17:00 AM

0

What a vigorous discussion I seem to have triggered :-)

It's really nice to see so many people interested in the topic - thanks
to all who replied.

Rather than reply individually to the several emails which raise
interesting points, I'll try to gather all the different bits here.

I really am interested in the points raised, and am definitely still in
the learning phase with Ruby. So all of the statements below should
really be prefaced with "I think", "It seems to me", "Do you think that
... is right?". However that would double the size of this email. Please
assume all below is tentative, and that comments/corrections are
welcome.

And I hope those people who "really wanted to stay out..." don't stay
out and chip in. I'm interested at the very least!

====
Re "xml-config" module, raised by Austin: there are significant
differences between the "xml-config" and "xmldigester" approaches.

Which is "better" will depend on circumstances and developer taste. The
most significant differences are:
(a)
Xml-config first builds a complete representation of the input xml in
memory, then starts extracting data. For large xml files this is not a
good idea. Xmldigester is "event-based", so the input xml does not have
to be completely loaded into memory.
(b)
I *believe* that the xmldigester rules-based approach will take less
client code, and will bind the "parsing" program less tightly to the API
of the objects being built than the xml-config approach.
(c)
If building inter-object relationships that are more complex than simple
parent/child references, the xml-config approach may prove easier. There
are some tricks that can be played with xmldigester (eg a common
"registry" object used to resolve relations), but having the entire xml
document available (DOM-style) can allow things that an event-style
approach cannot.
(d)
The xmldigester event-based approach is likely to be faster.

Of course the best test of all the above opinions is actually to create
the code, then compare the two. Once I have xmldigester knocked into
reasonable shape, I might port the xmldigester examples to xml-config
(and vice-versa) to see if any of the above is true!

Regardless of the results, I think that both approaches have their
place.

====

Regarding whether the target class should be responsible for accepting a
string and doing the conversion...

I think it is definitely *not* the receiving classes' responsibility to
do the conversion.

Here's my original class, with the initial implicit assumptions spelled
out more clearly as comments.

# Ruby
class StockItem
# contract with user: any value assigned to name must
# act like a string
attr_accessor :name

# contract with user: any value assigned to cost must act
# like a float object.
attr_accessor :cost
end

Isn't this a valid API for a class to provide? As far as the author of
StockItem is concerned, cost is a float.

I don't see why the author of StockItem should even consider the
possibility that a string could be assigned to cost; that would violate
the contract of the class, so any program that does so can damn well
take the consequences :-). The StrictTyping module can enforce this, but
perhaps does so over-eagerly, as it doesn't allow "duck-typing" ie
objects which aren't Float objects but do behave like them.

Now I happen to want to configure this object based on some string-typed
information. But that's my problem, not the problem of the author of the
StockItem class. And if I wanted to use ASN.1 format input to initialise
an instance of StockItem, then it is still my responsibility to convert
the ASN.1 representation to an appropriate type before assigning to
cost, not the StockItem class' responsibility to understand ASN.1 format
input.

Ok, with Ruby's "open" classes, I can alias the original cost= method
and insert some wrapper code. But I will have to restore the original
method after parsing is complete, otherwise during the real "running"
part of the program, the StockItem's cost= method won't behave like
other classes expect it to.

Not to mention that writing those "conversion" methods by hand is ugly.

>You're right, they shouldn't. But if your warehouse management
>classes don't do what they can to ensure their data integrity, then
>there's a problem with the classes -- not with the XML library. I'm
>not trying to be difficult here; just pointing out that I think
>you're trying to fix the problem from the wrong end.

The StockItem's contract clearly states that it only accepts Float types
for the cost attribute. It doesn't actually need to enforce its data
integrity - it is the calling code's responsibility to use StockItem
correctly.

> attr_accessor proc { |x| x.to_i }, :item_id

That's some very cool code. I can feel my brain expanding just by
looking at it! However I don't feel it does what I want, because this
code actually changes the API of the target class, breaking all other
code that accesses that same attribute thereafter.

The data conversion clearly has to be done somewhere, but I would like
it to be done separately from the target class so as not to muck around
with its API.

Here's the "conversion" code extracted out into a helper class:

def StockItemHelper
def StockItemHelper.cost=(stock_item, str)
stock_item.cost = str.to_f
end
end

In fact, why not use the Java convention and call it StockItemBeanInfo?

Applying a modified version of your attr_accessor code, this could be
written more succinctly as the following, generating effectively the
same code as shown above:

def StockItemBeanInfo
attr_from_str :name, String
attr_from_str :cost, Float
end

However I can also use something like Ryan's MetaTag syntax to write
this. I'm not sure which syntax is more convenient.

desc = <<-END
!class StockItem
!name String
!cost Float
END

# parse the string and dynamically create a wrapper class
beanInfo = createBeanInfoClass(desc)

# because cost was declared as a Float in the MetaTag string,
# the beanInfo class knows to convert the second (string) param
# to a float.
beanInfo.set_cost(stock_item, '3.50')


As you can see, I'm not interested in "type strictness" at all.
What I need is simply "what type of object should I generate in order to
be able to validly assign to cost without violating the API contract of
the StockItem class"...

Changing the StockItem class contract is one solution, but that screws
up all other code that really depended on the original contract being
valid.


Oh, and what if the target attribute is a "Date" class, and I want to
globally control the way string->date mapping works? If it is
distributed across every class that has a Date attribute that is much
trickier to handle than if I somehow know that classes X, Y and Z have
date attributes and the xmldigester code does the string->date
conversions before the assignment.

====
>From Ryan:


> Using #to_* methods are the ruby equivalent of type casting. The
> point in this case is not to _convert_ types, it's to provide the
> right type in the first place. Instead of giving the attribute a
> string and expecting it to be parsed, we want to create the desired
> type and hand that off.
>
> It has nothing to do with the #attr= function. Strict type checking
> at that point is merely a convenience. It's all about getting the
> input into a useful format without writing n^2 functions (for n
> classes). This is the primary reason I wrote StrongTyping in fact;
> the strict checking has merely helped with debugging a whole lot.
>

Yep, that's exactly how I see it.

However I don't want the "type enforcement at runtime" feature of
StrongTyping, and I want to avoid changing the target class' behaviour
in any significant way. Is it possible to get the "type info" part of
StrongTyping without the "type enforcement"?

====

The thread about namespaces still has me pondering a little.
I'm not sure it's relevant to my issue, though, is it?

I need to *instantiate* an object in order to assign it to an attribute
on a target object. So I do need to know the name of a concrete class to
instantiate. There's no "duck typing" there, is there?

====

Thanks Ryan, Chad, Austin, Richard, James, David, Christoph (phew!)


As said in the intro, all comments/corrections welcome!


Regards,

Simon


Ryan Pavlik

11/6/2003 6:49:00 AM

0

On Thu, 6 Nov 2003 12:45:39 +0900
dblack@wobblini.net wrote:

<snip>
> I believe that's by design; as I understand it, the StrongTyping
> module performs parameter gatekeeping based exclusively on the
> class/module ancestry of an object (the namespaces to which it
> belongs, as Rich and Chad were discussing), not on what the object
> actually can do. This means, as you say, that objects which might fit
> the bill may not get through, if their class/module ancestry is wrong,
> and also that objects which do not fit the bill can get through -- for
> example:
<snip>

This is the fundamental philosophical disagreement, or
miscommunication, or what have you. If an object fits the bill, and
its class/ancestry is wrong, then there is a error in design.
It should not be the case that this happens, or you have found an
error in your code.

I realize not all of Ruby is documented in this manner; that's a
simple matter to change. A few smaller modules would solve this; for
instance, Set, HashedSet, IndexedSet, etc. Array would be an
IndexedSet; modules such as CGI would include HashedSet. Then you
could ask for the simple behavioral pattern you desire, and know that
you have it. You would further be assured that this #[] means what
you want it to.

This isn't really any different than duck typing, except you're just
making sure that it really does quack, it doesn't just have a bill.

--
Ryan Pavlik <rpav@mephle.com>

"Do not question wizards, for they are quick to
turn you into a toad." - 8BT

Ryan Pavlik

11/6/2003 6:51:00 PM

0

On Thu, 6 Nov 2003 21:57:15 +0900
dblack@wobblini.net wrote:

<snip>
> > This is the fundamental philosophical disagreement, or
> > miscommunication, or what have you. If an object fits the bill, and
> > its class/ancestry is wrong, then there is a error in design.
> > It should not be the case that this happens, or you have found an
> > error in your code.
>
> At this point you're waging a battle directly against the design of
> Ruby. Ruby allows you to extend objects at runtime; to decide that
> this is sloppy or wrong or a second-rate programming technique is
> entirely arbitrary.

Not at all. The fact you _can_ do something doesn't mean you must do
it all over the place. The fact you _can_ extend objects has no
bearing on what the fact your class hierarchy documents the behavioral
pattern well, either.

> When you check whether or not an object's response to #is_a? includes
> an element you've specified, that's the one and only thing you're
> checking. It's not as if Ruby somehow pulls up its socks and
> straightens its tie and says "Better stop this dynamic stuff!" when it
> sees a call to #is_a? It doesn't; it remains dynamic, and the
> programming techniques required to ascertain the interface of an
> object do not change. (Besides, its socks and tie were just fine to
> start with :-)

You seem to have the preconception that #is_a? and "this dynamic
stuff" are mutually exclusive in some way. This is not the case. The
fact you're asking #is_a? just means you're asking if at some point it
had a parent that was related to this class.

I see this as both a fundamental problem of blindly using #to_*
methods and a factor that has limited the perception of typing.
When you call #to_f, or #to_s, you get a Float or a String... not a
subclass. (In fact, this is often used to work around having
singleton strings, or not-quite-strings.) Don't confuse this with
actually _having_ a String subclass, which _is_ a String, but (likely)
with some additional behavior.

The primary goal of inheritence is dynamic extension. The ability for
you to add something later to the code and have it fall into the
existing structure.

Consider:

* When writing code, you will never specifically want a type you
do not know about.

* When using the code later, you can provide a specific subclass
unknown to the original code.

* Thus, when type checking, you are not limited in any manner,
because you are asking for what you want (generally), and
getting it (specifically).

Dynamicism doesn't fall out of the picture here at all. (In fact, you
could in theory construct ST expect() statements dynamically, although
it would be odd.)

> > I realize not all of Ruby is documented in this manner; that's a
> > simple matter to change. A few smaller modules would solve this; for
> > instance, Set, HashedSet, IndexedSet, etc. Array would be an
> > IndexedSet; modules such as CGI would include HashedSet. Then you
> > could ask for the simple behavioral pattern you desire, and know that
> > you have it. You would further be assured that this #[] means what
> > you want it to.
>
> I think I must be not getting something here; it sounds like you're
> suggesting that every possible behavior of every future object in
> every Ruby program be anticipated by modules in the core distribution,
> with multi-barreled names to suit the purpose. I'm thinking that
> can't really be what you mean.

You've got it backwards. The core code should not have every possible
pattern; this is silly. It should provide the ones it uses and needs.
Future classes, if they provide an interface that is useful to this
code, they should document it by including the proper pattern.

For example (let def_abstract define a method that raises
SubclassResponsibility if unimplemented):

module Hashable
def_abstract :[], :[]=, :has_key?, :keys, :has_value?, :values
end

def show_hash(h)
expect h, Hashable

:
end

:

class SomeOddClass
include Hashable

def [](k);
:
end

:
end

Now the code knows that SomeOddClass is, in fact, Hashable. If you
fail to implement one of the functions necessary, it will complain.
This is only one example; you could make things a bit finer-grained.
Perhaps have a HashAccessed that defines #[] and #[]=, and a subclass
that defines the rest. I am not sure that level of granularity is
useful, but it is possible.

> Also, remember that you're never 100% assured that #[] or any other
> method means what you want it to. It's ducks all the way down :-)
> (http://www.the-funneled-web.com/h...) Every method call
> operates under the same conditions as every other. You can light a
> candle, dance a jig, call #is_a? twenty times... but in the end,
> obj#[] is whatever obj#[] is. You can't change Ruby for a few
> nanoseconds at a time through sheer willpower.

This is only correct when blindly assuming that if #[] exists, it must
act like you want. Having the class/module tie gives you a semantic
that further assures you it _does_ act like you want.

This can, of course, be broken. Many things can be broken in ruby
though, but it is not desirable to do so.

> Hence the quest to harness the dynamism, rather than wishfully think
> that it comes and goes.

There is no lack of dynamicism here. Nor does type checking make the
ability to extend classes on the fly go away or become less useful.
I rely heavily on the strongtyping module in Mephle; I also do some
modification to many base classes. Just because something is a
singleton, does not mean it's also not of the original class.

<snip more type-checking-is-static-typing misconceptions>

--
Ryan Pavlik <rpav@mephle.com>

"I have my rights. I want a fortitude check." - 8BT

John W. Long

11/8/2003 12:45:00 AM

0

Ryan,

> You've got it backwards. The core code should not have every possible
> pattern; this is silly. It should provide the ones it uses and needs.
> Future classes, if they provide an interface that is useful to this
> code, they should document it by including the proper pattern.
>
> For example (let def_abstract define a method that raises
> SubclassResponsibility if unimplemented):
>
> module Hashable
> def_abstract :[], :[]=, :has_key?, :keys, :has_value?, :values
> end
>
> def show_hash(h)
> expect h, Hashable
>
> :
> end
>
> :
>
> class SomeOddClass
> include Hashable
>
> def [](k);
> :
> end
>
> :
> end

An intriguing argument. By far the best that I have heard for Strong Typing.

I do wonder: what is really gained by Strong Typing? Are better error
messages the only advantage? An experienced ruby programmer will see a
method-not-defined error message and know that it means the wrong object was
probably passed in to his method. This kind of error message certainly
throws beginning Ruby programmers for a loop, but is it really a weakness of
the language?

If Strong Typing is an advantage how does it help experienced Ruby
programmers? Do you find that it saves a significant amount of time? Does it
help you catch errors you normally would not have known existed? Does it
encourage the right programming habits? If it can be demonstrated that it
does these things, perhaps it should be incorporated into the language.

I like the clean syntax, but I can't help feeling like I'm looking at code
someone with a strong background in statically typed languages would write.
How can you prevent someone from using Strong Typing in the wrong way? Is
there a way to accomplish this through a different implementation/syntax?

All Respect.
___________________
John Long
www.wiseheartdesign.com


----- Original Message -----
From: "Ryan Pavlik" <rpav@mephle.com>
To: "ruby-talk ML" <ruby-talk@ruby-lang.org>
Sent: Thursday, November 06, 2003 12:50 PM
Subject: Re: Managing metadata about attribute types


> On Thu, 6 Nov 2003 21:57:15 +0900
> dblack@wobblini.net wrote:
>
> <snip>
> > > This is the fundamental philosophical disagreement, or
> > > miscommunication, or what have you. If an object fits the bill, and
> > > its class/ancestry is wrong, then there is a error in design.
> > > It should not be the case that this happens, or you have found an
> > > error in your code.
> >
> > At this point you're waging a battle directly against the design of
> > Ruby. Ruby allows you to extend objects at runtime; to decide that
> > this is sloppy or wrong or a second-rate programming technique is
> > entirely arbitrary.
>
> Not at all. The fact you _can_ do something doesn't mean you must do
> it all over the place. The fact you _can_ extend objects has no
> bearing on what the fact your class hierarchy documents the behavioral
> pattern well, either.
>
> > When you check whether or not an object's response to #is_a? includes
> > an element you've specified, that's the one and only thing you're
> > checking. It's not as if Ruby somehow pulls up its socks and
> > straightens its tie and says "Better stop this dynamic stuff!" when it
> > sees a call to #is_a? It doesn't; it remains dynamic, and the
> > programming techniques required to ascertain the interface of an
> > object do not change. (Besides, its socks and tie were just fine to
> > start with :-)
>
> You seem to have the preconception that #is_a? and "this dynamic
> stuff" are mutually exclusive in some way. This is not the case. The
> fact you're asking #is_a? just means you're asking if at some point it
> had a parent that was related to this class.
>
> I see this as both a fundamental problem of blindly using #to_*
> methods and a factor that has limited the perception of typing.
> When you call #to_f, or #to_s, you get a Float or a String... not a
> subclass. (In fact, this is often used to work around having
> singleton strings, or not-quite-strings.) Don't confuse this with
> actually _having_ a String subclass, which _is_ a String, but (likely)
> with some additional behavior.
>
> The primary goal of inheritence is dynamic extension. The ability for
> you to add something later to the code and have it fall into the
> existing structure.
>
> Consider:
>
> * When writing code, you will never specifically want a type you
> do not know about.
>
> * When using the code later, you can provide a specific subclass
> unknown to the original code.
>
> * Thus, when type checking, you are not limited in any manner,
> because you are asking for what you want (generally), and
> getting it (specifically).
>
> Dynamicism doesn't fall out of the picture here at all. (In fact, you
> could in theory construct ST expect() statements dynamically, although
> it would be odd.)
>
> > > I realize not all of Ruby is documented in this manner; that's a
> > > simple matter to change. A few smaller modules would solve this; for
> > > instance, Set, HashedSet, IndexedSet, etc. Array would be an
> > > IndexedSet; modules such as CGI would include HashedSet. Then you
> > > could ask for the simple behavioral pattern you desire, and know that
> > > you have it. You would further be assured that this #[] means what
> > > you want it to.
> >
> > I think I must be not getting something here; it sounds like you're
> > suggesting that every possible behavior of every future object in
> > every Ruby program be anticipated by modules in the core distribution,
> > with multi-barreled names to suit the purpose. I'm thinking that
> > can't really be what you mean.
>
> You've got it backwards. The core code should not have every possible
> pattern; this is silly. It should provide the ones it uses and needs.
> Future classes, if they provide an interface that is useful to this
> code, they should document it by including the proper pattern.
>
> For example (let def_abstract define a method that raises
> SubclassResponsibility if unimplemented):
>
> module Hashable
> def_abstract :[], :[]=, :has_key?, :keys, :has_value?, :values
> end
>
> def show_hash(h)
> expect h, Hashable
>
> :
> end
>
> :
>
> class SomeOddClass
> include Hashable
>
> def [](k);
> :
> end
>
> :
> end
>
> Now the code knows that SomeOddClass is, in fact, Hashable. If you
> fail to implement one of the functions necessary, it will complain.
> This is only one example; you could make things a bit finer-grained.
> Perhaps have a HashAccessed that defines #[] and #[]=, and a subclass
> that defines the rest. I am not sure that level of granularity is
> useful, but it is possible.
>
> > Also, remember that you're never 100% assured that #[] or any other
> > method means what you want it to. It's ducks all the way down :-)
> > (http://www.the-funneled-web.com/h...) Every method call
> > operates under the same conditions as every other. You can light a
> > candle, dance a jig, call #is_a? twenty times... but in the end,
> > obj#[] is whatever obj#[] is. You can't change Ruby for a few
> > nanoseconds at a time through sheer willpower.
>
> This is only correct when blindly assuming that if #[] exists, it must
> act like you want. Having the class/module tie gives you a semantic
> that further assures you it _does_ act like you want.
>
> This can, of course, be broken. Many things can be broken in ruby
> though, but it is not desirable to do so.
>
> > Hence the quest to harness the dynamism, rather than wishfully think
> > that it comes and goes.
>
> There is no lack of dynamicism here. Nor does type checking make the
> ability to extend classes on the fly go away or become less useful.
> I rely heavily on the strongtyping module in Mephle; I also do some
> modification to many base classes. Just because something is a
> singleton, does not mean it's also not of the original class.
>
> <snip more type-checking-is-static-typing misconceptions>
>
> --
> Ryan Pavlik <rpav@mephle.com>
>
> "I have my rights. I want a fortitude check." - 8BT
>
>
>
>