[RCR] array or with non-array

Sometimes wish that [3, 5, 13] | [8] can be written as [3, 5, 13] | 8
that ary |= 42 would be possible.

chris2 pointed out that it would be inconsistent with [1,2,3] + 4.
maybe let + append 4 to the array?

ary = [1, 3, 4]
#=> [1, 3, 4]

ary |= 2
#=> [1, 2, 3, 4]

This is another bad idea..

···

--
Simon Strandgaard

Hi,

Sometimes wish that [3, 5, 13] | [8] can be written as [3, 5, 13] | 8
that ary |= 42 would be possible.

chris2 pointed out that it would be inconsistent with [1,2,3] + 4.
maybe let + append 4 to the array?

Too much conversion sometimes makes troubles, or hides troubles, for
example, Ruby used to convert string and numbers more eagerly, but I
stopped that to get a chance to detect human errors.

But I'm not sure this conversion is harmless and useful, or not. Let
us try for a while. Here's a patch to implement what you want. I
will merge it to the HEAD, to see how it goes.

              matz.

diff -p -u -1 -r1.173 array.c
--- array.c 5 Jul 2005 14:23:22 -0000 1.173
+++ array.c 2 Aug 2005 22:01:43 -0000
@@ -304,2 +304,13 @@ to_ary(ary)
static VALUE
+make_ary(ary)
+ VALUE ary;
+{
+ VALUE tmp = rb_check_array_type(ary);
+ if (NIL_P(tmp)) {
+ return rb_ary_new3(1, ary);
+ }
+ return tmp;
+}

···

In message "Re: [RCR] array or with non-array" on Wed, 3 Aug 2005 06:31:28 +0900, Simon Strandgaard <neoneye@gmail.com> writes:
+
+static VALUE
to_a(ary)
@@ -2346,6 +2357,12 @@ rb_ary_plus(x, y)
{
- VALUE z;
+ VALUE tmp, z;
     long len;

- y = to_ary(y);
+ tmp = rb_check_array_type(y);
+ if (NIL_P(tmp)) {
+ z = rb_ary_dup(x);
+ rb_ary_push(z, y);
+ return z;
+ }
+ y = tmp;
     len = RARRAY(x)->len + RARRAY(y)->len;
@@ -2696,6 +2713,6 @@ rb_ary_diff(ary1, ary2)
{
- VALUE ary3, hash;
+ VALUE tmp, ary3, hash;
     long i;

- hash = ary_make_hash(to_ary(ary2), 0);
+ hash = ary_make_hash(make_ary(ary2), 0);
     ary3 = rb_ary_new();
@@ -2727,5 +2744,5 @@ rb_ary_and(ary1, ary2)

- ary2 = to_ary(ary2);
+ ary2 = make_ary(ary2);
     ary3 = rb_ary_new2(RARRAY(ary1)->len < RARRAY(ary2)->len ?
- RARRAY(ary1)->len : RARRAY(ary2)->len);
+ RARRAY(ary1)->len : RARRAY(ary2)->len);
     hash = ary_make_hash(ary2, 0);
@@ -2761,3 +2778,3 @@ rb_ary_or(ary1, ary2)

- ary2 = to_ary(ary2);
+ ary2 = make_ary(ary2);
     ary3 = rb_ary_new2(RARRAY(ary1)->len+RARRAY(ary2)->len);

Are you suggesting this or saying it is bad?

I don't like it at all. So this is suggesting 2 forms to
Array#| and Array#+:

array | other_array => array
array | element => array

If you are looking at combining an element that happens to also
be an array, you have an ambiguous situation. It will combine
the contents of that array instead of the array.

If you want this functionality, you should ask for another
method that does this instead of overloading another. There is
no disadvantage to this other than having to remember a new
method name (and not being able to reuse an operator). The
problem is that there is a decision to be made about what to do
(combine a single element or an array of them) and that
decision is based on what the argument type is (or what methods
it responds to). This goes clearly against the duck-typing
philosophy where a method should ignore the types of its
arguments - it should just use their methods and not worry.

OT ... but, the built-in classes of Ruby violate duck-typing
all over the place. You'll find lots of examples where:

1) methods have multiple functionalities based on the types of
the arguments (usually exact class not just respond_to?).

