Protected methods and class methods


#1

Hi,

is there a way to call a protected method of a class from a static
method of
the same class? Or to acces an instance variable of a class from a
static
method of the same class?

Now I’m facing a problem. I use some static methods as “factory
methods”, to
create “prefilled” class instances. These methods can’t access the
protected
methods of the same class. Is this behavior intentional? Is there clean
solution to this problem? If not, how can I work around this problem?
This is
a public class, so I don’t want to add other params to initialize.

I get this error

irb(main):032:0> Info.fromBytes("\010\008")
NoMethodError: protected method length=' called for #<Info:0x300c3b70 @length=nil, @typeID=8> from (irb):23:infromBytes’

with this class

class Info
def initialize(typeID)
@typeID = typeID
@length = nil
end

attr_reader :typeID

def length
  if @length.nil?
    @length = veryLongMathCalcs()
  end
  return @length
end

def Info.fromBytes(bytes)
  typeID = bytes[0, 1].unpack("c")[0]
  length = bytes[1, 1].unpack("c")[0]

  info = Info.new(typeID)
  info.length = length  ## <<< this is the error!

  return info
end

protected
attr_writer :length

end


#2

On Sat, 2006-01-21 at 04:34 +0900, Gioele B. wrote:

Now I’m facing a problem. I use some static methods as “factory methods”, to
create “prefilled” class instances. These methods can’t access the protected
methods of the same class. Is this behavior intentional?

I believe so. Because the class Info is itself an instance of Class,
while the instance is an instance of Info, which is entirely unrelated
to Class (apart from the common ancestor, Object). So there’s no reason
for protected instance methods on Info to be available to methods on the
class itself.

(I think static methods are usually referred to as class methods in
Ruby. nothing is static here).

Access modifiers can be pretty surprising depending where you’re coming
from. Check out (if you haven’t already):

http://www.whytheluckystiff.net/ruby/pickaxe/html/tut_classes.html#S4

Is there clean solution to this problem? If not, how can I work around this
problem? This is a public class, so I don’t want to add other params
to initialize.

I get this error

irb(main):032:0> Info.fromBytes("\010\008")
NoMethodError: protected method length=' called for #<Info:0x300c3b70 @length=nil, @typeID=8> from (irb):23:infromBytes’

with this class

[ … snipped …]

Maybe try this workaround. I’ve also changed a few things to be more
‘Rubyish’, but you can just ignore that if you like :slight_smile:

class Info
def initialize(type_id)
@type_id = type_id
@length = nil
end

attr_reader :type_id

def length
@length ||= very_long_math_calcs
end

def Info.from_bytes(bytes)
type_id = bytes[0,1].unpack(“c”)[0]
len = bytes[1,1].unpack(“c”)[0]

info = Info.new(type_id)
info.instance_eval { self.length = len }  ## <<< changed!

# or (if you don't care about encapsulation here):
# info.instance_eval { @length = len }

info

end

maybe don’t need this now?

protected
attr_writer :length
end

Noticed a potential error in your input - \008 isn’t valid octal :slight_smile:

p Info.from_bytes("\010\015")
#=> #<Info:0xb7f7b228 @length=13, @type_id=8>

Hope that helps,
Ross


#3

On Mon, 2006-01-23 at 02:56 +0900, Gioele B. wrote:

class itself.
Instead it makes sense to me to be able to use Info protected methods from
Info class methods. I see no need for ‘Class’ methods to be able to use
protected members of an arbitrary class, but this is a particular case! Both
methods are strictly related to Info (and its subclasses, but this is just a
detail).

Yes, I can see the logic in that, and I don’t disagree that it’d
probably make sense in some respects, but now I’ve become more familiar
with Ruby I think I probably would find it surprising if protected
methods worked that way. Things are often more simple (and elegant) than
you’d imagine I suppose…

Maybe try this workaround.

info = Info.new(type_id)
info.instance_eval { self.length = len }  ## <<< changed!

Yes, it worked fine. Just I’m not so happy when I have to use *_eval :frowning: I feel
like cheating. Anyway it is better to have such a shortcut than not :slight_smile:

Definitely :slight_smile:


#4

On Saturday 21 January 2006 01:46, Ross B. wrote:

On Sat, 2006-01-21 at 04:34 +0900, Gioele B. wrote:

Now I’m facing a problem. I use some static methods as “factory methods”,
to create “prefilled” class instances. These methods can’t access the
protected methods of the same class. Is this behavior intentional?

I believe so. Because the class Info is itself an instance of Class,
while the instance is an instance of Info, which is entirely unrelated
to Class (apart from the common ancestor, Object). So there’s no reason
for protected instance methods on Info to be available to methods on the
class itself.
Instead it makes sense to me to be able to use Info protected methods
from
Info class methods. I see no need for ‘Class’ methods to be able to use
protected members of an arbitrary class, but this is a particular case!
Both
methods are strictly related to Info (and its subclasses, but this is
just a
detail).

(I think static methods are usually referred to as class methods in
Ruby. nothing is static here).
Ah, my C++ heritage :slight_smile:

Maybe try this workaround.

info = Info.new(type_id)
info.instance_eval { self.length = len }  ## <<< changed!

Hope that helps,
Ross
Yes, it worked fine. Just I’m not so happy when I have to use *_eval :frowning:
I feel
like cheating. Anyway it is better to have such a shortcut than not :slight_smile: