Simon Kitching
11/5/2003 5:07:00 AM
On Wed, 2003-11-05 at 17:09, Chad Fowler wrote:
> On Wed, 5 Nov 2003, 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.
> #
> # 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'm not exactly answering your question here, but I'd like to offer some
> words of caution...
>
> Be careful about relying on what "type" of object you've got (I'll
> avoiding going into detailed discussion of the fact that "type" and
> "class" are not equivalent). An object's class doesn't guarantee much of
> anything in Ruby. Javaisms may not apply:
Yes. I'm not strictly looking for "the type of the target attribute". As
you state, the question "what type *is* the attribute" is something that
is usually not worth asking in Ruby.
What I'm really looking for is "what type should I convert the string
extracted from the xml to before assignment to the attribute". Or, in
other words I want to know the name of one type that can validly be
assigned to the attribute, so I can generate an instance of that type
from the input xml string value.
This is slightly different from "what is the type of the attribute", but
close enough that Ryan's MetaTags "type annotation" approach will
probably work. It can be regarded as a way of giving "type hints". The
StrictTyping module is not, I agree, what I want.
In fact, the original Digester library has a similar problem when the
declared type of an attribute is an abstract type. The Digester library
essentially says "well, in that case you can't use the nice convenient
SetPropertiesRule api. Use the more explicit (and long-winded)
CallMethodRule api instead". Or you can create a BeanInfo class.
Unfortunately Java apps face this "lack of target type info" only
occasionally, while for Ruby it exists for every attribute....
Whatever syntax is used to indicate "what type should the input be
converted to" needs to be clean and concise because it will be used
quite a lot to tell xmldigester about how to map xml to
object-attributes.
> As you can see, any code that that relies on this kind of "type checking"
> in Ruby is naive. Worse than that, the desire to shoe-horn
> Ruby into Java-like "strictness" can blind the user into missing the
> point, and therefore the full benefit, of what Ruby has to offer.
Yep. I can't see how to offer what I want without some type info,
though.
If you look at my original example, how to I know that
item.cost = '3.50'
is wrong (the instance will eventually trigger some error), and
item.cost = '3.50'.to_f
is the right thing to do?
With Java it just happens magically and "does the right thing" (except
in the abstract type case mentioned above). Surely Ruby can't be
inferior :-).
>
> As I said, I haven't actually addressed your problem here. If it were me,
> I would be looking for (or writing) something that generates code based on
> an XML Schema.
One of the xmldigester goals is *not* to require an XML Schema.
There are "code generation" approaches that do this. In many
circumstances they are a good solution
However in many cases they are also a bad solution. The original
Digester fills this ecological niche nicely in Java. I hope xmldigester
will fill the same niche in Ruby. But that depends upon finding a
reasonable solution to this type-of-attribute problem that leaves the
library reasonably easy to use.
And I'm not sure that the XML Schema approach works that well either.
Yes, it can document the "type" of the data "in" the xml. But does that
always match with the datatype you want to pass to an attribute? I'll
think about this a bit, though. However if I do go down this road, I'll
have to change the project name as it will be quite different from the
Apache Digester ;-)
> What you're really looking for is convenience (as opposed
> to "type safety").
Yep. Absolutely.
> You want to be able to add 1 + 1 and not end up with 11.
Or go
item.cost = some_value
and not have an exception thrown later when the class goes to use cost
in some arithmetic operation.
> You could easily accomplish this via some tedious coding or you could
> generate the tedious code. By tedious, I mean things like this:
>
> class Person
> def age=(how_old)
> @age = Integer(how_old)
> end
> end
Yep. Tedious indeed. And as mentioned in my reply to Austin, it is a
goal to instantiate and initialise objects without requiring any changes
to their code. Digester manages this fine.
>
> Ruby being as dynamic as it is, it would be pretty easy to dream up a
> scheme to wrap existing classes with filters that could do this kind of
> conversion for you. And, of course, you could generate the filters.
The problem is : in order to automatically generate the filters, I need
to know what type of object is required for each attribute. Full circle!
That code in the Person class you show above could only be generated
because a human "knew" that Integer was an appropriate type to store
into the age attribute (and String was not). I just want to represent
that info in the code somehow...
> And now, the cold medication sets in....
That may have been more information than I needed to know :-)
>
>
> Good night,
> Chad
>
Good afternoon...
Simon