Accessing index inside map

Hi,

···

In message "Re: accessing index inside map" on Mon, 11 Jul 2005 17:37:07 +0900, nobuyoshi nakada <nobuyoshi.nakada@ge.com> writes:

It's all up to you. Although I feel no need to check rb_proc_call,
since enumerator is bundled with Ruby itself.

Static function proc_call() is defined now but rb_proc_call()
is not. Also rb_obj_method() and rb_method_call().

I know. But if you need those functions, just export (with proper
prefix). I see no need for have_func() check in extconf.rb.

              matz.

nobu.nokada@softhome.net writes:

Hi,

At Wed, 13 Jul 2005 01:10:19 +0900,
Brian Candler wrote in [ruby-talk:147876]:

However, perhaps 'to_enum' could be called something friendlier, e.g.

  obj.using(:each_with_index).inject(0) {|sum,(a,i)| sum + a*i}

`using' sounds too general.

In fact, even

  obj.enum(:each_with_index).inject(0) {|sum,(a,i)| sum + a*i}

reads better to me, as it's not stressing the creation of an intermediate
object. to_foo looks like you are converting obj into something completely
different, rather than just adding a temporary wrapper.

Enumerable#to_enum has an alias named as #enum_for.

How about just `for'? That word is already strongly associated
with enumeration, and connects well to the `each_*'.

   obj.for(:each_with_index).inject(0) { |sum, (a, i)| sum + a * i }

However, ``for each inject'' sounds pretty weird, since we're not
injecting something into each element --- we're injecting it into the
whole collection.

I don't know, just a thought.

···

--
Daniel Brockman <daniel@brockman.se>

The preposition "for" doesn't really sound right here. I don't think we are
enumerating "for" each_with_index; we are enumerating "with"
each_with_index, or "using", or perhaps "over".

The underscore also seems to break up the line visually. Now I know the full
details, I can understand the following, but there are two visual breaks
between the 'map' and the object being enumerated over:

    obj.enum_for(:each_with_index).map { .. }
            ^ ^
          break break

I think that

    obj.enum(:each_with_index).map { .. }

is more clearly a single method call separating the object and its map.

The idea of an enumeration method returning an Enumerator if called without
a block is interesting:

    obj.each_with_index.map { .. }

although this means that every enumeration method you write needs extra code
to support this behaviour. And I dread to think what happens if you start to
chain these methods :slight_smile:

This mechanism requires every programmer to do more work in their
enumeration methods. In that case, I still prefer to modify every method in
Enumerable instead: i.e.

    obj.map(:each_with_index) { .. }

But only one person has commented on this so far.

Regards,

Brian.

···

On Wed, Jul 13, 2005 at 01:46:17AM +0900, nobu.nokada@softhome.net wrote:

> However, perhaps 'to_enum' could be called something friendlier, e.g.
>
> obj.using(:each_with_index).inject(0) {|sum,(a,i)| sum + a*i}

`using' sounds too general.

> In fact, even
>
> obj.enum(:each_with_index).inject(0) {|sum,(a,i)| sum + a*i}
>
> reads better to me, as it's not stressing the creation of an intermediate
> object. to_foo looks like you are converting obj into something completely
> different, rather than just adding a temporary wrapper.

Enumerable#to_enum has an alias named as #enum_for.

Robert Klemme wrote:

Brian Candler wrote:

> In fact, even
>
> obj.enum(:each_with_index).inject(0) {|sum,(a,i)| sum + a*i}

That reads better IMHO.

> reads better to me, as it's not stressing the creation of an
> intermediate object. to_foo looks like you are converting obj into
> something completely different, rather than just adding a temporary
> wrapper.

Yeah, maybe. Anyway, this is far better than rename IMHO.

[1]; obj.enum(:each_with_index).inject(0) {|sum,(a,i)| sum + a*i}

[2]; i=-1; obj.inject(0) {|sum, a| sum + a*(i+=1)}

Can anyone shade me in on what, if any, advantage [1] has over [2]:
-- in terms of:

a) Readability
b) Ease of use and understanding
c) Performance
d) Flexibility
e) Accuracy
f) Memory usage
g) Anything else you care to throw in :wink:

