Class and Iterator Design Question

This may be a silly design question, but I always balk at
the right answer when I am confronted with it.

I have a class that manages a list and users need to iterate over that list.
The way I see it, I have to basic alternatives:

  # Give user access to the array and let them iterate over Array
  class Pea
    attr_reader :pods
  end
  Pea.new.pods.each { |pod| ..do stuff.. }

or

  # Provide a custom iterator
  class Pea
    def each_pod
      @pods.each { |pod| yield pod }
    end
  end
  Pea.new.each_pod { |pod| ..do stuff.. }
end

In other words, for classes that manage a list of items,
do people prefer to see a custom iterator, such as #each_<item>,
or do they prefer getting back an array and iterating
over it themselves, such as #<items>.each?

  Pea.new.each_pod { |pod| ..do stuff.. }
  Pea.new.pods.each { |pod| ..do stuff.. }

Cheers

···

--
Jim Freeze

Jim Freeze wrote:

This may be a silly design question, but I always balk at the right
answer when I am confronted with it.

I have a class that manages a list and users need to iterate over
that list. The way I see it, I have to basic alternatives:

# Give user access to the array and let them iterate over Array class
Pea attr_reader :pods end Pea.new.pods.each { |pod| ..do stuff.. }

or

# Provide a custom iterator class Pea def each_pod @pods.each { |pod|
yield pod } end end Pea.new.each_pod { |pod| ..do stuff.. } end

In other words, for classes that manage a list of items, do people
prefer to see a custom iterator, such as #each_<item>, or do they
prefer getting back an array and iterating over it themselves, such
as #<items>.each?

Pea.new.each_pod { |pod| ..do stuff.. } Pea.new.pods.each { |pod|
..do stuff.. }

Encapsulate, encapsulate, encapsulate!
I prefer not exposing the innards.
Define each, mixin Enumerator and let Ruby do it's magic.
Cheers,
V.-

···

____________________________________________________________________
http://www.freemail.gr - äùñåÜí õðçñåóßá çëåêôñïíéêïý ôá÷õäñïìåßïõ.
http://www.freemail.gr - free email service for the Greek-speaking.

This may be a silly design question, but I always balk at
the right answer when I am confronted with it.

I have a class that manages a list and users need to iterate over that list.
The way I see it, I have to basic alternatives:

# Give user access to the array and let them iterate over Array
class Pea
   attr_reader :pods
end
Pea.new.pods.each { |pod| ..do stuff.. }

Which exposes implementation somewhat, but....

or

# Provide a custom iterator
class Pea
   def each_pod
     @pods.each { |pod| yield pod }
   end

      # Maybe:-
      alias :each :each_pod

end
Pea.new.each_pod { |pod| ..do stuff.. }
end

In other words, for classes that manage a list of items,
do people prefer to see a custom iterator, such as #each_<item>,
or do they prefer getting back an array and iterating
over it themselves, such as #<items>.each?

Pea.new.each_pod { |pod| ..do stuff.. }
Pea.new.pods.each { |pod| ..do stuff.. }

I'd expect
    Pea.new.each{ |pod| ... ]

