Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

[RCR] array or with non-array

0 views
Skip to first unread message

Simon Strandgaard

unread,
Aug 2, 2005, 5:31:28 PM8/2/05
to
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


Yukihiro Matsumoto

unread,
Aug 2, 2005, 6:02:02 PM8/2/05
to
Hi,

In message "Re: [RCR] array or with non-array"


on Wed, 3 Aug 2005 06:31:28 +0900, Simon Strandgaard <neo...@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?

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;
+}
+
+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);


Eric Mahurin

unread,
Aug 2, 2005, 6:34:27 PM8/2/05
to


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.


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


Simon Strandgaard

unread,
Aug 2, 2005, 6:39:13 PM8/2/05
to
On 8/3/05, Yukihiro Matsumoto <ma...@ruby-lang.org> wrote:
> In message "Re: [RCR] array or with non-array"
> on Wed, 3 Aug 2005 06:31:28 +0900, Simon Strandgaard <neo...@gmail.com> writes:
> |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.

--
Simon Strandgaard


Yukihiro Matsumoto

unread,
Aug 2, 2005, 7:05:33 PM8/2/05
to
Hi,

In message "Re: [RCR] array or with non-array"

on Wed, 3 Aug 2005 07:39:13 +0900, Simon Strandgaard <neo...@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.


Yukihiro Matsumoto

unread,
Aug 2, 2005, 7:08:08 PM8/2/05
to
Hi,

In message "Re: [RCR] array or with non-array"

on Wed, 3 Aug 2005 07:34:27 +0900, Eric Mahurin <eric_m...@yahoo.com> writes:

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


Eric Mahurin

unread,
Aug 2, 2005, 9:40:03 PM8/2/05
to
--- Yukihiro Matsumoto <ma...@ruby-lang.org> wrote:

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

unread,
Aug 3, 2005, 5:58:09 AM8/3/05
to
Hi,

In message "Re: [RCR] array or with non-array"

on Wed, 3 Aug 2005 10:40:03 +0900, Eric Mahurin <eric_m...@yahoo.com> writes:

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

Devin Mullins

unread,
Aug 3, 2005, 6:09:52 AM8/3/05
to
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. :)

>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

Devin Mullins

unread,
Aug 3, 2005, 6:11:57 AM8/3/05
to
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

David A. Black

unread,
Aug 3, 2005, 7:07:59 AM8/3/05
to
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

:-)


David

--
David A. Black
dbl...@wobblini.net


David A. Black

unread,
Aug 3, 2005, 7:22:44 AM8/3/05
to
Hi --

On Wed, 3 Aug 2005, Eric Mahurin wrote:

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

Eric Mahurin

unread,
Aug 3, 2005, 9:14:02 AM8/3/05
to
--- "David A. Black" <dbl...@wobblini.net> wrote:

> Hi --
>
> On Wed, 3 Aug 2005, Eric Mahurin wrote:
>
> > 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

unread,
Aug 3, 2005, 9:32:23 AM8/3/05
to
Hi --

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.

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

Michael Campbell

unread,
Aug 3, 2005, 10:09:00 AM8/3/05
to

Simon Strandgaard <neo...@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

Yukihiro Matsumoto

unread,
Aug 3, 2005, 10:55:42 AM8/3/05
to
Hi,

In message "Re: [RCR] array or with non-array"

on Wed, 3 Aug 2005 23:31:05 +0900, Michael Campbell <michael....@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.

Eric Mahurin

unread,
Aug 3, 2005, 11:03:44 AM8/3/05
to
--- Yukihiro Matsumoto <ma...@ruby-lang.org> wrote:

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

unread,
Aug 3, 2005, 11:10:51 AM8/3/05
to
Hi,

In message "Re: [RCR] array or with non-array"

on Thu, 4 Aug 2005 00:03:44 +0900, Eric Mahurin <eric_m...@yahoo.com> writes:

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

|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 you need to convince its usefulness before someone implement it.

|> Convenience is important, sometimes more than pure duck typing.
|

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

I don't know about numbers, but a purist were not able to create Ruby.
He would create something very different from Ruby.

|It would definitely increase the code size. But, it shouldn't
|change the run-time efficiency.

I wasn't talking about performance cost. It was implementation cost.

matz.

Caleb Clausen

unread,
Aug 3, 2005, 11:58:51 AM8/3/05
to
David A. Black wrote:
> I'm not sure I agree conceptually with the idea of
> matching an IO object to a pattern.

You need this to be able to do fancy parsing/lexing in ruby.

> It actually feels to me like
> there *should* be an explicit, intervening string representation.

And in this string would be what? The entire file contents? That works
well for small files, and I've done it many times myself. It doesn't
scale well, tho. If your explicit string contains only part of the
file, you get other problems.


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