I can tell at a glance that it's going to require more typing
because it contains the string '_with_index' ...

## keystrokes (including shifts on UK kbd)
# _with_index #-> 11/13
# i=-1; i+=1; #-> 10/11

But there seem to be so many other overheads in comparison,
that I can't focus on whether or not you're saying something
that I need to get my head around.

TIA,

daz

> The Enumerator stuff is new to me, since I'm still just using 1.8.2.

It's in 1.8.2 and I think it's been around for some time, maybe even as
far back as 1.7.*.

Ah, I was just going on "ri Enumerator", which shows only SyncEnumerator.

<< Rummages around >> - OK, so this is a C extension, which like most of
them, is undocumented in a running system. Pulling down the source though, I
find ext/enumerator/enumerator.txt

Perhaps someone would like to rdoc-merge this into the source?

Regards,

Brian.

I've long since started renaming them to ewi and mwi in my own code.

martin

···

daz <dooby@d10.karoo.co.uk> wrote:

I can tell at a glance that it's going to require more typing
because it contains the string '_with_index' ...

Brian Candler wrote:

<< Rummages around >> - OK, so this is a C extension, [...]

Nobu has transformed enumerator.c -- Try the latest:
http://tinyurl.com/7ljdw/ext/enumerator/enumerator.c?rev=1.6;content-type=text%2Fplain

daz

[1]; obj.enum(:each_with_index).inject(0) {|sum,(a,i)| sum + a*i}

[2]; i=-1; obj.inject(0) {|sum, a| sum + a*(i+=1)}

Can anyone shade me in on what, if any, advantage [1] has over [2]:
-- in terms of:

a) Readability
b) Ease of use and understanding
c) Performance
d) Flexibility
e) Accuracy
f) Memory usage
g) Anything else you care to throw in :wink:

1. It retains the enapsulation of "iterating with an index"; you are
reimplementing it in your inner block. (Violation of DRY principle).

2. It's more general; it works with other iteration methods. Consider
Hash#each_value and Hash#each_key, or String#each_byte for example.

    require 'enumerator'
    "abc".to_enum(:each_byte).collect #=> [97, 98, 99]

Of course you could rewrite this too, but then you're reimplementing
'collect':

    res =
    "abc".each_byte { |x| res << x }
    res

3. If you were using the index in more than one place in the inner block, it
would become more verbose.

    i=0; obj.inject(0) { ... use i ... use i ...; i+=1 }

Regards,

Brian.

Brian Candler wrote:

>
> [1]; obj.enum(:each_with_index).inject(0) {|sum,(a,i)| sum + a*i}
>
> [2]; i=-1; obj.inject(0) {|sum, a| sum + a*(i+=1)}
>
> Can anyone shade me in on what, if any, advantage [1] has over [2]:
> -- in terms of:
>
> a) Readability
> b) Ease of use and understanding
> c) Performance
> d) Flexibility
> e) Accuracy
> f) Memory usage
> g) Anything else you care to throw in :wink:

1. It retains the enapsulation of "iterating with an index";

OK. That's why I want it provided automatically inside the block.
It's information known to, but not revealed by, the iterator. We're the
programmers ... they're our blocks ... why can't we discover a fundamental
detail like which iteration we're on ??

you are reimplementing it in your inner block.

Both examples implement an index. One as an external variable, the other
as an extra block parameter provided by #each_with_index.
I can't see anything I've reimplemented. We may be at cross-purposes ?

(Violation of DRY principle).

Not so. There's no index, and I need one, so I have to create it.
So do you. It's no more a violation of DRY than having to
open a file _every_ flippin' time I want to read it.

2. It's more general; it works with other iteration methods. Consider
Hash#each_value and Hash#each_key, or String#each_byte for example.

I've considered. I can't think of any that it wouldn't work with.
Is there anything more general than that ?

    require 'enumerator'
    "abc".to_enum(:each_byte).collect #=> [97, 98, 99]

Of course you could rewrite this too, but then you're reimplementing
'collect':

    res =
    "abc".each_byte { |x| res << x }
    res