because you might change your list to a Set or tree or soemthing
later. Unless you normally iterate over something else... (But having said that, I'd expect a Pod to contain Peas :-)!)

Cheers
--
Jim Freeze

         Hugh

···

On Wed, 28 Sep 2005, Jim Freeze wrote:

Don't you want peas in a pod and not the other way around :slight_smile:

I think either is fine with a couple changes:

alternative #1: in the docs say that #pods returns an
Enumerable not an Array. This gives you the freedom to change
the implementation to use a Set or some other Enumerable to
hold the pods.

alternative #2: as long as you don't have multiple each
methods, call the method #each instead of #each_pod and include
Enumerable.

···

--- Jim Freeze <jim@freeze.org> wrote:

This may be a silly design question, but I always balk at
the right answer when I am confronted with it.

I have a class that manages a list and users need to iterate
over that list.
The way I see it, I have to basic alternatives:

  # Give user access to the array and let them iterate over
Array
  class Pea
    attr_reader :pods
  end
  Pea.new.pods.each { |pod| ..do stuff.. }

or

  # Provide a custom iterator
  class Pea
    def each_pod
      @pods.each { |pod| yield pod }
    end
  end
  Pea.new.each_pod { |pod| ..do stuff.. }
end

In other words, for classes that manage a list of items,
do people prefer to see a custom iterator, such as
#each_<item>,
or do they prefer getting back an array and iterating
over it themselves, such as #<items>.each?

  Pea.new.each_pod { |pod| ..do stuff.. }
  Pea.new.pods.each { |pod| ..do stuff.. }

Cheers
--
Jim Freeze

__________________________________
Yahoo! Mail - PC Magazine Editors' Choice 2005

This may be a silly design question, but I always balk at
the right answer when I am confronted with it.

I don't think this is a silly question at all. I'm having to deal with it myself right now. I never seem to come up with the same answer twice in a row.

[snip]

In other words, for classes that manage a list of items,
do people prefer to see a custom iterator, such as #each_<item>,
or do they prefer getting back an array and iterating
over it themselves, such as #<items>.each?

  Pea.new.each_pod { |pod| ..do stuff.. }
  Pea.new.pods.each { |pod| ..do stuff.. }

There is another possibility, have the pods accessor return a (shallow) copy of the original.

I've done all three.

These days I just return the array and let the user do what they want. This saves me a lot of work at the risk of potentially ruining the integrity of the object structure. Seemed like a good idea at the time, but putting it that way... :slight_smile: Actually I don't think it is that bad. If I was worried, I'd return a copy. I don't think I'd go the each_pod route. Who knows what I'm going to think tomorrow.

Cheers,
Bob

···

On Sep 27, 2005, at 11:49 AM, Jim Freeze wrote:

Cheers
--
Jim Freeze

----
Bob Hutchison -- blogs at <http://www.recursive.ca/hutch/&gt;
Recursive Design Inc. -- <http://www.recursive.ca/&gt;
Raconteur -- <http://www.raconteur.info/&gt;

Hi --

···

On Wed, 28 Sep 2005, Jim Freeze wrote:

This may be a silly design question, but I always balk at
the right answer when I am confronted with it.

I have a class that manages a list and users need to iterate over that list.
The way I see it, I have to basic alternatives:

# Give user access to the array and let them iterate over Array
class Pea
   attr_reader :pods
end
Pea.new.pods.each { |pod| ..do stuff.. }

or

# Provide a custom iterator
class Pea
   def each_pod

Why not just call that #each? (And, as others have said, possibly
include Enumerable, though only if you need the other Enumerable
stuff).

David

--
David A. Black
dblack@wobblini.net

Hi, Jim. Don't worry. All design questions are silly, but I don't mind pontificating. :slight_smile:

I think I'd return an Array or Set or something.

1. It's just easier to write the Pod class that way (as you showed).
2. It's just easier to use the Pod class that way. Array & Set map more closely to what you're exposing (a finite list with random access) and provide methods that might be helpful to the user, such as #+ and #empty?, that Enumerable doesn't provide.

However, as a rule of thumb, I'm lazy, so I may be biased.

If you don't like the idea of exposing your internal Array or Set, you're welcome to wrap it in some sort of Decorator class (say, to make it immutable) before returning it -- that's a common Java idiom (*ahem* I mean "pattern"; I must not have been served the right Kool-Aid). The awfully cool APIs will actually return a "live" Array, where modifying the array or its contents through typical-looking Array methods actually triggers the backend logic to do its thang.

Devin

Jim Freeze wrote:

···

This may be a silly design question, but I always balk at
the right answer when I am confronted with it.

I have a class that manages a list and users need to iterate over that list.
The way I see it, I have to basic alternatives:

# Give user access to the array and let them iterate over Array
class Pea
   attr_reader :pods
end
Pea.new.pods.each { |pod| ..do stuff.. }

or

# Provide a custom iterator
class Pea
   def each_pod
     @pods.each { |pod| yield pod }
   end
end
Pea.new.each_pod { |pod| ..do stuff.. }
end

In other words, for classes that manage a list of items,
do people prefer to see a custom iterator, such as #each_<item>,
or do they prefer getting back an array and iterating
over it themselves, such as #<items>.each?

Pea.new.each_pod { |pod| ..do stuff.. }
Pea.new.pods.each { |pod| ..do stuff.. }

Cheers
--
Jim Freeze

Wow, thanks for all the responses.

First, duh, yeah, I got it backwards (pod and peas should be reversed.)

So, from what I have read, we have:

  1. Pod.new.each { |pea| ... }
  2. Pod.new.peas.each { |pea| ... }

#2 compromises the OO integrity. I understand that, but
I guess I am bugged by #1 where Pod.new.each yields a 'pea'.
If I see a Pod.each, I kind of expect to get a 'pod' back, not
a pea. That is the reason I did #each_pod.

Any comments on this?

···

--
Jim Freeze

Good question.

  1) Pod.each { |pea| ... }. There is no indication what each will yield.
  2) In some cases, there are multiple things that can be iterated through.
      Maybe a better example:

Car.new.each_wheel { |wheel| ... }
Car.new.each_headlight { |light| ... }

