Ruby-dev summary 18711-18810

Hi,

···

In message “Re: ruby-dev summary 18711-18810” on 02/11/18, “Aleksei Guzev” aleksei.guzev@bigfoot.com writes:

If the longest sequence would be chosen, what value should receive the
absent items?

nil

But this will raise TypeError in the case of incompatible type/length of the
sequences. This would hide the error and violate “…* (on zip) We should
not raise exceptions when the length of the components are differ…”

I’m not sure if I get what you mean. How does it hide errors and
violate the assumption? nil does not always raise TypeError, if you
know the value may be nil. If “zip” itself raises exceptions, there’s
no workaround.

						matz.

I guess, if zip existed, you could simulate that with:

a = [“a”, “b”, “c”, “d”]
a.zip(0…a.length).map {|item, index| …}

By the way, just like we have each_line, each_value, each_pair,
each_byte… what about each_zip and map_zip as method names?

a.map_zip(0…a.length) {|item, index| …}

Massimiliano

···

On Tue, Nov 19, 2002 at 12:19:50AM +0900, dblack@candle.superlink.net wrote:

Do you mean that map_with_index has been rejected on its own, or just
as a zip implementation?
Hmmmm… I’ll try to think of some examples. It certainly seems to
me to be at least as useful as each_with_index, potentially (i.e., if
it existed :slight_smile:

Hi,

···

In message “Re: ruby-dev summary 18711-18810” on 02/11/19, Paul Brannan pbrannan@atdesk.com writes:

but my naive solution in Ruby doesn’t work:

a = [1, 2, 3, 4, 5]
a.each_with_index do |x, idx|
puts x
if x == 3 then
a.delete_at(idx)
end
end

(it skips the 4).

Or is there a better way to write this that I am missing?

a = [1, 2, 3, 4, 5]
a.delete_if do |x|
puts x
x == 3
end

						matz.

Do you know implementations like (from Ruby CVS)
rough/lib/generator.rb? Why do you think these are inefficient?

I haven’t seen that (but I’ll definitely take a look). I think generators
can be implemented efficiently. In my experience with generators in other
languages, the time efficiency is good enough, and depending on the
underlying language implementation, they can be costly of space since in
some implementations they require their own contiguous stacks (almost like
threads – to support suspended C stacks in the underlying C code).

If Ruby has an efficient generator capability, it would be a good way to
implement “zip” without the space cost of creating an entire copy of all of
the pointers in all involved sequences.

BTW, I have quite a bit of experience with languages that support
generators, primarily with Icon whose generators are normally used at the
site of the generation (like Ruby’s iterators) but can be also be captured
in a “co-expression” to be used anywhere and any time to grab values from
the generator (like Python’s generators). Like Matz says, the Ruby iterator
mechanism is simpler and nicely handles 99% of the cases that usually come
up. On the other hand, in those relatively rare cases where when parallel
iteration requirements arise, the “use anywhere” variety of generator can
make the task much more pleasant.

Maybe Ruby could consider approaches like Icon’s where iterators are
normally internal (like they are now), but can be converted to external for
those occasional needs (apologies if this has already been discussed to
death). I attached a small experimental Ruby class I wrote a long time ago
that implements something like this. The implementation uses threads and
queues, so is not very efficient. However, an API of this sort could
possibly be implemented efficiently at a lower level. Here is the
description from the top of the code:

iterator.rb (1.69 KB)

···

From: “Pit Capitain” pit@capitain.de

Creates an iterator object from an iterator method.

Iterator objects do not replace Ruby iterator methods, but they extend

their capabilities in certain ways:

- The next value(s) can be obtained from anywhere in the program, not

just from the code block passed to the iterator method.

- Multiple iterator objects can be active in parallel.

Iterator creation examples:

i = Iterator.new((1..10).method(:each))

i = Iterator.new([11, 22, 33].method(:each_with_index))

The iterator’s values are retrieved as the array of arguments passed

to the iterator method’s block, for example:

list_element, index = i.get

Bob
(packing for a trip – will be away from my email for a couple of weeks)

Hi –

From: dblack@candle.superlink.net
To: “ruby-talk ML” ruby-talk@ruby-lang.org
Sent: Monday, November 18, 2002 9:19 AM
Subject: Re: ruby-dev summary 18711-18810

Hi –

map_with_index was rejected just because no one proposed its typical
usage. YANGI principle applied.

Hmmmm… I’ll try to think of some examples. It certainly seems to
me to be at least as useful as each_with_index, potentially (i.e., if
it existed :slight_smile:

I’d go so far as to say that map_with_index
does for map exactly what each_with_index
does for each.

I do find it useful.

It’s used in scanf, David, isn’t it? :slight_smile:

Almost, but in the end we didn’t use it. I can’t remember the whole
sequence of events…

I definitely agree that map_with_index (or map_with_indices) is as
deserving of existence as each_with_index. Not that each_with_index
is itself terribly critical:

$ grep each_with_index find . -name "*.rb" | wc -l
6

but still, mwi makes things symmetrical :slight_smile:

David
President, Citizens for MWI, Inc.

···

On Tue, 19 Nov 2002, Hal E. Fulton wrote:

----- Original Message -----

On Mon, 18 Nov 2002, Yukihiro Matsumoto wrote:


David Alan Black
home: dblack@candle.superlink.net
work: blackdav@shu.edu
Web: http://pirate.shu.edu/~blackdav

Hi –

Do you mean that map_with_index has been rejected on its own, or just
as a zip implementation?
Hmmmm… I’ll try to think of some examples. It certainly seems to
me to be at least as useful as each_with_index, potentially (i.e., if
it existed :slight_smile:

I guess, if zip existed, you could simulate that with:

a = [“a”, “b”, “c”, “d”]
a.zip(0…a.length).map {|item, index| …}

And if map_with_index existed, you could define #zip in terms of it
:slight_smile:

def zip(*others)
map_with_index {|e,i| [e,others.map{|n| n[i]}]}
end

(or something)

David

···

On Tue, 19 Nov 2002, Massimiliano Mirra wrote:

On Tue, Nov 19, 2002 at 12:19:50AM +0900, dblack@candle.superlink.net wrote:


David Alan Black
home: dblack@candle.superlink.net
work: blackdav@shu.edu
Web: http://pirate.shu.edu/~blackdav

“Yukihiro Matsumoto” matz@ruby-lang.org wrote in message
news:1037661991.163626.9880.nullmailer@picachu.netlab.jp…

Hi,

If the longest sequence would be chosen, what value should receive the
absent items?

nil

But this will raise TypeError in the case of incompatible type/length of
the
sequences. This would hide the error and violate “…* (on zip) We
should
not raise exceptions when the length of the components are differ…”

I’m not sure if I get what you mean. How does it hide errors and
violate the assumption? nil does not always raise TypeError, if you
know the value may be nil. If “zip” itself raises exceptions, there’s
no workaround.

matz.

Hiding error means one would receive diagnostic message of TypeError while
the error is not of that type. It’s an index error. This will make locating
bugs harder.

Violation means that one calling “zip” will get an exception regardless of
what method has raised it. It doesn’t matter who raised an exception.
Matters its nature and its origin in the user code(!), not library one.

···

In message “Re: ruby-dev summary 18711-18810” > on 02/11/18, “Aleksei Guzev” aleksei.guzev@bigfoot.com writes:

From: “Pit Capitain” pit@capitain.de

Do you know implementations like (from Ruby CVS)
rough/lib/generator.rb? Why do you think these are inefficient?

I haven’t seen that (but I’ll definitely take a look). I think
generators can be implemented efficiently. In my experience with
generators in other languages, the time efficiency is good enough, and
depending on the underlying language implementation, they can be
costly of space since in some implementations they require their own
contiguous stacks (almost like threads – to support suspended C
stacks in the underlying C code).

Hi Bob,

thanks for the clarification. I wasn’t sure what you meant by
“inefficient”. The (generic) iterator implementations presented so
far seem to be at least space-inefficient, because they either create
arrays or use threads/continuations.

If Ruby has an efficient generator capability, it would be a good way
to implement “zip” without the space cost of creating an entire copy
of all of the pointers in all involved sequences.

Not yet, but Matz seems to be working on it.

BTW, I have quite a bit of experience with languages that support
generators (…)
I attached a small experimental Ruby class I
wrote a long time ago that implements something like this. The
implementation uses threads and queues, so is not very efficient.

But the code is a nice read, thanks a lot.

However, an API of this sort could possibly be implemented efficiently
at a lower level.

If I understood Matz correctly he’s working on a low-level
implementation of zip, but doesn’t like external iterators (sigh).

Regards,
Pit

···

On 20 Nov 2002 at 2:59, Bob Alexander wrote:

Hello Bob,

Tuesday, November 19, 2002, 8:59:03 PM, you wrote:

that implements something like this. The implementation uses
threads and queues, so is not very efficient. However, an API of
this sort could possibly be implemented efficiently at a lower
level. Here is the description from the top of the code:

ruby iterators insert iterator body in CALL STACK between caller code
and block evaluated by iterator - so that you hold a state of iterator
body but no state for iterated block

caller
→ iterator
→ block

“.next-style” iterators use opposite scheme:

outside code
→ loop body
→ iterator body

if you want to hold BOTH state of iterator (local vars, ability to
do yield at different places) and state of loop (local vars, ability
to do .next at different places) you need coroutines

···


Best regards,
Bulat mailto:bulatz@integ.ru

Hi,

Hiding error means one would receive diagnostic message of TypeError while
the error is not of that type. It’s an index error. This will make locating
bugs harder.

But it happens all the time in dynamic languages. Why this bothers
you so much?

Violation means that one calling “zip” will get an exception regardless of
what method has raised it. It doesn’t matter who raised an exception.
Matters its nature and its origin in the user code(!), not library one.

You can always get the error position in the user code, either in
stack trace in the error message, or in caller information.

						matz.
···

In message “Re: ruby-dev summary 18711-18810” on 02/11/19, “Aleksei Guzev” aleksei.guzev@bigfoot.com writes:

That would only work for objects with #. But then you
already said it’s ok to you… :wink:

Massimiliano

···

On Tue, Nov 19, 2002 at 09:06:05AM +0900, dblack@candle.superlink.net wrote:

And if map_with_index existed, you could define #zip in terms of it
:slight_smile:

def zip(*others)
map_with_index {|e,i| [e,others.map{|n| n[i]}]}
end

(or something)

“Yukihiro Matsumoto” matz@ruby-lang.org wrote in message
news:1037682098.970812.11088.nullmailer@picachu.netlab.jp…

Hi,

Hiding error means one would receive diagnostic message of TypeError
while
the error is not of that type. It’s an index error. This will make
locating
bugs harder.

But it happens all the time in dynamic languages. Why this bothers
you so much?

All the time people die in auto crashes. But noone says ‘Let them die…’
If there exists an opportunity to work around this issue, why not to do
this?
Of course, I understand there could be some problems implemeting raising
exceptions.

Violation means that one calling “zip” will get an exception regardless
of

···

In message “Re: ruby-dev summary 18711-18810” > on 02/11/19, “Aleksei Guzev” aleksei.guzev@bigfoot.com writes:

what method has raised it. It doesn’t matter who raised an exception.
Matters its nature and its origin in the user code(!), not library one.

You can always get the error position in the user code, either in
stack trace in the error message, or in caller information.

matz.

Hi –

···

On Tue, 19 Nov 2002, Massimiliano Mirra wrote:

On Tue, Nov 19, 2002 at 09:06:05AM +0900, dblack@candle.superlink.net wrote:

And if map_with_index existed, you could define #zip in terms of it
:slight_smile:

def zip(*others)
map_with_index {|e,i| [e,others.map{|n| n[i]}]}
end

(or something)

That would only work for objects with #. But then you
already said it’s ok to you… :wink:

Yes, although I’d be interested in hearing people’s ideas about cases
where that wasn’t sufficient. I guess maybe objects which generate a
random sequence of some kind?

David


David Alan Black
home: dblack@candle.superlink.net
work: blackdav@shu.edu
Web: http://pirate.shu.edu/~blackdav

Hi,

···

In message “Re: ruby-dev summary 18711-18810” on 02/11/19, “Aleksei Guzev” aleksei.guzev@bigfoot.com writes:

But it happens all the time in dynamic languages. Why this bothers
you so much?

All the time people die in auto crashes. But noone says ‘Let them die…’
If there exists an opportunity to work around this issue, why not to do
this?

I still don’t understand what you mean. Sorry.
What do you mean by “work around” and “this”?

						matz.