OK, _that_ would be a reimplementation of 'collect' but I can't respond
with an example of what I'd do because you haven't used an index.
I'm talking index only, albeit within a slightly expanded topic.

However, dawning is in progress, perhaps :slight_smile:

# "abc".to_enum(:each_byte).collect #=> [97, 98, 99]

I was about to describe the #each_byte block as a "proxy receiver"
for #collect, but I think I'll wait before spreading untruths
because it feels reversed (?)

3. If you were using the index in more than one place in the inner block, it
would become more verbose.

    i=0; obj.inject(0) { ... use i ... use i ...; i+=1 }

Absurd :wink:
If your block had 30 uses of the index, my version would have 31.

I'll say again - we may be mixing subjects (accessing an index
versus Enumeration and it's probably just me who doesn't know the
difference, yet).

Brian.

Thanks BC,

daz

The documentation in enumerator.txt has not been merged in. How is it
different functionally?

I've diffed this file against ruby-1.8.2 and I see a number of changes but I
don't know what they're doing. Although I do see a couple of nice buffer
overflows :slight_smile:

+ VALUE args[2];
+ args[0] = obj;
+ args[1] = sym_each_slice;
+ args[2] = n;

Doh!

Regards,

Brian.

···

On Wed, Jul 13, 2005 at 07:20:53PM +0900, daz wrote:

Nobu has transformed enumerator.c -- Try the latest:
http://tinyurl.com/7ljdw/ext/enumerator/enumerator.c?rev=1.6;content-type=text%2Fplain

Hi,

At Thu, 14 Jul 2005 18:02:53 +0900,
Brian Candler wrote in [ruby-talk:148087]:

> Nobu has transformed enumerator.c -- Try the latest:
> http://tinyurl.com/7ljdw/ext/enumerator/enumerator.c?rev=1.6;content-type=text%2Fplain

The documentation in enumerator.txt has not been merged in. How is it
different functionally?

Moved it to the top level and merged the document.

I've diffed this file against ruby-1.8.2 and I see a number of changes but I
don't know what they're doing. Although I do see a couple of nice buffer
overflows :slight_smile:

+ VALUE args[2];
+ args[0] = obj;
+ args[1] = sym_each_slice;
+ args[2] = n;

Doh!

Thank you, but the code has been rewritten. :wink:

···

--
Nobu Nakada

Hi,

At Fri, 15 Jul 2005 14:46:39 +0900,
nobuyoshi nakada wrote in [ruby-talk:148205]:

At Thu, 14 Jul 2005 18:02:53 +0900,
Brian Candler wrote in [ruby-talk:148087]:
> > Nobu has transformed enumerator.c -- Try the latest:
> > http://tinyurl.com/7ljdw/ext/enumerator/enumerator.c?rev=1.6;content-type=text%2Fplain
>
> The documentation in enumerator.txt has not been merged in. How is it
> different functionally?

Moved it to the top level and merged the document.

But I found rdoc can't handle a module/class enclosed in a
built-in module/class.

                               enum.c: m..........................
  No definition for enum_join

                         enumerator.c: c
  Enclosing class/module 'rb_mEnumerable' for class Enumerator not known
  ............

Index: lib/rdoc/parsers/parse_c.rb

···

===================================================================
RCS file: /cvs/ruby/src/ruby/lib/rdoc/parsers/parse_c.rb,v
retrieving revision 1.30
diff -U2 -p -r1.30 parse_c.rb
--- lib/rdoc/parsers/parse_c.rb 14 May 2005 02:23:45 -0000 1.30
+++ lib/rdoc/parsers/parse_c.rb 15 Jul 2005 14:30:23 -0000
@@ -228,4 +228,11 @@ module RDoc
         enclosure = @classes[in_module]
         unless enclosure
+ if enclosure = @known_classes[in_module]
+ handle_class_module(in_module, (/^rb_m/ =~ in_module ? "module" : "class"),
+ enclosure, nil, nil)
+ enclosure = @classes[in_module]
+ end
+ end
+ unless enclosure
           warn("Enclosing class/module '#{in_module}' for " +
                 "#{class_mod} #{class_name} not known")

--
Nobu Nakada