start_with

R

Rong

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
 
D

David A. Black

Hi --

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}

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


David
 
R

Rong

Thanks David. I sent you a tweet.

Hi --

Can someone explain why this doesn't work?
class Person
=A0attr_accessor :firstName
=A0P=3D[]
=A0def initialize
=A0 =A0P << self
=A0end
=A0def self.find_person(part)
=A0 =A0P.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....
=A0 =A0end
=A0end

=A0q=3DPerson.find_person("Ro")
=A0puts q.firstName

p Person.find_person("nobody")

Output: [#<Person:0x1ee628 @firstName=3D"Ron">, #<Person:0x1ee5d8
@firstName=3D"Bob">]

What you want is:

=A0 =A0def self.find_person(part)
=A0 =A0 =A0P.find {|e| e.firstName.start_with(part) }
=A0 =A0end

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

David

--
David A. Black, Director
Ruby Power and Light, LLC (http://www.rubypal.com)
Ruby/Rails training, consulting, mentoring, code review
Book: The Well-Grounded Rubyist (http://www.manning.com/black2)
 
R

Rong

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

Hi --

Can someone explain why this doesn't work?
class Person
=A0attr_accessor :firstName
=A0P=3D[]
=A0def initialize
=A0 =A0P << self
=A0end
=A0def self.find_person(part)
=A0 =A0P.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....
=A0 =A0end
=A0end

=A0q=3DPerson.find_person("Ro")
=A0puts q.firstName

p Person.find_person("nobody")

Output: [#<Person:0x1ee628 @firstName=3D"Ron">, #<Person:0x1ee5d8
@firstName=3D"Bob">]

What you want is:

=A0 =A0def self.find_person(part)
=A0 =A0 =A0P.find {|e| e.firstName.start_with(part) }
=A0 =A0end

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

David

--
David A. Black, Director
Ruby Power and Light, LLC (http://www.rubypal.com)
Ruby/Rails training, consulting, mentoring, code review
Book: The Well-Grounded Rubyist (http://www.manning.com/black2)
 
D

David A. Black

Hi --

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 :) 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::p # => [#<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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,142
Latest member
arinsharma
Top