2) even where a method only has one functionality (or the
multiple functionalites are determined by means other than arg
type/capabilities - flags, number of args, etc), many/most
built-in methods can't take args that have the same
capabilities as what is excepted - they only take a certain
type or maybe one derived from it.

I think this sucks about the Ruby library - that most builtin
methods have poor polymorphism/duck-typing of their arguments.

···

--- Simon Strandgaard <neoneye@gmail.com> wrote:

Sometimes wish that [3, 5, 13] | [8] can be written as [3,
5, 13] | 8
that ary |= 42 would be possible.

chris2 pointed out that it would be inconsistent with [1,2,3]
+ 4.
maybe let + append 4 to the array?

ary = [1, 3, 4]
#=> [1, 3, 4]

ary |= 2
#=> [1, 2, 3, 4]

This is another bad idea..

____________________________________________________
Start your day with Yahoo! - make it your home page
http://www.yahoo.com/r/hs

Simon Strandgaard <neoneye@gmail.com> writes:

Sometimes wish that [3, 5, 13] | [8] can be written as [3, 5, 13] | 8
that ary |= 42 would be possible.

chris2 pointed out that it would be inconsistent with [1,2,3] + 4.
maybe let + append 4 to the array?

ary = [1, 3, 4]
#=> [1, 3, 4]

ary |= 2
#=> [1, 2, 3, 4]

Why not [2, 1, 3, 4] or [1, 3, 2, 4] or [1, 3, 4, 2] here? Arrays have
an ordering; how do you specify where your new element goes?

···

--
I tend to view "truly flexible" by another term: "Make everything
equally hard". -- DHH

Simon Strandgaard wrote:

Sometimes wish that [3, 5, 13] | [8] can be written as [3, 5, 13] | 8
that ary |= 42 would be possible.

chris2 pointed out that it would be inconsistent with [1,2,3] + 4.
maybe let + append 4 to the array?

Sorry for such a late response, but I just had to ask:

Why not just use Array#<<? It works fine, is unambiguous, and neither
the suggestions for Array#| nor that for Array#+ do anything that
Array#<< doesn't already. Or am I missing something vital here?,
        nikolai

···

--
Nikolai Weibull: now available free of charge at http://bitwi.se/\!
Born in Chicago, IL USA; currently residing in Gothenburg, Sweden.
main(){printf(&linux["\021%six\012\0"],(linux)["have"]+"fun"-97);}

>Sometimes wish that [3, 5, 13] | [8] can be written as [3, 5, 13] | 8
>that ary |= 42 would be possible.

[snip]

But I'm not sure this conversion is harmless and useful, or not. Let
us try for a while. Here's a patch to implement what you want. I
will merge it to the HEAD, to see how it goes.

Hehe.. that was fast. Thanks many times.

···

On 8/3/05, Yukihiro Matsumoto <matz@ruby-lang.org> wrote:

In message "Re: [RCR] array or with non-array" > on Wed, 3 Aug 2005 06:31:28 +0900, Simon Strandgaard <neoneye@gmail.com> writes:

--
Simon Strandgaard

Hi,

1) methods have multiple functionalities based on the types of
the arguments (usually exact class not just respond_to?).

Usually using duck types, for example "to_str" for string-like
objects. It it's not, I consider it a bug.

2) even where a method only has one functionality (or the
multiple functionalites are determined by means other than arg
type/capabilities - flags, number of args, etc), many/most
built-in methods can't take args that have the same
capabilities as what is excepted - they only take a certain
type or maybe one derived from it.

Example, please?

              matz.

···

In message "Re: [RCR] array or with non-array" on Wed, 3 Aug 2005 07:34:27 +0900, Eric Mahurin <eric_mahurin@yahoo.com> writes:

Hi,

···

In message "Re: [RCR] array or with non-array" on Wed, 3 Aug 2005 23:31:05 +0900, Michael Campbell <michael.campbell@gmail.com> writes:

Why not [2, 1, 3, 4] or [1, 3, 2, 4] or [1, 3, 4, 2] here? Arrays have
an ordering; how do you specify where your new element goes?

It's random. It uses Hash inside.

              matz.

Nikolai Weibull <mailing-lists.ruby-talk@rawuncut.elitemail.org> writes:

Simon Strandgaard wrote:

Sometimes wish that [3, 5, 13] | [8] can be written as [3, 5, 13] | 8
that ary |= 42 would be possible.