Which directs me to do something like:
Car.new.wheels.each ...
Car.new.headlights.each ...

which is back to the un-encapsulation that has been previously mentioned.

···

On 9/27/05, David A. Black <dblack@wobblini.net> wrote:

Why not just call that #each? (And, as others have said, possibly
include Enumerable, though only if you need the other Enumerable
stuff).

--
Jim Freeze

a = [ 1, "s", 3.0, [1,2] ]
a.each { |el| ... }

What do you expect "el" to be?

Hi --

Wow, thanks for all the responses.

First, duh, yeah, I got it backwards (pod and peas should be reversed.)

So, from what I have read, we have:

1. Pod.new.each { |pea| ... }
2. Pod.new.peas.each { |pea| ... }

#2 compromises the OO integrity. I understand that, but
I guess I am bugged by #1 where Pod.new.each yields a 'pea'.
If I see a Pod.each, I kind of expect to get a 'pod' back, not
a pea. That is the reason I did #each_pod.

Any comments on this?

I think if you're using pod/peas as a container/elements example, then
you should accept that the container contains the elements :slight_smile:

   pod.each {|pea| ... }

has enough pod/pea semantics to make it clear. In fact, this:

   pod.each_pea {|pea| ... }

seems a bit redundant to me. (Unless there's something else that a
pod might iterate over, similar to String#each vs. String#each_byte.
Of course, lots of people wish that String#each did what
String#each_byte does :slight_smile:

David

···

On Wed, 28 Sep 2005, Jim Freeze wrote:

--
David A. Black
dblack@wobblini.net

I still think the second way is just fine if you just say in
the docs that #wheels and #headlights returns an Enumerable.
Or if you really wanted to make sure there is no abuse, just
make #wheels and #headlights return an Enumerator (naming
@wheels.each and @headlights.each as the each methods). Or if
you wanted to be v1.9-like make #each_wheel and #each_headlight
return an Enumerator when no block is supplied.

···

--- Jim Freeze <jim@freeze.org> wrote:

On 9/27/05, David A. Black <dblack@wobblini.net> wrote:
> Why not just call that #each? (And, as others have said,
possibly
> include Enumerable, though only if you need the other
Enumerable
> stuff).

Good question.

  1) Pod.each { |pea| ... }. There is no indication what each
will yield.
  2) In some cases, there are multiple things that can be
iterated through.
      Maybe a better example:

Car.new.each_wheel { |wheel| ... }
Car.new.each_headlight { |light| ... }

Which directs me to do something like:
Car.new.wheels.each ...
Car.new.headlights.each ...

which is back to the un-encapsulation that has been
previously mentioned.

__________________________________
Yahoo! Mail - PC Magazine Editors' Choice 2005

In article <5cd596d6050927105154fafd66@mail.gmail.com>,

···

Jim Freeze <jim@freeze.org> wrote:

Wow, thanks for all the responses.

First, duh, yeah, I got it backwards (pod and peas should be reversed.)

So, from what I have read, we have:

1. Pod.new.each { |pea| ... }
2. Pod.new.peas.each { |pea| ... }

#2 compromises the OO integrity. I understand that, but
I guess I am bugged by #1 where Pod.new.each yields a 'pea'.
If I see a Pod.each, I kind of expect to get a 'pod' back, not
a pea. That is the reason I did #each_pod.

Any comments on this?

what if youcalled the iterator function each_pea?

  Pod.new.each_pea {|pea| ... }

Of course then certain Enumerable magic won't work...

But if you consider that a Pod is a container for Peas then even the 'each'
iterator makes sense, I think.

Phil

Ok, so you convinced me. Use #each. But, there still does not seem
to be a clear answer for an object having multiple containers.
Granted, there is precedence with things like #each_byte. But,
I wonder if it is better to use an argument to each.
Here are four methods that I can see as potential solutions:

  1. obj.each(:container) { |element| ... }
  2. obj.each_container { |element| ... }
  3. obj.container.each { |element| ... }
  4. obj.container; obj.each { |element| ... }

No. (4) simply sets an internal state variable to indicate which container
#each uses. Not pretty, and not thread safe, but permits Enumerable to
be used.

Do you have a preference for 1-4 or another solution?

···

On 9/27/05, David A. Black <dblack@wobblini.net> wrote:

I think if you're using pod/peas as a container/elements example, then
you should accept that the container contains the elements :slight_smile:

   pod.each {|pea| ... }

has enough pod/pea semantics to make it clear. In fact, this:

   pod.each_pea {|pea| ... }

