Forum: Ruby instance variables available in derived clases

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Richard R. (Guest)
on 2007-01-27 13:28
Hi.

Please read my <a
href="http://richtextblog.blogspot.com/2007/01/ruby-inst...
post</a>, regarding instance variables in derived classes.

Does anyone know a way to make instance variables 'private'?

Cheers,
Rich.
Richard R. (Guest)
on 2007-01-27 13:30
Ah - I see putting html into the posts doesn't work!  The blog url is

http://richtextblog.blogspot.com/2007/01/ruby-inst...

:)
Wolfgang N. (Guest)
on 2007-01-27 13:55
(Received via mailing list)
Richard R. schrieb:
>
Instance variables are part of an object, they are the attributes that
contain
values special for each instance.

 From an OO point of view a derived class can only extend an excisting
class.
This means all objects of the parent class are still relevant for the
child,
plus additional ones.

So it doesn't make any sense to hide these instance variables.

For local working inside a method "local variables" are available.

btw - There is one method in Ruby which I sometimes use for special
cases, and
which breakes the rule, that a derived class should only extend a class,
an not
shorten it's capabilities: "Module#undef_method".

Wolfgang Nádasi-Donner
Richard R. (Guest)
on 2007-01-27 14:08
Hi Wolfgang.  Thanks for your response.

I agree in many cases derived classes just extend an existing class, and
all objects of the parent class are relevent to the children.  In fact,
I have often written quite a base class quite defensively in C#, only to
find that I do indeed need to expose further properties to the derived
ones later.

However, sometimes it is good to keep stuff in the base class private.
What if there was an algorithm in the base class which depended on a
class level instance variable to govern its behaviour?  In ruby, all
derived classes would be allowed to change this variable, possibly
breaking or affecting it's operation (especially if the derived class
was written by a different developer).

In rails, you can set instance variables in the ApplicationController,
and they're automatically available in other controllers.  The behaviour
of ruby I described means that in the other controllers you've got to be
careful not to accidentally overwrite this value.

i.e. We have not explicitly exposed the instance variable in the base
class but in the derived classes we still need to know about the
implementation of the base class.  This kind of breaks the orthogonality
of the design, doesn't it?

Rich.

Wolfgang Nádasi-donner wrote:
> Richard R. schrieb:
>>
> Instance variables are part of an object, they are the attributes that
> contain
> values special for each instance.
>
>  From an OO point of view a derived class can only extend an excisting
> class.
> This means all objects of the parent class are still relevant for the
> child,
> plus additional ones.
>
> So it doesn't make any sense to hide these instance variables.
>
> For local working inside a method "local variables" are available.
>
> btw - There is one method in Ruby which I sometimes use for special
> cases, and
> which breakes the rule, that a derived class should only extend a class,
> an not
> shorten it's capabilities: "Module#undef_method".
>
> Wolfgang Nádasi-Donner
Richard R. (Guest)
on 2007-01-27 18:05
Anyone else got views on this??
Gavin K. (Guest)
on 2007-01-27 18:21
(Received via mailing list)
On Jan 27, 9:05 am, Richard R. <removed_email_address@domain.invalid> wrote:
> Anyone else got views on this??

It looks like Ruby 1.9 will give you the ability to define private
methods in the base class (which may be simple getter/setter methods)
that are accessible to the base class, but not the descendents. Of
course the subclass will still have access to the instance variables -
in my opinion it would be madness to have 'inheritance' without this.
Avdi G. (Guest)
on 2007-01-27 21:44
(Received via mailing list)
To the contrary, it's not madness at all.  It's a legitimate
interpretation of OO principles to say that a private member variable
is private to a class, and should be inaccessible to all clients of
the class - INCLUDING derived classes.  Because your class may be used
as a base class by other programmers in other projects, it's important
to be able to define a stable interface not only to the class's
collaborators (other classes), but to it's children as well.  That way
other programmers can build on your class without worrying about the
changes in implementation.

This is precisely why both C++ and Java make a distinction between
"private" and "protected".  The former is for internal use only by the
class; the latter is the interface the class exposes to it's
descendants.  And public, of course, is the interface it exposes to
the outside world.

Actually, I wouldn't mind seeing this in Ruby.  Ruby's approach is
very flexible and convenient, but it carries with it the danger that
if you derive from a third-party class (like, say, ActiveRecord), you
might inadvertently overwrite a member variable that the base class
uses.

--
Avdi
Richard R. (Guest)
on 2007-01-27 21:50
I'm glad not everyone thinks I'm mad!

Does anyone know a good way to simulate the C++ and Java behaviour in
ruby? I've tried various things, but to no avail (e.g. declaring them as
class-level instance variables in a private block, creating private
accessors etc).

Avdi G. wrote:
"> To the contrary, it's not madness at all"
Vincent F. (Guest)
on 2007-01-27 22:12
(Received via mailing list)
Richard R. wrote:
> I'm glad not everyone thinks I'm mad!
>
> Does anyone know a good way to simulate the C++ and Java behaviour in
> ruby? I've tried various things, but to no avail (e.g. declaring them as
> class-level instance variables in a private block, creating private
> accessors etc).

  Write a C structure holding your variables (it doesn't even have to be
complex: a VALUE array should do). Apart from that, no solution. You
won't change easily a design feature of Ruby ;-)...

  Vince