chris2 pointed out that it would be inconsistent with [1,2,3] + 4.
maybe let + append 4 to the array?

Sorry for such a late response, but I just had to ask:

Why not just use Array#<<? It works fine, is unambiguous, and neither
the suggestions for Array#| nor that for Array#+ do anything that
Array#<< doesn't already. Or am I missing something vital here?,
        nikolai

<< is destructive, + copies, | copies but doesn't add it if it's
already in there.

Still, I don't see what you are trying to say?

···

Nikolai Weibull

--
Christian Neukirchen <chneukirchen@gmail.com> http://chneukirchen.org

Hi,

···

In message "Re: [RCR] array or with non-array" on Wed, 3 Aug 2005 07:39:13 +0900, Simon Strandgaard <neoneye@gmail.com> writes:

But I'm not sure this conversion is harmless and useful, or not. Let
us try for a while. Here's a patch to implement what you want. I
will merge it to the HEAD, to see how it goes.

Hehe.. that was fast. Thanks many times.

They are fragile. Don't assume they will behave same forever.

              matz.

Hi,

>1) methods have multiple functionalities based on the types
of
>the arguments (usually exact class not just respond_to?).

Usually using duck types, for example "to_str" for
string-like
objects. It it's not, I consider it a bug.

Having the the method take any object that implements the to_s
is good duck typing, but then we get right back to static
typing as soon the the built-in methods use the result of to_s
- they require it to be a string. Having many of the built-in
methods do a to_s is nothing more than a convenience (you could
easily do the same thing by putting a .to_s appended to those
arguments). It doesn't really help the arguments be more
polymorphic. If I had a class that implemented all of the
String methods, it wouldn't be any good to the built-in classes
- to_s would still have to return an actual String, not self.

But, this wasn't really what my #1 above was about. It was
about overloaded methods where the functionality is determined
by looking at the type of the arguments. One example would be
String#[arg]:

str[fixnum] => fixnum or nil
str[range] => new_str or nil
str[regexp] => new_str or nil
str[other_str] => new_str or nil

All of these behave very different. The way you figure out
what to do is based on type - which goes against the
duck-typing philosophy. I think the only advantage of
combining all of these functions into one method is
convenience. But, by doing so you loose the ability to handle
more general duck-typed/polymorphic arguments.

I think the = method has a more legitimate excuse for the
amount of overloading - a syntactical one - because there is no
other way to make a method that can be assigned to and have
arguments (other than the rvalue). RCR #307 would help solve
that issue.

>2) even where a method only has one functionality (or the
>multiple functionalites are determined by means other than
arg
>type/capabilities - flags, number of args, etc), many/most
>built-in methods can't take args that have the same
>capabilities as what is excepted - they only take a certain
>type or maybe one derived from it.

Example, please?

              matz.

I think a primary example where I would really like real
duck-typing in a built-in would be Regexp#match(str). This
requires the arg to be a String. I would really like to have
this be able to operate on a file. If I implement a class that
walks like, talks like, quacks like a String but really
accesses a file (practically did that in my rubyforge cursor
project), it wouldn't do any good because Regexp#match only
takes a String - period.

The Regexp#match method could be implemented to take ANY object
that implemented a some subset of the String API. Now you
might say that would be really slow, but you could just make
that functionality. Implementation-wise, you could special
case when the object in a String and do a much faster
implementation (but functionally the same as the general
version). A side effect of doing it this way is that you'd
have two implementations (with a String arg) that should be
functionally equivalent and thus great for testing (could be
put in a self-checking mode).

Eric

···

--- Yukihiro Matsumoto <matz@ruby-lang.org> wrote:

In message "Re: [RCR] array or with non-array" > on Wed, 3 Aug 2005 07:34:27 +0900, Eric Mahurin > <eric_mahurin@yahoo.com> writes:

____________________________________________________
Start your day with Yahoo! - make it your home page
http://www.yahoo.com/r/hs

Christian Neukirchen wrote:

Nikolai Weibull <mailing-lists.ruby-talk@rawuncut.elitemail.org> writes:

> Simon Strandgaard wrote:

> > Sometimes wish that [3, 5, 13] | [8] can be written as [3, 5, 13] | 8
> > that ary |= 42 would be possible.
> >
> > chris2 pointed out that it would be inconsistent with [1,2,3] + 4.
> > maybe let + append 4 to the array?