seems a bit redundant to me. (Unless there's something else that a
pod might iterate over, similar to String#each vs. String#each_byte.
Of course, lots of people wish that String#each did what
String#each_byte does :slight_smile:

--
Jim Freeze

Concerning multiple containers for an object:

Here are four methods that I can see as potential solutions:

  1. obj.each(:container) { |element| ... }
  2. obj.each_container { |element| ... }
  3. obj.container.each { |element| ... }
  4. obj.container; obj.each { |element| ... }

No. (4) simply sets an internal state variable to indicate which container
#each uses. Not pretty, and not thread safe, but permits Enumerable to
be used.

I am curious what people think about these methods.
To all you pattern experts, is there a pattern for this
situation?

···

On 9/27/05, Jim Freeze <jim@freeze.org> wrote:

--
Jim Freeze

Jim Freeze wrote:

Ok, so you convinced me. Use #each. But, there still does not seem
to be a clear answer for an object having multiple containers.
Granted, there is precedence with things like #each_byte. But,
I wonder if it is better to use an argument to each.

I think people should require 'enumerator' for this, it creates Kernel#enum_for, so you can create a Enumerable::Enumerator instance
for every iterator:

somethings = obj.enum_for(:each_something)

Then you can iterate

somethings.each do |something|
   # ...
end

and because Enumerator includes Enumerable, you can get an
array as well by calling

somethings_array = somethings.to_a

without breaking encapsulation.

This solves all your problems, and you only have to create an arbitrary named iterator method. I think enumerator should become part of Standard Ruby, because it's so damn useful.

Let me suggest yet another possibility, borrowing from Hash:

obj.each { | element, container | ... }

You could even combine that with 1?

I like Mine and #1 .

···

On 27-Sep-05, at 12:24 PM, Jim Freeze wrote:

On 9/27/05, Jim Freeze <jim@freeze.org> wrote:

Concerning multiple containers for an object:

Here are four methods that I can see as potential solutions:

  1. obj.each(:container) { |element| ... }
  2. obj.each_container { |element| ... }
  3. obj.container.each { |element| ... }
  4. obj.container; obj.each { |element| ... }

No. (4) simply sets an internal state variable to indicate which container
#each uses. Not pretty, and not thread safe, but permits Enumerable to
be used.

I am curious what people think about these methods.
To all you pattern experts, is there a pattern for this
situation?

--
Jim Freeze

Concerning multiple containers for an object:

Here are four methods that I can see as potential solutions:

  1. obj.each(:container) { |element| ... }
  2. obj.each_container { |element| ... }
  3. obj.container.each { |element| ... }
  4. obj.container; obj.each { |element| ... }

No. (4) simply sets an internal state variable to indicate which
container #each uses. Not pretty, and not thread safe, but permits
Enumerable to
be used.

4. is definitely a non option. That's in the same league as containers glued together with an iterator (not #each). That's simply a don't do. It's thread unsafe and error prone. I strongly favor 3 with an optional variant of a read only proxy returned (using Enumerator for example). 2 is ok also and maybe 1, too. Normally OO suggests to have separate methods but since you can easily say this in Ruby 1 seems ok, too:

def each(cont, &b)
  instance_variable_get("@#{cont}").each(&b)
  self
end

IOW you don't need to touch this method when you add more containers.

I am curious what people think about these methods.
To all you pattern experts, is there a pattern for this
situation?

Not that I'm a pattern expert... I'll throw in my 0.02EUR anyway:

- My rule of thumb, if the object's main task is to be a container, give it an each method - this makes usage for clients convenient (example TreeNode, each will iterate child nodes).

- If there are several containers contained :slight_smile: then make them accessible and let clients work with them. You save yourself a lot of hassle and name collisions (KISS).

- Remember: there's no way to protect the internals of an instance: if someone wants to screw up your instance he can always use send, instance_eval, instance_variable_get and *_set to access your innards.

Kind regards

    robert

···

Jim Freeze <jim@freeze.org> wrote:

On 9/27/05, Jim Freeze <jim@freeze.org> wrote:

I believe that's the plan. I think all the standard iterators are going to start returning enumerator objects when called without a block.

James Edward Gray II

···

On Sep 28, 2005, at 5:10 AM, Florian Frank wrote:

I think enumerator should become part of Standard Ruby, because it's so damn useful.

Thanks Robert. That's good advice.

···

On 9/27/05, Robert Klemme <bob.news@gmx.net> wrote:

- My rule of thumb, if the object's main task is to be a container, give it
an each method - this makes usage for clients convenient (example TreeNode,
each will iterate child nodes).

- If there are several containers contained :slight_smile: then make them accessible
and let clients work with them. You save yourself a lot of hassle and name
collisions (KISS).

--
Jim Freeze