Wolfgang N. (Guest)
on 2007-01-27 22:40
(Received via mailing list)
Avdi G. schrieb:
> To the contrary, it's not madness at all.  It's a legitimate
> interpretation of OO principles to say that a private member variable
> is private to a class, and should be inaccessible to all clients of
> the class - INCLUDING derived classes.

I think this not possible in Ruby in general, because onybody can change
a class
later.

It's normal practice to write code in Ruby, which changes classes of the
standard library.

 >>>>> Example >>>>>

class Otto
   def show
     puts "here is 'show'"
   end
   private
   def hiddenshow
     puts "here is 'hiddenshow'"
   end
end

o = Otto.new
o.show
o.hiddenshow rescue puts '+++ cannot call hiddenshow'

class Otto
   public :hiddenshow
end

o.hiddenshow

 >>>>> Output >>>>>

here is 'show'
+++ cannot call hiddenshow
here is 'hiddenshow'

 >>>>> EoE >>>>>

Wolfgang Nádasi-Donner
Chris C. (Guest)
on 2007-01-27 22:54
(Received via mailing list)
On 1/27/07, Richard R. <removed_email_address@domain.invalid> wrote:
>
> --
> Posted via http://www.ruby-forum.com/.
>
>
Richard,
Instance variables are private, as you noticed you had to give it a
getter/setter.  What is happening the subclass inherits teh setter
method, and when it is called, it operates on the object it was called
on, not the object it was defined in, because for all intents and
purposes, it was defined in the child class.
Richard R. (Guest)
on 2007-01-28 02:05
Chris, what you say about the method operating on the child class is
true.

However, instance variables are not private (at least not in the
C++/C#/java sense) because derived classes can access them.  If they
were, you wouldn't be able to access them outside the class in which
they were defined.

The example in my blog post
(http://richtextblog.blogspot.com/2007/01/ruby-inst...)

could be written like somehting this in C# (please forgive any typos, as
I've not got a C# compiler on the computer on which I'm typing this)...

public Class Parent
{
  private String var = String.Empty;

  public String ParentMeth()
  {
    return "hello";
  }
}

public Class Child:Parent
{
  public String ChildMeth
  {
    return var;
  }
}


...This shouldn't even compile, as var is not defined in the child.



Chris C. wrote:
> On 1/27/07, Richard R. <removed_email_address@domain.invalid> wrote:
>>
>> --
>> Posted via http://www.ruby-forum.com/.
>>
>>
> Richard,
> Instance variables are private, as you noticed you had to give it a
> getter/setter.  What is happening the subclass inherits teh setter
> method, and when it is called, it operates on the object it was called
> on, not the object it was defined in, because for all intents and
> purposes, it was defined in the child class.
Richard R. (Guest)
on 2007-01-28 02:08
Sorry - the code in my last entry should read...

public Class Parent
{
  private String var = String.Empty;

  public String ParentMeth()
  {
    var = "hello";
    return var;
  }
}

public Class Child:Parent
{
  public String ChildMeth
  {
    return var;
  }
}
Richard R. (Guest)
on 2007-01-28 02:10
Anyway, looks like it's just the way it is in ruby, and I'm going to
have to be careful when I inherit.

Thanks, all.
Trans (Guest)
on 2007-01-28 03:30
(Received via mailing list)
On Jan 27, 2:50 pm, Richard R. <removed_email_address@domain.invalid> wrote:
> I'm glad not everyone thinks I'm mad!
>
> Does anyone know a good way to simulate the C++ and Java behaviour in
> ruby? I've tried various things, but to no avail (e.g. declaring them as
> class-level instance variables in a private block, creating private
> accessors etc).

Use define_method against local vars.

  class X
    x = 100

    define_method(:x) do ; x; end
  end

  X.new.x #=> 10

Generalizing this, perhaps make use an OpenStruct (or Facets'
OpenObject class) and use that for local vars:

  class X
    local = OpenObject.new
    local.x = 10

    define_method(:x) do
      local.x
    end
  end

Personally I think Ruby would do well to make it's method defintion
syntax uniform across def and define_method. Instead it could control
scope via alternate forms of 'do'. In other words, let 'def' be a
method too, or at least a short hand that actually calls
define_method. It would be nice to write:

  class X
    local = OpenObject.new
    local.x = 10

    def x does
      local.x
    end
  end

Where 'does' keeps the scope open.

T.
Avdi G. (Guest)
on 2007-01-28 23:07
(Received via mailing list)
On 1/27/07, Trans <removed_email_address@domain.invalid> wrote:
> Use define_method against local vars.
>
>   class X
>     x = 100
>
>     define_method(:x) do ; x; end
>   end
>
>   X.new.x #=> 10

Whoa!  That's cool!

I love how no matter how long I program in Ruby, I still get pleasant
surprised like this.

Thanks!
unknown (Guest)
on 2007-01-29 03:34
(Received via mailing list)
On Jan 27, 2007, at 7:10 PM, Richard R. wrote:
> Anyway, looks like it's just the way it is in ruby, and I'm going to
> have to be careful when I inherit.

Bertrand Meyer in Object Oriented Software Engineering talks a lot
about the differences between the client and subclass relationships.
If I recall, he argues that a choice to subclass is in effect a choice
to reuse implementation.

Delegation is another way to reuse a class without gaining access to
private information.

Gary W.
This topic is locked and can not be replied to.