> Sorry for such a late response, but I just had to ask:
>
> Why not just use Array#<<? It works fine, is unambiguous, and neither
> the suggestions for Array#| nor that for Array#+ do anything that
> Array#<< doesn't already. Or am I missing something vital here?,

<< is destructive, + copies, | copies but doesn't add it if it's
already in there.

Ah, of course; silly me.

Still, I don't see what you are trying to say?

Huh?,
        nikolai

···

--
Nikolai Weibull: now available free of charge at http://bitwi.se/\!
Born in Chicago, IL USA; currently residing in Gothenburg, Sweden.
main(){printf(&linux["\021%six\012\0"],(linux)["have"]+"fun"-97);}

Hi,

Having the the method take any object that implements the to_s
is good duck typing, but then we get right back to static
typing as soon the the built-in methods use the result of to_s
- they require it to be a string.

I know but it is a matter of cost both efficiency and implementation.
Since current "restriction" covers 99.99% usage of strings, it is
kinda hard to pay cost to implement full polymorphic arguments like
you mentioned. When MetaRuby comes true, I'm not going to oppose,
perhaps.

But, this wasn't really what my #1 above was about. It was
about overloaded methods where the functionality is determined
by looking at the type of the arguments. One example would be
String#[arg]:

str[fixnum] => fixnum or nil
str[range] => new_str or nil
str[regexp] => new_str or nil
str[other_str] => new_str or nil

All of these behave very different. The way you figure out
what to do is based on type - which goes against the
duck-typing philosophy. I think the only advantage of
combining all of these functions into one method is
convenience. But, by doing so you loose the ability to handle
more general duck-typed/polymorphic arguments.

Convenience is important, sometimes more than pure duck typing.
There still be a room for improvement though.

I think a primary example where I would really like real
duck-typing in a built-in would be Regexp#match(str). This
requires the arg to be a String.

Again, it's a matter of cost. For example, full duck typing
Regexp#match likely requires re-implementation of a regular expression
matching engine in Ruby.

              matz.

···

In message "Re: [RCR] array or with non-array" on Wed, 3 Aug 2005 10:40:03 +0900, Eric Mahurin <eric_mahurin@yahoo.com> writes:

Eric Mahurin wrote:

Having the the method take any object that implements the to_s
is good duck typing, but then we get right back to static
typing as soon the the built-in methods use the result of to_s
- they require it to be a string.

Uhh... erh?
1. What methods do you think Regexp#match (or IO#write) calls on a String object to extract the data out of it? What would you mock to make your object quack like a String, for Regexp#match to be able to print it to the screen? What would you have the #each method return?
2. What added flexibility would you get out of having to_str (not to_s) return a duck rather than a String? Specifically, what flexibility would you get that is not afforded by the ability to subclass String?

That said, I realize that not every core method is IO#write. :slight_smile:

One example would be
String#[arg]:

All of these behave very different. The way you figure out
what to do is based on type - which goes against the
duck-typing philosophy.

True. But...

I think the only advantage of
combining all of these functions into one method is
convenience.