Yes, and it would be orders of magnitude slower. This kind of thing is
the major performance issue in Cursor at the moment. Efficiency is a
tin god, but some attention needs be paid to it, to make sure that you
don't define interfaces that are inherently inefficent, for example.

Yukihiro Matsumoto wrote:
> 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.

Not really, no. You can read into a buffer and match against the
buffer. This works pretty well for every pattern without anchors.
Supporting anchors too requires a smidge of rewriting the Regexp at
runtime. My current implementation interprets ^ and \A (or $ and \Z
when matching backward) as matching at the current file position,
rather than the beginning of file.

It's a minor pain, but I have most of the necessary code already.
There's a compromise or two that have to be made: an upper limit on
the length of a single match, ^ won't work right in some rarer cases
until regexp lookback in ruby 1.9. I don't like this, but these
restrictions seem minor enough, considering the massive increase in
functionality otherwise.

Yukihiro Matsumoto

unread,
Aug 3, 2005, 12:13:55 PM8/3/05
to
Hi,

In message "Re: array or with non-array"


on Thu, 4 Aug 2005 00:58:51 +0900, Caleb Clausen <vik...@gmail.com> writes:

|Yukihiro Matsumoto wrote:
|> 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.
|
|Not really, no. You can read into a buffer and match against the
|buffer. This works pretty well for every pattern without anchors.
|Supporting anchors too requires a smidge of rewriting the Regexp at
|runtime. My current implementation interprets ^ and \A (or $ and \Z
|when matching backward) as matching at the current file position,
|rather than the beginning of file.
|
|It's a minor pain, but I have most of the necessary code already.
|There's a compromise or two that have to be made: an upper limit on
|the length of a single match, ^ won't work right in some rarer cases
|until regexp lookback in ruby 1.9. I don't like this, but these
|restrictions seem minor enough, considering the massive increase in
|functionality otherwise.

It's good to hear it's not impossible. Although I'm not agree very
much about "massive" increase of functionality.

matz.

David A. Black

unread,
Aug 3, 2005, 1:29:25 PM8/3/05
to
Hi --

On Thu, 4 Aug 2005, Eric Mahurin wrote:

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

class != type. Type is at the heart of duck-typing; class isn't :-)

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

I'm not clear on how you define purity or purism, but it doesn't
bother me that array[1] and array[1..3] do different things. Maybe
it's because a few core methods where a few core classes are
hard-coded allows for so much richness later, or something along those
lines -- a kind of bootstrapping.

Eric Mahurin

unread,
Aug 3, 2005, 3:21:15 PM8/3/05
to
--- "David A. Black" <dbl...@wobblini.net> wrote:


Huh? Where do you get that? Duck-typing is about not caring
about what the type/class the object is. Duck-typing in the
purest sense is calling the methods of the arguments without
regard to what the class of the object is.

In the above, the functionality is clearly affected by the
class. If you wrote the single arg String#[] above you'd have
something like this:

def [](i)
if Fixnum===i
# retrieve character at index i
elsif Range===i
# retrieve slice designated by the Range i
elsif Regexp===i
# retrieve slice found by the Regexp i
elsif String===i
# retrieve slice that is the same as String i
else
raise
end
end

That is far from duck-typing. This very much cares about the
type/class of the argument. It both restricts the class and
makes decisions about what functionality to have based on that
type. You could use respond_to? instead of klass=== to help,
but that would like just introduce ambiguities about what
functional branch to take - you'd have to favor one case over
another. Implementation-wise, I don't have a problem with
choosing how to operate based on class, but this decision
should not affect functionality - only performance.

David A. Black

unread,
Aug 3, 2005, 4:07:52 PM8/3/05
to
On Thu, 4 Aug 2005, Eric Mahurin wrote:

> --- "David A. Black" <dbl...@wobblini.net> wrote:
>
>> class != type. Type is at the heart of duck-typing; class
>> isn't :-)
>
>
> Huh? Where do you get that? Duck-typing is about not caring
> about what the type/class the object is. Duck-typing in the

Class is irrelevant, but you'd be well-advised to care about what the
type is, or you'll find yourself with a lot of NoMethodErrors :-)

> purest sense is calling the methods of the arguments without
> regard to what the class of the object is.

An object's type is the sum of all of its capabilities. Duck typing
involves focusing on an object's capabilities -- its type -- and not
worrying about its class. You also don't have to "worry" about its
type (and I agree with those who say that duck typing does not mean
sticking respond_to? everywhere). But you are dealing with type --
dealing with it, in the sense of making assumptions about it, writing
code governed by those assumptions, etc. -- and not dealing with
class.

I like Jim Weirich's characterization of Ruby as "a duck-typed
language", because it captures the fact that, in a sense, one is
always doing duck typing in Ruby. That's also why I always feel
uneasy with meta-concepts like the "duck type" of an object. What
people sometimes call the "duck type" of an object, I call simply the
type of the object. Duck typing, in that respect, is a way of
describing an approach to programming that arises very organically
from Ruby.

