Start_with

Can someone explain why this doesn’t work?

class Person
attr_accessor :firstName
P=[]
def initialize
P << self
end
def self.find_person(part)
P.each {|e| if e.firstName.start_with(part) then return e end}
end
end

u=Person.new
u.firstName=“Ron”
r=Person.new
r.firstName=“Bob”

q=Person.find_person(“Ro”)
puts q.firstName

Hi –

On Tue, 22 Sep 2009, Rong wrote:

P.each {|e| if e.firstName.start_with(part) then return e end}
You mean start_with? (with question mark).

Also, you’ve got a bug. The #each method returns its receiver. That
means that if nothing triggers the return inside the block, you’ll get
back the whole P array. See below…

end
end

u=Person.new
u.firstName=“Ron”
r=Person.new
r.firstName=“Bob”

q=Person.find_person(“Ro”)
puts q.firstName

p Person.find_person(“nobody”)

Output: [#<Person:0x1ee628 @firstName=“Ron”>, #<Person:0x1ee5d8
@firstName=“Bob”>]

What you want is:

def self.find_person(part)
P.find {|e| e.firstName.start_with(part) }
end

which will return nil if nothing is found. (Also, first_name would be
more idiomatic than firstName, as a variable name.)

I’ve got reservations about using a constant as a modifiable array
like you’re doing, but one (or two) thing(s) at a time :slight_smile:

David

Thanks David. I sent you a tweet.

I tried changing the array to an instance variable but the code won’t
work.

Hi –

On Tue, 22 Sep 2009, Rong wrote:

I tried changing the array to an instance variable but the code won’t
work.

You’d have to make it an instance variable of the class itself, like
this:

class Person
@people = []
def self.people
@people
end

 def initialize
   self.class.people << self
 end

end

You were very considerate in using a tweet instead of this mailing
list to point out that, in spite of my saying I had reservations about
using a constant the way your code did, I had done exactly the same
thing on page 108 of my book :slight_smile: So let me try to return the kindness
by explaining my reservations.

The main issue at least to be aware of is what happens when you
inherit:

class Person
P = []
def initialize
P << self
end
end

class Rubyist < Person
end

r = Rubyist.new
p Person::stuck_out_tongue: # => [#Rubyist:0x2202a4]

In other words, you end up using the same constant for all the
subclasses, and thus getting what you might consider false positives
(depending on exactly what you want to count). This is also why using
a class variable is a problem in this kind of role: it will also be
the same variable down the class hierarchy.

The other issue is just the question of using a “constant” for
something that changes, like this array. I don’t consider that
to be automatically bad (and it’s very different from re-assigning to
a constant, which is really non-constant), but it feels perhaps like
a looser fit than using an instance variable, as in my first example
above. The instance variable is designed to maintain state on a
per-object (in this case, per class-object) basis, which a constant
can do but which isn’t their main or most “natural” role.

David