Convenience is very important. It's why Rubyists do:
array.each {|i| puts i}
but Javaers don't:
array.each(new Function() {
  public void call(Object obj) {
    System.out.println(obj);
  }
}
(with a Function interface definition somewhere, and an each method definition on a subclass of ArrayList somewhere else).

Devin

Hi --

I think a primary example where I would really like real
duck-typing in a built-in would be Regexp#match(str). This
requires the arg to be a String. I would really like to have
this be able to operate on a file. If I implement a class that
walks like, talks like, quacks like a String but really
accesses a file (practically did that in my rubyforge cursor
project), it wouldn't do any good because Regexp#match only
takes a String - period.

You can define #to_str on your object to get Regexp#match to accept
it as an argument:

   irb(main):006:0> o = Object.new
   => #<Object:0x401f3db4>
   irb(main):007:0> def o.to_str; "hi"; end
   => nil
   irb(main):008:0> /i/.match(o)
   => #<MatchData:0x401eec60>

The Regexp#match method could be implemented to take ANY object
that implemented a some subset of the String API.

I think there's a semantic or perhaps definitional issue here, though.
What does it mean for a regular expression to "match" an arbitrary
object? I don't think it's just a matter of what methods the object
has. The object has to match the pattern, and the patterns are
descriptions of strings. I'm not sure how you would detect a pattern
like /[A-Z]{3}(\d\d)?/ in something that wasn't a string.

David

···

On Wed, 3 Aug 2005, Eric Mahurin wrote:

--
David A. Black
dblack@wobblini.net

Devin Mullins wrote:

What would you mock to make your object quack like a String, for Regexp#match to be able to print it to the screen?

Oops. Guess I should proofread.

Devin

Hi --

···

On Wed, 3 Aug 2005, Devin Mullins wrote:

Convenience is very important. It's why Rubyists do:
array.each {|i| puts i}

Or even:

   puts array

:slight_smile:

David

--
David A. Black
dblack@wobblini.net

Hi --

> I think a primary example where I would really like real
> duck-typing in a built-in would be Regexp#match(str). This
> requires the arg to be a String. I would really like to
have
> this be able to operate on a file. If I implement a class
that
> walks like, talks like, quacks like a String but really
> accesses a file (practically did that in my rubyforge
cursor
> project), it wouldn't do any good because Regexp#match only
> takes a String - period.

You can define #to_str on your object to get Regexp#match to
accept
it as an argument:

   irb(main):006:0> o = Object.new
   => #<Object:0x401f3db4>
   irb(main):007:0> def o.to_str; "hi"; end
   => nil
   irb(main):008:0> /i/.match(o)
   => #<MatchData:0x401eec60>

This doesn't really help in the polymorphism department. This
is no different than writing:

/i/.match(o.to_str)

> The Regexp#match method could be implemented to take ANY
object
> that implemented a some subset of the String API.

I think there's a semantic or perhaps definitional issue
here, though.
What does it mean for a regular expression to "match" an
arbitrary
object? I don't think it's just a matter of what methods the
object
has. The object has to match the pattern, and the patterns
are
descriptions of strings. I'm not sure how you would detect a
pattern
like /[A-Z]{3}(\d\d)?/ in something that wasn't a string.

By the same methods used in String. It could get away with
just one method to accomplish the task: #[positive_int]. We
could put this in IO for example:

class IO
  def (i)
    self.pos = i
    if eof? # pos can go beyond the eof
      self.pos = i-1
      return(nil) if eof?
      self.pos = i
    end
    getc
  end
end

If Regexp#match(obj) used just obj[pos], we could match a
Regexp across a file with the above.

Like I said earlier, for efficiency the code should special
case the String case and use the same implementation there is
now.

···

--- "David A. Black" <dblack@wobblini.net> wrote:

On Wed, 3 Aug 2005, Eric Mahurin wrote:

____________________________________________________
Start your day with Yahoo! - make it your home page
http://www.yahoo.com/r/hs

Hi,

>Having the the method take any object that implements the
to_s
>is good duck typing, but then we get right back to static
>typing as soon the the built-in methods use the result of
to_s
>- they require it to be a string.

I know but it is a matter of cost both efficiency and
implementation.
Since current "restriction" covers 99.99% usage of strings,
it is
kinda hard to pay cost to implement full polymorphic
arguments like
you mentioned. When MetaRuby comes true, I'm not going to
oppose,
perhaps.

Right now, it probably covers 100%. I think it is hard to
determine the usefulness of many features like this until it
they are implemented.

>But, this wasn't really what my #1 above was about. It was
>about overloaded methods where the functionality is
determined
>by looking at the type of the arguments. One example would
be
>String#[arg]:
>
>str[fixnum] => fixnum or nil
>str[range] => new_str or nil
>str[regexp] => new_str or nil
>str[other_str] => new_str or nil
>
>All of these behave very different. The way you figure out
>what to do is based on type - which goes against the
>duck-typing philosophy. I think the only advantage of
>combining all of these functions into one method is
>convenience. But, by doing so you loose the ability to
handle
>more general duck-typed/polymorphic arguments.

Convenience is important, sometimes more than pure duck
typing.
There still be a room for improvement though.

I'm more of a purist and thus prefer the purity over the
convenience. And I know there may not be many in my camp.

As long as the built-in methods don't handle full
duck-typed/polymorphic arguments, the above overloading isn't
an issue. In the case above, all of the object types are
exclusive. I think cases where the object types aren't
exclusive or you have to prioritize is not a good thing. Those
cases lead to confusion and inconsistencies. An example would
be the overloading of Array#| you just added as a trial. With
this, you can now OR in any single element to the array EXCEPT
when that element is an Array. That exception case exists
because you can OR in a single element or an Array and the
Array case takes precedence. If you look at almost any
non-trivial bug in software, it happens when? exceptions and
end-cases. Putting intentional exceptions in the methods only
makes the problem worse - the caller now may have to handle
that same exception/end-case.

>I think a primary example where I would really like real
>duck-typing in a built-in would be Regexp#match(str). This
>requires the arg to be a String.

Again, it's a matter of cost. For example, full duck typing
Regexp#match likely requires re-implementation of a regular
expression
matching engine in Ruby.

              matz.

It would definitely increase the code size. But, it shouldn't
change the run-time efficiency. Right now Regexp#match(str)
probably looks something like this:

raise(...) if !(String===str)
# code to match against a String

This would become

if String===str
  # code to match against a String (functionally same as below)
else
  # full duck-typed code using methods of str
end

Anyways, I'm glad I brought this up so that you can at least
give it some thought... Everybody talks about having your Ruby
code duck-typed, well why not ask the same of the built-in
methods?

···

--- Yukihiro Matsumoto <matz@ruby-lang.org> wrote:

In message "Re: [RCR] array or with non-array" > on Wed, 3 Aug 2005 10:40:03 +0900, Eric Mahurin > <eric_mahurin@yahoo.com> writes:

____________________________________________________
Start your day with Yahoo! - make it your home page
http://www.yahoo.com/r/hs

Hi --

Hi --

I think a primary example where I would really like real
duck-typing in a built-in would be Regexp#match(str). This
requires the arg to be a String. I would really like to

have

this be able to operate on a file. If I implement a class

that

walks like, talks like, quacks like a String but really
accesses a file (practically did that in my rubyforge

cursor

project), it wouldn't do any good because Regexp#match only
takes a String - period.

You can define #to_str on your object to get Regexp#match to
accept
it as an argument:

   irb(main):006:0> o = Object.new
   => #<Object:0x401f3db4>
   irb(main):007:0> def o.to_str; "hi"; end
   => nil
   irb(main):008:0> /i/.match(o)
   => #<MatchData:0x401eec60>

This doesn't really help in the polymorphism department. This
is no different than writing:

/i/.match(o.to_str)

I think it's quite different, certainly in appearance and to some
extent in logic. I'm not sure how much more polymorphic one could
get, unless one had every object present its .to_s representation for
matching, which would not be good.

The Regexp#match method could be implemented to take ANY

object

that implemented a some subset of the String API.

I think there's a semantic or perhaps definitional issue
here, though.
What does it mean for a regular expression to "match" an
arbitrary
object? I don't think it's just a matter of what methods the
object
has. The object has to match the pattern, and the patterns
are
descriptions of strings. I'm not sure how you would detect a
pattern
like /[A-Z]{3}(\d\d)?/ in something that wasn't a string.

By the same methods used in String. It could get away with
just one method to accomplish the task: #[positive_int]. We
could put this in IO for example:

class IO
def (i)
   self.pos = i
   if eof? # pos can go beyond the eof
     self.pos = i-1
     return(nil) if eof?
     self.pos = i
   end
   getc
end
end

If Regexp#match(obj) used just obj[pos], we could match a
Regexp across a file with the above.

scanf.rb does something along those lines. (It gets tricky with
scanf, because of whitespace and stuff, but it's basically position
and index manipulation.) Then again, scanf has always been
stream-oriented. I'm not sure I agree conceptually with the idea of
matching an IO object to a pattern. It actually feels to me like
there *should* be an explicit, intervening string representation.

Nor do I think this is a sign of failure or rejection of the principle
of duck typing or anything like that. Everything doesn't have to do
everything. For instance, you can't do File.rename on an integer, or
divide a hash by a float. And yes, I know that the reductio ad
absurdum is not proof of anything :slight_smile: I just think there's some
nuance to some of the cases, including the specificity of the
pattern/string connection. I don't see pattern matching as strictly a
matter of integer indexability.

David

···

On Wed, 3 Aug 2005, Eric Mahurin wrote:

--- "David A. Black" <dblack@wobblini.net> wrote:

On Wed, 3 Aug 2005, Eric Mahurin wrote:

--
David A. Black
dblack@wobblini.net