Eric Mahurin

unread,
Aug 3, 2005, 5:27:58 PM8/3/05
to


Whatever your definition of type is, a method should not care
(i.e. check) about the types of its arguments. It should just
assume that the arguments have the capabilities that it wants.
That is is core of duck-typing, is it not?

I also think your definition of type (or duck-type) is too
restrictive. Instead of "An object's type is the sum of all of
its capabilities", it should be "An argument's type is the sum
of its capabilities that the method uses or documents that it
may use". Every method argument has its own duck-type.

But, back to the original thing that spawned this discussion -
the String#[] method. I claim that this violates the spirit of
duck-typing all over the place because of the class (or type)
checking done to accomplish multiple functions. Do you claim
it is duck-typed? If so, show me how you could get the
multiple functions that it has and still be duck-typed.

My point is that when coding ruby, we are encouraged to use
duck-typing, but the ruby library itself does not. Seems kind
of hypocritical.

Ryan Leavengood

unread,
Aug 3, 2005, 6:09:26 PM8/3/05
to
Eric Mahurin said:
>
> My point is that when coding ruby, we are encouraged to use
> duck-typing, but the ruby library itself does not. Seems kind
> of hypocritical.

It seems to me that much of this encouragement to use duck-typing comes
from other "purists" like yourself, and not from Matz himself, who seems
to care more about pragmatic, usable code and not just purity. While
maintaining some amount of purity is certainly a worthwhile goal, it
should not eclipse usability.

I think that flexible methods like String#[] can be pretty useful, though
I'll admit the semantics can sometimes break the POLS. But not very often

David A. Black

unread,
Aug 3, 2005, 6:47:22 PM8/3/05
to
Hi --

On Thu, 4 Aug 2005, Eric Mahurin wrote:

> Whatever your definition of type is, a method should not care
> (i.e. check) about the types of its arguments. It should just
> assume that the arguments have the capabilities that it wants.
> That is is core of duck-typing, is it not?

I guess it usually involves method arguments, though only indirectly
-- meaning, it's about how objects are treated, and what assumptions
are made about them, whether or not they arrived on the scene as
method arguments (though I guess that's the usual scenario).

> I also think your definition of type (or duck-type) is too
> restrictive. Instead of "An object's type is the sum of all of
> its capabilities", it should be "An argument's type is the sum
> of its capabilities that the method uses or documents that it
> may use". Every method argument has its own duck-type.

My definition of "type" isn't restricted to method arguments, so your
definition doesn't work as a drop-in replacement :-)

I don't find the concept of a "duck-type" very useful. *Type* in
Ruby, without the duck, already reflects something dynamic, flexible,
unrestricted by class/module ancestry, and so on. Duck typing is a
way of leveraging type, in this sense.

> But, back to the original thing that spawned this discussion -
> the String#[] method. I claim that this violates the spirit of
> duck-typing all over the place because of the class (or type)

(definitely class, in this case)

> checking done to accomplish multiple functions. Do you claim
> it is duck-typed? If so, show me how you could get the
> multiple functions that it has and still be duck-typed.
>
> My point is that when coding ruby, we are encouraged to use
> duck-typing, but the ruby library itself does not. Seems kind
> of hypocritical.

You're turning it into a game of "Simon Says" -- "Uh oh, you branched
on class membership: you're out!" :-) I think it's a little more
subtle than that. As I said before, I tend to be accepting of
hard-coded class-based things when they're in the core, since it
provides such a flexible and powerful programming environment and
there's no mandate to base one's Ruby style on the class-name checks
in the C source.

Joel VanderWerf

unread,
Aug 3, 2005, 9:41:25 PM8/3/05
to

warn "philosophical pootling ahead"

Maybe we need to begin talking about ruby not just as a language with
formal, constructive meanings, but as a "language game" in the sense of
Wittgenstein, with meaning accruing through use.[1]

Obviously, any particular ruby program has a constructive meaning
assigned by the interpreter. But that doesn't capture the way meanings
change as a library is used in different ways over time. I can write a
library that works in one way with all the inputs I've considered, but
because those inputs are "duck typed", there exist future
interpretations of my library, based on inputs with unforseen
implementations, that cannot be explained in terms of the "types" I was
thinking of when I wrote my library.

[1] http://plato.stanford.edu/entries/wittgenstein/#Mea

--
vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Nikolai Weibull

unread,
Sep 1, 2005, 2:36:23 PM9/1/05
to
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);}


Christian Neukirchen

unread,
Sep 1, 2005, 4:12:52 PM9/1/05
to
Nikolai Weibull <mailing-lis...@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 <chneuk...@gmail.com> http://chneukirchen.org


Nikolai Weibull

unread,
Sep 1, 2005, 5:17:08 PM9/1/05
to
Christian Neukirchen wrote:

> Nikolai Weibull <mailing-lis...@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?,

0 new messages