Private visibility should be removed from Ruby 2 [was: Caveats with #method_missing]

Discussion in 'Ruby' started by Tomasz Wegrzanowski, Oct 2, 2006.

  1. On 10/1/06, David Vallner <> wrote:
    > On Mon, 2006-10-02 at 05:00 +0900, Tomasz Wegrzanowski wrote:
    > > I have an modest proposal - can't we just get rid of private methods
    > > completely in Ruby 2 ?
    > > [snip justification]

    >
    > In my code, I use private methods for helper operations to dissect an
    > algorithm into separate steps - these serve only to give fragments of
    > code a name, not encapsulate any standalone functionality. Calling them
    > out-of-order from client code would usually clobber an object's
    > internals beyond repair.
    >
    > In all OO systems, the private / public distinction is to hide
    > information about the inner workings of a class. While instance
    > variables are obviously such information, often also how a class
    > achieves what it does qualifies.
    >
    > If you have to call __methods__ directly, that's one more indication
    > that you're Doing Something Weird.
    >
    > The difficulty in unit-testability is more of a failure on the side of
    > the test framework. Including a "whitebox" mode in Test::Unit
    > (generating public wrappers for private methods of tested classes) would
    > be a more concise solution to this problem.
    >
    > The feature of private methods in Ruby is one I like. It's an
    > encapsulation safety net as opposed to a roadblock in Ruby, but makes it
    > more apparent in code that something out-of-the-ordinary is being done.
    >
    > I might be biased, since I'm opposed to strong usage of Ruby's
    > metaprogramming capacities in "serious" code, at least without
    > encapsulating such code very tightly. But removing all method-level
    > encapsulation to facilitate meta hacks or get rid of some scenarios when
    > they are necessary seems just overkill.


    It almost sounds that you're using Ruby as only a "better Java" :)
    Many people consider Smalltalk-style OO and metaprogramming
    in Ruby extremely important.

    Back to the point. It is very unusual for OO system to have
    public/private distinction.
    (http://www.approximity.com/ruby/Comparison_rb_st_m_java.html)
    *The* OO language Smalltalk did not have it, and other OO systems
    like Objective C, CLOS, Perl 5 and Python do not have it either.

    The only listed languages that do are C++, Java and Ruby.
    Conceptual model behind C++ is very far from Smalltalk-style OO.
    In fact it has very little to do with OO, C++ objects are little
    more than abstract data types. There is nothing remotely similar
    to OO "message passing", the "methods" are merely nicely
    namespaced functions with some hacks for "inheritance" (and you
    need to turn inheritance support explicitly using virtual keyword,
    by default you get nothing more than nicely namespaced functions).
    There is no such thing as interface of an objects. The same object
    is going to behave in completely different way depending on
    context - a single method is going to do something completely different
    depending on whether you call it from object's class, subclass of it
    (and there is public and private inheritance, that changes object's
    interface), or a different place.
    The same method can behave differently depending on type of variable
    to which object is assigned - if Foo is a subclass of Bar, then the
    following code:
    Foo *f = new Foo();
    Bar *b = f;
    b->bar();
    f->bar(); // bar redefined in Foo, bar not virtual
    can do two completely different things.
    The model is already so complicated, that adding private/public
    distinction to everything doesn't affect it much.

    Java object model is halfway between C++ and Smalltalk.
    Objects still do not have single clear interfaces. If Foo is
    a subclass of Bar, and both have a private method bar(),
    then calls to some_foo_obj->bar() will behave differently
    depending on whether the call was done from methods declared in
    Foo class or from methods declared in Bar class.
    Private methods are also *automatically final*, and therefore
    they cannot be overriden. So private methods in Java still
    have more to do with global functions than with regular methods.
    Fortunately they at least got rid of private inheritance.

    I'm not saying "private methods" are useless in C++/Java.
    They are simply not methods at all. They are nicely encapsulated
    global helper functions for implementation of a class. They have
    class-specific namespace and cannot be overriden, so a class
    can define whatever private functions it wants to, and they do not
    affect anything else.

    The only language left that has Smalltalk-style OO and this kind of
    access controls in Ruby. Instead of objects having single interface
    like Smalltalk or multiple interfaces like C++/Java, Ruby objects has
    exactly two - one for normal method calls, and a second for "implicit self"
    method calls. And we don't get much - defining method "private"
    doesn't provide much "protection" as there is a single namespace
    for all methods, so it can be accidentally redefined in a subclass.
    On the other hand methods cannot call private methods of different
    object of the same class (or its subclasses), so objects with less-defined
    interface and hidden implementation need to either hack around
    access control inside own methods (ugly), or to have their internals public.
    A very simple and very common example would be == method
    that checks if both objects have the same class, and if so,
    whether their fields are identical.

    While writing this reply I found something that really surprised me.
    It is possible to get real private variables in Ruby, with private
    per-class namespaces, not overridable, and working with other objects
    of the same class, just like in C++/Java, by a few lines of
    metaprogramming.
    They are much better at encapsulation control than the official classes.

    Here's a snippet:

    class Class
    def define_private_method(name, &blk)
    define_method:)xyzzy, &blk)
    class_variable_set("@@#{name}".to_sym, instance_method:)xyzzy))
    remove_method :xyzzy
    end
    end
    class Foo
    define_private_method:)bar) { puts "Hello" }
    # Not the prettiest syntax possible.
    # A slightly different idea:
    # @@bar.call(self, *arguments)
    def foo; @@bar.bind(self).call() end
    end
    Foo.new.foo

    By movinc @@bar around or keeping it in some other variable (like
    file-local, or package-local) we can easily implement advanced
    visibility
    control.

    So I think it would be good idea to have method visibility controls
    removed because:
    * They do not fit Smalltalk-style OO, so removing them would make
    everything simpler
    * We get very limited benefit from them due to lack of C++/Java-style
    features like per-class namespaces for private methods (or even
    instance variables), and ability to call private methods of other
    objects of the same type
    * They make metaprogramming, unit testing etc. more difficult
    * They provide very limited control over visibility
    * Very simple Ruby metaprogramming gives us much more powerful private
    variables anyway.
    * I think it's unlikely for current visibility control system to lead
    to any cool things. As far as I can tell it was never used for
    implementing any magic. There is no obvious way to add any features
    (even to get them to the level of that metaprogramming snippet)
    without greatly complicating the language.
    * Ruby 2 is exactly the right time for doing such changes

    --
    Tomasz Wegrzanowski [ http://t-a-w.blogspot.com/ ]
     
    Tomasz Wegrzanowski, Oct 2, 2006
    #1
    1. Advertising

  2. Tomasz Wegrzanowski

    Trans Guest

    Tomasz Wegrzanowski wrote:

    > [snip]


    > So I think it would be good idea to have method visibility controls
    > removed because:
    > * They do not fit Smalltalk-style OO, so removing them would make
    > everything simpler
    > * We get very limited benefit from them due to lack of C++/Java-style
    > features like per-class namespaces for private methods (or even
    > instance variables), and ability to call private methods of other
    > objects of the same type
    > * They make metaprogramming, unit testing etc. more difficult
    > * They provide very limited control over visibility
    > * Very simple Ruby metaprogramming gives us much more powerful private
    > variables anyway.
    > * I think it's unlikely for current visibility control system to lead
    > to any cool things. As far as I can tell it was never used for
    > implementing any magic. There is no obvious way to add any features
    > (even to get them to the level of that metaprogramming snippet)
    > without greatly complicating the language.
    > * Ruby 2 is exactly the right time for doing such changes


    At times I have had such thoughts too. After all Ruby is largely a
    Document and Test oritented language b/c of it's high degree of
    dynamicisim. There is at least one feature of the private/protected vs.
    public system that is valuable though: you can catch public calls via
    method_missing even when there are private/protected methods defined.
    Eg.

    class X
    def method_missing( name ); name; end
    private
    def bird; "hoot!"; end
    end

    x = X.new
    x.bird #=> "bird"
    x.send:)bird) #=> "hoot!"

    I only recently came to understand this myself and it made a big
    difference in how I handled certain usecases of method_missing. Unless
    you see a better way to hadle this, then I think the private/protected
    vs. public distiguish it useful.

    As a side note, I sure would like to see class/module local methods
    (not part of inheritance chain) if possible.

    T.
     
    Trans, Oct 2, 2006
    #2
    1. Advertising

  3. Re: Private visibility should be removed from Ruby 2 [was: Caveatswith #method_missing]

    --------------enigDE69D55A9FC815C6156E431A
    Content-Type: text/plain; charset=ISO-8859-1
    Content-Transfer-Encoding: quoted-printable

    Tomasz Wegrzanowski wrote:
    > It almost sounds that you're using Ruby as only a "better Java" :)
    > Many people consider Smalltalk-style OO and metaprogramming
    > in Ruby extremely important.
    >=20


    Maybe.

    > Back to the point. It is very unusual for OO system to have
    > public/private distinction.
    > (http://www.approximity.com/ruby/Comparison_rb_st_m_java.html)
    > *The* OO language Smalltalk did not have it, and other OO systems
    > like Objective C, CLOS, Perl 5 and Python do not have it either.
    >=20
    > The only listed languages that do are C++, Java and Ruby.
    >


    They forget Ada, Simula 87, Eiffel...

    > Conceptual model behind C++ is very far from Smalltalk-style OO.


    Smalltalk-style OO isn't the only true one. In fact, object-oriented
    programming is known to have no actual definition.

    > There is nothing remotely similar
    > to OO "message passing",=20


    See above, OO !=3D message passing. And even in Smalltalk, the message
    pass will trigger a method invocation most of the time.

    > the "methods" are merely nicely
    > namespaced functions with some hacks for "inheritance" (and you
    > need to turn inheritance support explicitly using virtual keyword,
    > by default you get nothing more than nicely namespaced functions).


    That's a specific C++ quirk that comes is part historical, part
    intentional. A design policy of C++ is that it should introduce no
    overhead over C unless explicitly stated by the programmer. Vtable
    method dispatch is overhead, that's why it has to be explicitly enabled.

    > There is no such thing as interface of an objects.


    Pure virtual classes.

    > The same object
    > is going to behave in completely different way depending on
    > context - a single method is going to do something completely different=


    > depending on whether you call it from object's class, subclass of it
    > (and there is public and private inheritance, that changes object's
    > interface), or a different place.
    > The same method can behave differently depending on type of variable
    > to which object is assigned - if Foo is a subclass of Bar, then the
    > following code:
    > Foo *f =3D new Foo();
    > Bar *b =3D f;
    > b->bar();
    > f->bar(); // bar redefined in Foo, bar not virtual
    > can do two completely different things.
    > The model is already so complicated, that adding private/public
    > distinction to everything doesn't affect it much.
    >=20


    Once again, C++ quirks which do have a reason, even if you might find
    them unjustified. Also are completely unrelated to the issue of access
    level restriction, except as an "Oh, look, this thing about C++ sucks,
    that's why another thing that's in C++ too sucks."


    > Java object model is halfway between C++ and Smalltalk.
    > Objects still do not have single clear interfaces.


    Can you elaborate on what you expect as a clear interface?

    > If Foo is
    > a subclass of Bar, and both have a private method bar(),
    > then calls to some_foo_obj->bar() will behave differently
    > depending on whether the call was done from methods declared in
    > Foo class or from methods declared in Bar class.


    That's why you use protected on methods you intend to be called in
    subclasses.

    > Private methods are also *automatically final*, and therefore
    > they cannot be overriden. So private methods in Java still
    > have more to do with global functions than with regular methods.


    That's why you use protected on methods you intend to be overridden in
    subclasses.

    > Fortunately they at least got rid of private inheritance.
    >=20


    Eiffelists might disagree. Multiple inheritance, private inheritance,
    and feature renaming are core features of Eiffel's object model as far
    as I know.

    > I'm not saying "private methods" are useless in C++/Java.
    > They are simply not methods at all. They are nicely encapsulated
    > global helper functions for implementation of a class.


    The question is what distinguishes a method from a function. Is it the
    polymorphic dispatch, or being bound to a specific object? In CLOS, it's
    only the former because of multimethods, in other languages polymorphic
    dispatch seems to happen as a consequence of the latter. Once again,
    lacking an actual definition of object-orientation, both approaches can
    be considered equally valid.

    > They have
    > class-specific namespace and cannot be overriden, so a class
    > can define whatever private functions it wants to, and they do not
    > affect anything else.
    >=20


    I consider uncontrolled namespace clobbering such as this a flaw of
    ruby. "Module Foo does weird stuff to module Bar because the author of
    Foo thought they're convenient / more Right (tm) and now my code broke
    when I wanted to add support for Foo." Bugs like that are annoying in
    the least.

    > The only language left that has Smalltalk-style OO and this kind of
    > access controls in Ruby. Instead of objects having single interface
    > like Smalltalk or multiple interfaces like C++/Java, Ruby objects has
    > exactly two - one for normal method calls, and a second for "implicit s=

    elf"
    > method calls.


    I personally think this is a design burp.

    > And we don't get much - defining method "private"
    > doesn't provide much "protection" as there is a single namespace
    > for all methods, so it can be accidentally redefined in a subclass.


    Separating private methods in a separate namespace has been thought for
    Ruby 2.0. No idea what happened to the proposal.

    > On the other hand methods cannot call private methods of different
    > object of the same class (or its subclasses), so objects with less-defi=

    ned
    > interface and hidden implementation need to either hack around
    > access control inside own methods (ugly), or to have their internals
    > public.


    Protected. I don't like calling private methods on other objects in Java
    either and find it one of the C++ quirks that shouldn't have made it
    into that language.

    > A very simple and very common example would be =3D=3D method
    > that checks if both objects have the same class, and if so,
    > whether their fields are identical.
    >=20


    If an operation can't be implemented only communicating with another
    object's public interface, there's something wrong with the design. You
    may differ on this point, I'll admit it's one of taste more than
    anything else.

    > [snip metaprogramming code]
    >=20
    > So I think it would be good idea to have method visibility controls
    > removed because:
    > * They do not fit Smalltalk-style OO, so removing them would make
    > everything simpler


    Ruby isn't Smalltalk.

    > * We get very limited benefit from them due to lack of C++/Java-style
    > features like per-class namespaces for private methods (or even
    > instance variables), and ability to call private methods of other
    > objects of the same type


    I argue that it would be better to just fix those design burps instead
    of removing a language feature.

    > * They make metaprogramming, unit testing etc. more difficult


    More verbose. Not really difficult - at least for metaprogramming you
    need a miner helmet for when you need to bang your head against a wall
    anyway.

    > * They provide very limited control over visibility


    I can't imagine it could be improved without making them not the
    advisory "you shouldn't do this" tags they are now.

    > * Very simple Ruby metaprogramming gives us much more powerful private
    > variables anyway.


    Remove a core language feature only to get umpty modules reemulating it
    in incompatible ways?

    > * I think it's unlikely for current visibility control system to lead
    > to any cool things. As far as I can tell it was never used for
    > implementing any magic. There is no obvious way to add any features
    > (even to get them to the level of that metaprogramming snippet)
    > without greatly complicating the language.


    It's used to tighten up code, make possible bugs due to metaprogramming
    more visible, etc. Not necessarily cool or magical. Mind you, cool and
    magical aren't necessarily good qualities.

    > * Ruby 2 is exactly the right time for doing such changes
    >=20


    The Ruby 1 -> Ruby 2 transition isn't supposed to be in the order of the
    Perl 5 -> Perl 6 one. As far as I know, the changes are mostly touchups
    that fall out of scope for a minor version bump because they address
    some of the core design burps. As far as I know, it's supposed to be as
    little codebreaking a change as necessary. Ruby 2 is not at all the time
    for a keyword removal and object model revamp.

    David Vallner


    --------------enigDE69D55A9FC815C6156E431A
    Content-Type: application/pgp-signature; name="signature.asc"
    Content-Description: OpenPGP digital signature
    Content-Disposition: attachment; filename="signature.asc"

    -----BEGIN PGP SIGNATURE-----
    Version: GnuPG v1.4.5 (MingW32)

    iD8DBQFFIFoPy6MhrS8astoRAuhGAJ0Q6BEksykY2bBXnMjO3Hd+9wbxBwCfd50Q
    PQNhHtXjT/lv2MO/uQ09zqM=
    =VLso
    -----END PGP SIGNATURE-----

    --------------enigDE69D55A9FC815C6156E431A--
     
    David Vallner, Oct 2, 2006
    #3
  4. On 10/2/06, Trans <> wrote:
    > Tomasz Wegrzanowski wrote:
    > > * Ruby 2 is exactly the right time for doing such changes

    >
    > At times I have had such thoughts too. After all Ruby is largely a
    > Document and Test oritented language b/c of it's high degree of
    > dynamicisim. There is at least one feature of the private/protected vs.
    > public system that is valuable though: you can catch public calls via
    > method_missing even when there are private/protected methods defined.
    > Eg.
    >
    > class X
    > def method_missing( name ); name; end
    > private
    > def bird; "hoot!"; end
    > end
    >
    > x = X.new
    > x.bird #=> "bird"
    > x.send:)bird) #=> "hoot!"
    >
    > I only recently came to understand this myself and it made a big
    > difference in how I handled certain usecases of method_missing. Unless
    > you see a better way to hadle this, then I think the private/protected
    > vs. public distiguish it useful.


    You'll have to unlearn what you've learned anyway,
    as it gets changed in 1.9, where you get:
    x.send:)bird) #=> :bird

    That's part of the complexity I was talking about.
    There are two very similar operations - "generic message passing",
    and "message passing with implicit self". In Ruby 1.8
    Object#send did the former, in 1.9 it does the latter.
    To do "message passing with implicit self" in 1.9 there is
    a new method x.funcall:)bird).

    But that's not enough. Normal objects can be implemented
    in terms of message_missing. If we let one method name to
    do different things depending on context, we need to extend
    it to message_missing somehow, using private_message_missing
    or some sort of Kernel#implicit_self_context? method that would let
    methods know in what context they have been called.
    Reflection methods are already provided in 3 versions
    (public, protected, private). Somehow Object#singleton_methods
    only lists public singleton methods. I have no idea what private/protected
    singleton methods would be good for, but lack of symetry is somewhat
    disturbing. ( x.singleton_methods lists only redefined methods,
    it's different from (class << x; self; end).methods, so I don't see any
    simple way of emulating private/protected_singleton_methods)

    I have very little idea of what "protected" methods do, as Ruby "private"
    is most similar to Java "protected". It would be highly disturbing me
    if third version of send was needed. Another thing that disturbs me is
    that there is not a single "protected" method in Ruby standard library,
    in either 1.8 or 1.9. (Verified by ObjectSpace.each_object(Class) {|c|
    c.protected_methods.each{|m| puts m}})

    I'm not sure whether getting rid of all method visibility issues is
    worth it. It seems to be a big improvement, but it also introduces
    some compatibility problems (I dont).

    I think that we can at least get rid of "protected" level,
    which is used extremely rarely, and is very confusing.
    Java did a similar thing when it removed "private protected"
    visibility, which was also used extremely rarely and was very
    confusing.

    > As a side note, I sure would like to see class/module local methods
    > (not part of inheritance chain) if possible.


    [Long list of possible solutions follows]

    It should be pretty straightforward to simply store a procedure in
    instance/class variable or in local variable, just like we do with any
    other value.

    I didn't look at the problem much, so maybe I missed something,
    but I haven't seen any elegant ways of creating methods
    without names ?

    Some intuitive solutions would be:
    @@bar = UnboundMethod.new{ puts "bar #{@x}" }
    @@bar.bind(self).call()
    but UnboundMethod doesn't have #new

    Or:
    @@bar = lambda{ puts "bar #{@x}" }
    @@bar.bind(self).call()
    but Proc doesn't have #bind.

    Two solutions that work are:
    @@bar = lambda{ puts "bar #{@x}" }
    self.instance_eval{ @@bar.call() }
    Using different code for method objects created from
    named methods and directly from lambdas is not very elegant,
    as they are something pretty similar.

    And:
    class Class
    def define_private_method(name, &blk)
    define_method:)xyzzy, &blk)
    class_variable_set("@@#{name}".to_sym, instance_method:)xyzzy))
    remove_method :xyzzy
    end
    end

    And then:
    define_private_method:)bar) { puts "Hello" }
    @@bar.bind(self).call()

    I dislike the :xyzzy part a bit, as it can collide with some real method,
    but that's the best I was able to find.

    Syntax like @@bar.bind(self).call() looks a bit ugly.
    We can probably somehow make it possibly to avoid
    bind(self) part if we bind to self. The @@ .call part is
    unfortunately going to stay.

    --
    Tomasz Wegrzanowski [ http://t-a-w.blogspot.com/ ]
     
    Tomasz Wegrzanowski, Oct 2, 2006
    #4
  5. On 10/2/06, Tomasz Wegrzanowski <> > I'm
    not sure whether getting rid of all method visibility issues is
    > worth it. It seems to be a big improvement, but it also introduces
    > some compatibility problems (I dont).


    Sorry, I must have mistyped alt-something and gmail sent my message
    too early :)

    What I meant is that I don't expect compatibility problems to be too
    serious. The only code that would be broken is code that depended on
    the same message behaving differently depending on context. This is
    not common. And method visibility was going to be radically changed in
    1.9 anyway, as send changed its behaviour (send was very often used as
    "call while ignoring method visibility"). In fact, it wouldn't
    surprise me if getting rid of all visibility issues introduced fewer
    problems than changing behaviour of send.

    --
    Tomasz Wegrzanowski [ http://t-a-w.blogspot.com/ ]
     
    Tomasz Wegrzanowski, Oct 2, 2006
    #5
  6. On 10/2/06, David Vallner <> wrote:
    > Tomasz Wegrzanowski wrote:
    > > There is no such thing as interface of an objects.

    >
    > Pure virtual classes.
    >
    > > Java object model is halfway between C++ and Smalltalk.
    > > Objects still do not have single clear interfaces.

    >
    > Can you elaborate on what you expect as a clear interface?


    It seems that this is the main point of misunderstanding.
    My very long comparison of C++ and Smalltalk models
    was not meant to be about "C++ sucks and Smalltalk is the only true OO".
    I want to explain radically different models they use,
    and that solutions (private etc.) that fit C++/Java-style models
    do not really fit Ruby/Smalltalk-style models.

    So let me try to do it again.

    Imagine a Smalltalk object floating in the space. Nothing can ever learn
    what is inside it. The only thing it does is receiving messages and
    sending them. It does not have and does not want to have even a
    faintest idea what was the context in which the message was sent. The
    message has no idea what kind of object sent it and what kind of
    object is the receiver.

    Now imagine a C++ object. It is not a black box at all. It has
    *multiple interfaces*, and everything that communicates with it must
    know *exactly* what at least some of them are. Like with Smalltalk
    object, it receives messages. But the sender addresses messages to
    different interfaces, not to the object itself. So one message "bar"
    can be sent to "Foo in public context", while other message "bar" can
    be sent to "Bar in private context". It is pretty meaningless to talk
    about "sending messages to objects" in C++, as the receiver is not an
    object (but one of its many interfaces) and the message must know
    exactly what interface it is targetting.

    Java is following a cleaned-up version of C++ model, with some limited
    reflection capabilities. Objects still have multiple interfaces, but
    at least with public interfaces when a message comes, it's going to
    behave the same way no matter which interface was used. C++
    non-virtual and Java final behave in significantly different ways. In
    any case, Java is kinda halfway between C++ and Smalltalk, as from the
    outside Java objects behaves a lot like Smalltalk objects (the same
    message must do the same thing), but from the inside they are pretty
    much like C++, and which method is going to be called depends on
    context of the call.

    Ruby object model is almost like Smalltalk's. There are objects that
    receive messages and everything is context-independent. The main
    difference is that they have two interfaces, not one. They have an
    interface for generic messages (like Smalltalk objects), and a special
    interface for "implicit self" messages. (from the inside the
    difference is much bigger, but that's not important here)

    Having a single well-defined interface was a big win for Smalltalk.
    Ruby is almost there, but not quite. What is the reason for Ruby
    to have "almost-Smalltalk" object model ?

    Each object has only one "implicit self" interface,
    not one "private" interface for each class, so it's not going
    to provide the kind of encapsulation that Java and C++'s
    visibility controls do.

    So what other benefits come from "implicit self" interface ?

    > > And we don't get much - defining method "private"
    > > doesn't provide much "protection" as there is a single namespace
    > > for all methods, so it can be accidentally redefined in a subclass.

    >
    > Separating private methods in a separate namespace has been thought for
    > Ruby 2.0. No idea what happened to the proposal.


    Moving Ruby object model from "almost Smalltalk" to "pretty much Java"
    would be much more radical than moving it to "completely Smalltalk".

    And I don't think it's a good idea. Mostly for metaprogramming reasons.

    > > * Ruby 2 is exactly the right time for doing such changes

    >
    > The Ruby 1 -> Ruby 2 transition isn't supposed to be in the order of the
    > Perl 5 -> Perl 6 one. As far as I know, the changes are mostly touchups
    > that fall out of scope for a minor version bump because they address
    > some of the core design burps. As far as I know, it's supposed to be as
    > little codebreaking a change as necessary. Ruby 2 is not at all the time
    > for a keyword removal and object model revamp.


    I'd argue that removal of private/protected is a very small change.
    protected is hardly used at all (not a single use in standard library),
    so it can be thrown away without much further discussion.

    Removing private/protected distinction is more significant,
    but it seems that everyone acknowledges than the way it works in 1.8
    is not completely right. 1.9 already contains very big changes (and a lot of
    backward incompatibility by changing behaviour of Object#send) to
    handling of private/protected, and many more changes are needed
    before it's useful (after two versions of send we need two versions of
    method_missing etc.). And after these radical changes we don't get
    Java-like encapsulation, but something that is a lot less powerful
    than a (admittedly ugly-looking) solution which uses a few lines of
    metaprogramming. So it is going to change in Ruby 2, and the only
    question is which way.

    --
    Tomasz Wegrzanowski [ http://t-a-w.blogspot.com/ ]
     
    Tomasz Wegrzanowski, Oct 2, 2006
    #6
  7. Tomasz Wegrzanowski

    Csaba Henk Guest

    Tomasz Wegrzanowski wrote:
    > Ruby object model is almost like Smalltalk's. There are objects that
    > receive messages and everything is context-independent. The main
    > difference is that they have two interfaces, not one. They have an
    > interface for generic messages (like Smalltalk objects), and a special
    > interface for "implicit self" messages. (from the inside the
    > difference is much bigger, but that's not important here)


    I actually see the presence of these two interfaces beneficial.

    Using aux methods which are not intended to be part of the public
    interface is unevitable programming practice. The need to take it out
    from the public interface is also a very basic request.

    This should be solved in the core language (as others said before,
    no dozen witty hacky metaprogramming snippets for this, please).
    If not in the way it is done now, how would you do it?

    (Well, at least it's clear how not to do it. I think of Python's horrid
    name
    manglng...)

    Csaba
     
    Csaba Henk, Oct 2, 2006
    #7
  8. On 10/2/06, Csaba Henk <> wrote:
    > Tomasz Wegrzanowski wrote:
    > > Ruby object model is almost like Smalltalk's. There are objects that
    > > receive messages and everything is context-independent. The main
    > > difference is that they have two interfaces, not one. They have an
    > > interface for generic messages (like Smalltalk objects), and a special
    > > interface for "implicit self" messages. (from the inside the
    > > difference is much bigger, but that's not important here)

    >
    > I actually see the presence of these two interfaces beneficial.
    >
    > Using aux methods which are not intended to be part of the public
    > interface is unevitable programming practice. The need to take it out
    > from the public interface is also a very basic request.


    I tried to get some empirical data on this, and the result
    really surprised me. Of "private" methods in the whole Ruby
    standard library, very few were used as "aux method".

    The code to get the results:
    ObjectSpace.each_object(Module){|c| n = (c.private_instance_methods -
    (c.ancestors - [c]).inject([]){|a,b|a+b.private_instance_methods}); p
    [c.class, c, n.size, *n.sort] unless n.size == 0 }

    Most of them were clearly part of the interface.
    Like Module#attr_reader or FileUtils#rm_rf, they were supposed to be
    used, but mostly in "implicit self context". I do not see any reason
    not to expand visibility of such methods.

    Next category were some confusing entries like
    Math.private_instance_methods containing a whole list of trigonometric
    functions, Kernel containing Array, Float etc.

    I wasn't able to find any methods that were unambiguously meant
    *not* to be called by a programmer. There might be some,
    but they're just a very small fraction of all "private" methods.

    There wasn't even a single "protected" method anywhere.

    So whatever the purpose of Ruby visibility controls is,
    it is difficult to claim it is hiding aux methods.

    But assuming that we indeed want visibility control, what kind would
    make sense in Ruby ? Of those OO systems that have such controls (most
    don't have any), every single language uses a completely different
    design.

    Is there even a rough agreement on what a good solution would look
    like ? I guess we can at least agree that neither Ruby 1.8 nor Ruby
    1.9 solutions are particularly good, as they contain confusing and
    rarely used "protected" visibility, don't work well with
    method_missing and other reflection/metaprogramming methods, and use
    highly confusing naming (Ruby "private" is kinda but not really Java
    "protected", and "private"
    methods are usually public parts of the interface, not private parts of the
    implementation)

    > This should be solved in the core language (as others said before,
    > no dozen witty hacky metaprogramming snippets for this, please).
    > If not in the way it is done now, how would you do it?


    I don't really get the distinction between "core language" and "hacky
    metaprogramming". Half of Ruby core language is actually implemented
    as metaprogramming. Ok, syntax in my example:
    @@bar.bind(self).call(1, 2, 3)
    was very ugly, but maybe someone can come up with nicer syntax,
    or if it's impossible and the problem is important, we can add a tiny
    bit of syntactic sugar to Ruby. If we agree that some kind of visibility
    control is the right way, we can simply add a few metaprogramming
    methods to the standard library, and it becomes part of the "core
    language".

    The idea of making visibility controls a metaprogramming hack is that
    it makes it possible to test right now many different systems and see
    how well they work.

    --
    Tomasz Wegrzanowski [ http://t-a-w.blogspot.com/ ]
     
    Tomasz Wegrzanowski, Oct 2, 2006
    #8
  9. On 10/1/06, Tomasz Wegrzanowski <> wrote:
    > On 10/1/06, David Vallner <> wrote:
    > > On Mon, 2006-10-02 at 05:00 +0900, Tomasz Wegrzanowski wrote:
    > > > I have an modest proposal - can't we just get rid of private methods
    > > > completely in Ruby 2 ?
    > > > [snip justification]

    > >
    > > In my code, I use private methods for helper operations to dissect an
    > > algorithm into separate steps - these serve only to give fragments of
    > > code a name, not encapsulate any standalone functionality. Calling them
    > > out-of-order from client code would usually clobber an object's
    > > internals beyond repair.
    > >
    > > In all OO systems, the private / public distinction is to hide
    > > information about the inner workings of a class. While instance
    > > variables are obviously such information, often also how a class
    > > achieves what it does qualifies.
    > >
    > > If you have to call __methods__ directly, that's one more indication
    > > that you're Doing Something Weird.
    > >
    > > The difficulty in unit-testability is more of a failure on the side of
    > > the test framework. Including a "whitebox" mode in Test::Unit
    > > (generating public wrappers for private methods of tested classes) would
    > > be a more concise solution to this problem.
    > >
    > > The feature of private methods in Ruby is one I like. It's an
    > > encapsulation safety net as opposed to a roadblock in Ruby, but makes it
    > > more apparent in code that something out-of-the-ordinary is being done.
    > >
    > > I might be biased, since I'm opposed to strong usage of Ruby's
    > > metaprogramming capacities in "serious" code, at least without
    > > encapsulating such code very tightly. But removing all method-level
    > > encapsulation to facilitate meta hacks or get rid of some scenarios when
    > > they are necessary seems just overkill.

    >
    > It almost sounds that you're using Ruby as only a "better Java" :)
    > Many people consider Smalltalk-style OO and metaprogramming
    > in Ruby extremely important.
    >
    > Back to the point. It is very unusual for OO system to have
    > public/private distinction.
    > (http://www.approximity.com/ruby/Comparison_rb_st_m_java.html)
    > *The* OO language Smalltalk did not have it, and other OO systems
    > like Objective C, CLOS, Perl 5 and Python do not have it either.


    Well although Smalltalk doesn't have a mechanism for identifying
    private methods at run-time, it's common practice to document them
    using categories. You see categories like 'accessing' and
    'private-accessing'.

    Some Smalltalkers saw the lack of an enforced mechanism as a problem.
    I can't recall whether or not this came up in discussions in X3J20.

    Speaking as an experienced Smalltalker; I was the secretary of X3J20,
    which was the committee which developed the ANSI/ISO Smalltalk
    language standard; I find David's use cases for private methods far
    more compelling that the arguments to remove the feature.

    > The only listed languages that do are C++, Java and Ruby.
    > Conceptual model behind C++ is very far from Smalltalk-style OO.
    > In fact it has very little to do with OO, C++ objects are little
    > more than abstract data types. There is nothing remotely similar
    > to OO "message passing", the "methods" are merely nicely
    > namespaced functions with some hacks for "inheritance" (and you
    > need to turn inheritance support explicitly using virtual keyword,
    > by default you get nothing more than nicely namespaced functions).
    > There is no such thing as interface of an objects. The same object
    > is going to behave in completely different way depending on
    > context - a single method is going to do something completely different
    > depending on whether you call it from object's class, subclass of it
    > (and there is public and private inheritance, that changes object's
    > interface), or a different place.
    > The same method can behave differently depending on type of variable
    > to which object is assigned - if Foo is a subclass of Bar, then the
    > following code:
    > Foo *f = new Foo();
    > Bar *b = f;
    > b->bar();
    > f->bar(); // bar redefined in Foo, bar not virtual
    > can do two completely different things.


    All of this is true, but pretty much irrelevant as far as I can tell.

    > The model is already so complicated, that adding private/public
    > distinction to everything doesn't affect it much.


    Nor does it affect Ruby's model much either.

    > Java object model is halfway between C++ and Smalltalk.


    Maybe, whatever that means. Ruby does have a lot of similarities to
    Smalltalk, but it's quite different in other areas, including instance
    behavior.

    > Objects still do not have single clear interfaces. If Foo is
    > a subclass of Bar, and both have a private method bar(),
    > then calls to some_foo_obj->bar() will behave differently
    > depending on whether the call was done from methods declared in
    > Foo class or from methods declared in Bar class.


    I'm assuming that this is talking about Java.

    > Private methods are also *automatically final*, and therefore
    > they cannot be overriden. So private methods in Java still
    > have more to do with global functions than with regular methods.
    > Fortunately they at least got rid of private inheritance.


    Huh?!??? If I define a private method, I certainly can't call it as a
    global function. The lack of overriden private methods in Java is due
    to binding them early to methods, rather than because they are global,
    which they aren't.


    > I'm not saying "private methods" are useless in C++/Java.
    > They are simply not methods at all. They are nicely encapsulated
    > global helper functions for implementation of a class. They have
    > class-specific namespace and cannot be overriden, so a class
    > can define whatever private functions it wants to, and they do not
    > affect anything else.
    >
    > The only language left that has Smalltalk-style OO and this kind of
    > access controls in Ruby. Instead of objects having single interface
    > like Smalltalk or multiple interfaces like C++/Java, Ruby objects has
    > exactly two - one for normal method calls, and a second for "implicit self"
    > method calls.


    I can't understand what you mean here by two interfaces. The methods
    are in a single namespace, Making a method private affects what
    happens with you invoke it using an explicit receiver.

    > And we don't get much - defining method "private"
    > doesn't provide much "protection" as there is a single namespace
    > for all methods, so it can be accidentally redefined in a subclass.


    What we get is an ability to mark methods as being private at
    run-time. The fact that this can be overriden by subclasses is a
    feature which is harmonious with the basic philosophy of Ruby.

    > On the other hand methods cannot call private methods of different
    > object of the same class (or its subclasses), so objects with less-defined
    > interface and hidden implementation need to either hack around
    > access control inside own methods (ugly), or to have their internals public.


    I'm lost here, what does 'less-defined interface' mean? What's meant
    by internals? Objects internals can only be accessed by methods,
    Allowing methods to be private gives a tool to be used in class
    design. If you don't like private methods in your classes, just don't
    use them.

    > A very simple and very common example would be == method
    > that checks if both objects have the same class, and if so,
    > whether their fields are identical.


    This is a pretty restricted view of ==, in general the two objects
    don't need ot be the same class, and the comparison involves either
    public methods or a public conversion method.

    > While writing this reply I found something that really surprised me.
    > It is possible to get real private variables in Ruby, with private
    > per-class namespaces, not overridable, and working with other objects
    > of the same class, just like in C++/Java, by a few lines of
    > metaprogramming.
    > They are much better at encapsulation control than the official classes.


    Why would I want to do that, Ruby is a better Ruby than Java or C++,
    Java is a better Java than Ruby. C++ is the best C++, sad to say. <G>.

    >
    > So I think it would be good idea to have method visibility controls
    > removed because:
    > * They do not fit Smalltalk-style OO, so removing them would make
    > everything simpler


    No, it would just remove a feature, and one that some Smalltalkers
    wished that they had.

    > * We get very limited benefit from them due to lack of C++/Java-style
    > features like per-class namespaces for private methods (or even
    > instance variables), and ability to call private methods of other
    > objects of the same type


    The benefit comes not from trying to do C++ style features, but from
    providing a mechanism to denote methods which shouldn't be called by
    outsiders.

    > * They make metaprogramming, unit testing etc. more difficult


    I don't see why or how.

    > * They provide very limited control over visibility


    So? At least they provide some control.

    > * Very simple Ruby metaprogramming gives us much more powerful private
    > variables anyway.


    Simple?

    > * I think it's unlikely for current visibility control system to lead
    > to any cool things. As far as I can tell it was never used for
    > implementing any magic. There is no obvious way to add any features
    > (even to get them to the level of that metaprogramming snippet)
    > without greatly complicating the language.


    And assuming that that's something that someone would want to do, how
    does having private methods get in the way?

    > * Ruby 2 is exactly the right time for doing such changes


    Well, put in a ruby change request, I doubt that it will get much support.


    --
    Rick DeNatale

    My blog on Ruby
    http://talklikeaduck.denhaven2.com/
     
    Rick DeNatale, Oct 2, 2006
    #9
  10. Hello,

    In message "Re: Private visibility should be removed from Ruby 2 [was: Caveats with #method_missing]"
    on Mon, 2 Oct 2006 13:21:27 +0900, "Tomasz Wegrzanowski" <> writes:

    |Having a single well-defined interface was a big win for Smalltalk.
    |Ruby is almost there, but not quite. What is the reason for Ruby
    |to have "almost-Smalltalk" object model ?

    Because Ruby is not Smalltalk. Really.

    Let me elaborate a bit. Since I made the syntax of Ruby more
    traditional than Smalltalk's "everything is a message passing" style,
    you can write traditional code in Ruby, for example:

    print "hello world\n"

    rather than

    "hello world" printIt.

    or something like that. If everything procedure is a method, what
    should I do? There were several choices, and I chose "print" to be a
    method with implicit receiver, but made it "private" to detect weird

    "foobar".print "hello world\n"

    as an error. If you want to remove "private" from Ruby2, I expect
    your proposal addresses the above issue.

    matz.
     
    Yukihiro Matsumoto, Oct 3, 2006
    #10
  11. Tomasz Wegrzanowski

    Trans Guest

    Yukihiro Matsumoto wrote:
    > Because Ruby is not Smalltalk. Really.
    >
    > Let me elaborate a bit. Since I made the syntax of Ruby more
    > traditional than Smalltalk's "everything is a message passing" style,
    > you can write traditional code in Ruby, for example:
    >
    > print "hello world\n"
    >
    > rather than
    >
    > "hello world" printIt.
    >
    > or something like that. If everything procedure is a method, what
    > should I do? There were several choices, and I chose "print" to be a
    > method with implicit receiver, but made it "private" to detect weird
    >
    > "foobar".print "hello world\n"
    >
    > as an error. If you want to remove "private" from Ruby2, I expect
    > your proposal addresses the above issue.


    That's interesting. The difference between function and method?

    T.
     
    Trans, Oct 3, 2006
    #11
  12. Re: Private visibility should be removed from Ruby 2 [was: Caveatswith #method_missing]

    Yukihiro Matsumoto wrote:
    > should I do? There were several choices, and I chose "print" to be a
    > method with implicit receiver, but made it "private" to detect weird
    > "foobar".print "hello world\n"
    > as an error.

    All right. Just for that, I'm going into all my code and changing my
    print statements to "foobar".send:)print) statements.*

    Seriously, though, you know, a pox on any body that wants to type
    "foobar".print "hello world\n". (A more realistic mistake would, of
    course, be "foobar".puts.) In Io, the "OO" 5 print and the "procedural"
    write(5) coexist just fine.

    Wait, what are we talking about? You know, I should never respond to a
    post without reading the whole thread. Well, whatever it is, I agree
    with Jim Weirich.

    Devin
    * s/send/funcall/g... you get the idea.
     
    Devin Mullins, Oct 3, 2006
    #12
  13. On 10/3/06, Yukihiro Matsumoto <> wrote:
    > In message "Re: Private visibility should be removed from Ruby 2 [was: Caveats with #method_missing]"
    > on Mon, 2 Oct 2006 13:21:27 +0900, "Tomasz Wegrzanowski" <> writes:
    >
    > |Having a single well-defined interface was a big win for Smalltalk.
    > |Ruby is almost there, but not quite. What is the reason for Ruby
    > |to have "almost-Smalltalk" object model ?
    >
    > Because Ruby is not Smalltalk. Really.
    >
    > Let me elaborate a bit. Since I made the syntax of Ruby more
    > traditional than Smalltalk's "everything is a message passing" style,
    > you can write traditional code in Ruby, for example:
    >
    > print "hello world\n"
    >
    > rather than
    >
    > "hello world" printIt.
    >
    > or something like that. If everything procedure is a method, what
    > should I do? There were several choices, and I chose "print" to be a
    > method with implicit receiver, but made it "private" to detect weird
    >
    > "foobar".print "hello world\n"
    >
    > as an error. If you want to remove "private" from Ruby2, I expect
    > your proposal addresses the above issue.


    New version of my proposal:
    * add implicit_self? method analogous to block_given?
    * method called by send/funcall would have implicit_self? set to false/true
    * remove "protected" visibility completely
    * make all currently private "real" methods (that is almost all
    private methods outside Kernel) public
    * change names public/private to object/global (or something like that)
    * officially discourage using "global" visibility for real methods

    --
    Tomasz Wegrzanowski [ http://t-a-w.blogspot.com/ ]
     
    Tomasz Wegrzanowski, Oct 3, 2006
    #13
  14. Hi,

    In message "Re: Private visibility should be removed from Ruby 2 [was: Caveats with #method_missing]"
    on Tue, 3 Oct 2006 16:57:02 +0900, "Tomasz Wegrzanowski" <> writes:


    |> If you want to remove "private" from Ruby2, I expect
    |> your proposal addresses the above issue.
    |
    |New version of my proposal:
    |* add implicit_self? method analogous to block_given?
    |* method called by send/funcall would have implicit_self? set to false/true
    |* remove "protected" visibility completely
    |* make all currently private "real" methods (that is almost all
    |private methods outside Kernel) public
    |* change names public/private to object/global (or something like that)
    |* officially discourage using "global" visibility for real methods

    Interesting. Will you analyze consequences of above changes?
    How they make the language better? How they make it incompatible?

    In addition, I didn't understand how global "global" visibility, and
    why it should be discouraged.

    matz.
     
    Yukihiro Matsumoto, Oct 3, 2006
    #14
  15. Tomasz Wegrzanowski

    Marc Heiler Guest

    Re: Private visibility should be removed from Ruby 2

    'Seriously, though, you know, a pox on any body that wants to type
    "foobar".print "hello world\n". '

    For sure, because Ruby syntax (at least for me), is different to
    pretty every other language out there in that it is a lot cleaner.
    And with multiple choices given you can easily avoid any quirky
    syntax - although I am aware of the meta-meta languages
    interpreted in ruby. :)


    --
    Posted via http://www.ruby-forum.com/.
     
    Marc Heiler, Oct 3, 2006
    #15
  16. On 10/3/06, Yukihiro Matsumoto <> wrote:
    > Interesting. Will you analyze consequences of above changes?
    > How they make the language better? How they make it incompatible?
    >
    > In addition, I didn't understand how global "global" visibility, and
    > why it should be discouraged.


    Before I analyze, a short preexplanation.
    It is possible to have private and public methods that both do something,
    and this thing is different. It is impossible to do so directly, but if an
    object has private method "bar", and method_missing catches "bar",
    this is the result. It is highly pathological and it happens sometimes.

    And now the analysis.

    > |New version of my proposal:
    > |* add implicit_self? method analogous to block_given?


    implicit_self? will make more metaprogramming possible and
    metaprogrammed objects will behave more like native objects.

    For example to do delegation we can:
    def method_missing(*args, &blk)
    if implicit_self?
    @obj.funcall(*args, &blk)
    else
    @obj.send(*args, &blk)
    end
    end
    In 1.8 one would normally use:
    def method_missing(*args, &blk)
    @obj.send(*args, &blk) # send calls private methods too
    end
    what is further from calling @obj directly, as it fails to raise an exception if
    "implicit self only" method is called in public context. Or even worse -
    when private and public method with the same name do different thing
    (see preexplanation).

    implicit_self? seems like the simplest way to extend method_missing.
    Two alternatives:
    * Calling different method, like function_missing. Most of the time,
    we want them to do the same thing.
    * Changing method_missing API - no obvious way to do so, as it already
    takes arbitrary number of arguments.

    Another thing we get is soft visibility protection.

    class Class
    def soft_private(m)
    old_m = instance_method(m)
    c = self
    define_method(m){|*args,&blk|
    warn "#{c}##{m} should only be called in implicit self context"
    unless implicit_self?
    old_m.bind(self).call(*args, &blk)
    }
    end
    end

    class Foo
    def hello
    puts "Hello"
    end
    soft_private :hello
    end

    Foo.new.hello
    # => Foo#hello should only be called in implicit self context
    # => Hello

    Such soft protection would be quite helpful in refactoring, as
    it saves us from "run, die on first bug, fix, run again" cycle
    we would have with hard protection.

    I'm sure people will come with other ideas.
    Basically, more metaprogrammability is good.

    > |* method called by send/funcall would have implicit_self? set to false/true


    implicit_self? should obviously behave correctly with send/funcall,
    as we want foo.send:)bar, *args, &blk) to be exactly identical to
    foo.bar(*args, &blk)
    and funcall:)bar, *args, &blk) to be exactly identical to bar(*args, &blk)

    > |* remove "protected" visibility completely


    Nobody uses "protected" (0 uses in standard library - can anybody find some
    code that actually uses it ?). Nobody understands it.
    And it seriously complicates metaprogramming.

    I tried to check what protected really do.

    class Foo
    def hello
    puts "Hello"
    end
    protected :hello
    def world
    hello
    end
    end

    a = Foo.new

    a.hello # NoMethodError: protected method `hello' called for #<Foo:0xb7cdffb4>
    a.world # => "Hello"
    a.instance_eval { hello } # => "Hello"
    a.instance_eval { a.hello } # NoMethodError: protected method `hello'
    called for #<Foo:0xb7cdffb4>
    a.class.instance_eval { a.hello } # NoMethodError: protected method
    `hello' called for #<Foo:0xb7cdffb4>

    Ruby FAQ says that "protected methods are callable only from within
    their own class or its subclasses", but whether self is Foo or
    instance of Foo, I cannot call protected methods of Foo. I understood
    the explanation that it does something like checking in the caller
    whether self.is_a? class_where_method_was_defined, but it does
    something different.

    How was it supposed to work ? Am I the only one with a problem here ?

    And getting rid of it make metaprogramming easier.
    One example: I have no idea how to make delegation by method_missing
    that behaves correctly with public, protected and private methods.
    Delegation would either have to ignore visibility (what is wrong -
    see preexplanation again) or fail to forward some methods.

    > |* make all currently private "real" methods (that is almost all
    > |private methods outside Kernel) public


    If something is part of public interface, not a global function or an
    aux method,
    what's the reason for forcing instance_eval/funcall etc. ?
    And as far as I can tell, almost every use of private outside Kernel
    is for methods that are parts of public interface (mostly methods of Module).

    People often want to call private methods of Module for metaprogramming.
    I guess it's the same with other such cases.

    > |* change names public/private to object/global (or something like that)
    > |* officially discourage using "global" visibility for real methods


    Terminology Ruby uses is highly non-standard.
    In Java/C++/etc. private implies "in private namespace"
    and is typica//y used for methods that are not part of the public interface.

    In Ruby "private" means something completely different
    (more like Java/C++ "protected"), and is used for different things -
    public global functions and some public "implicit self only" functions
    (like those from Module). And I fail to see any real use
    for "implicit self only" methods (the proposal wants to make them all public).

    I guess some people use "private" for aux methods (probably due to getting
    used to "private" in Java/C++), but it's not very good for that purpose.
    Ruby private doesn't introduce private namespace, doesn't protect against
    accidental overriding, doesn't prevent calling a method if someone
    really wants to,
    and definitely doesn't detect the problem at compile time like in C++/Java.
    And unlike Java/C++ objects, Ruby objects have typically >100 public methods
    already (still less than Smalltalk but getting there),
    so what problem could possibly a few more aux methods introduce ?

    So the only good use of "private" left is for global function, and the name
    is non-standard and doesn't reflect what "private" does or what it's used for.
    So why not change it ?

    I would discourage using "private" for actual methods for previously
    metioned reasons:
    * it can lead to pathological situations where the same method does
    different thing depending on context. We can still have the problem
    with global functions (Foo.foo called bar, wanting to go through
    method_missing, but someone defined global function bar), but we limit
    it a bit
    * if method is part of public interface (like in Module) it only makes
    programming (especially metaprogramming) more difficult
    * for aux methods, it has few benefits of "private" in other languages

    I guess namechange and officially discouragement part of the proposal may
    be the least convincing and depend a lot on how one feels about it.
    The rest is pretty solid as far as I see.

    --
    Tomasz Wegrzanowski [ http://t-a-w.blogspot.com/ ]
     
    Tomasz Wegrzanowski, Oct 3, 2006
    #16
  17. On Oct 3, 2006, at 7:20 AM, Tomasz Wegrzanowski wrote:

    >> |* remove "protected" visibility completely

    >
    > Nobody uses "protected" (0 uses in standard library - can anybody
    > find some
    > code that actually uses it ?). Nobody understands it.


    I understand it just fine and have used it before. Here's an example
    where it might be needed:

    >> class Name < Struct.new:)first, :last)
    >> def full
    >> "#{first} #{last}"
    >> end
    >>

    ?> def last_first
    >> "#{last}, #{first}"
    >> end
    >>

    ?> def sortable
    >> [last, first]
    >> end
    >> protected :sortable
    >>

    ?> def <=>(other)
    >> sortable <=> other.sortable
    >> end
    >> end

    => nil
    >> names = [ %w[James Gray],

    ?> %w[Dana Gray],
    ?> %w[Joe Fair] ].inject(Array.new) { |a, n| a + [Name.new
    (*n)] }
    => [#<struct Name first="James", last="Gray">, #<struct Name
    first="Dana", last="Gray">, #<struct Name first="Joe", last="Fair">]
    >> # OK, because protected allows the call to other.sortable:

    ?> names.sort.map { |n| n.last_first }
    => ["Fair, Joe", "Gray, Dana", "Gray, James"]
    >> # Not OK, because sortable is for internal use only:

    ?> names.first.sortable
    NoMethodError: protected method `sortable' called for #<struct Name
    first="James", last="Gray">
    from (irb):28
    from :0

    James Edward Gray II
     
    James Edward Gray II, Oct 3, 2006
    #17
  18. Tomasz Wegrzanowski

    Trans Guest

    Yukihiro Matsumoto wrote:
    > Hello,
    >
    > In message "Re: Private visibility should be removed from Ruby 2 [was: Caveats with #method_missing]"
    > on Mon, 2 Oct 2006 13:21:27 +0900, "Tomasz Wegrzanowski" <> writes:
    >
    > |Having a single well-defined interface was a big win for Smalltalk.
    > |Ruby is almost there, but not quite. What is the reason for Ruby
    > |to have "almost-Smalltalk" object model ?
    >
    > Because Ruby is not Smalltalk. Really.
    >
    > Let me elaborate a bit. Since I made the syntax of Ruby more
    > traditional than Smalltalk's "everything is a message passing" style,
    > you can write traditional code in Ruby, for example:
    >
    > print "hello world\n"
    >
    > rather than
    >
    > "hello world" printIt.
    >
    > or something like that. If everything procedure is a method, what
    > should I do? There were several choices, and I chose "print" to be a
    > method with implicit receiver, but made it "private" to detect weird
    >
    > "foobar".print "hello world\n"
    >
    > as an error. If you want to remove "private" from Ruby2, I expect
    > your proposal addresses the above issue.


    With the proposal of #funcall, I think a lot of people were confounded.
    What did fucntions have to do with private vs. public. But it becomes
    increasing clear what matz has done, for better of worse. He noticed a
    function is a method without a receiver, which by all accounts is
    essentially the same as a method that can take no other reciever but
    self. In turn, that fits the concpet of a so-called "private" method.
    It's a very interesting sort of conscilence. Unfortuately the mixed
    terminolgy can be quite confusing since the two aren't readily
    associated. How many Rubyists would know that saying "private function"
    is redundant?

    Honestly one the syntax features that UI alwasy found out of place was
    'private' keyword. Here was essentially a DECLARATION in a language
    that sought to avoid declarations. I always felt at the least it would
    be better to make it take a block, 'private do ... end'. And I see that
    could just as well be 'function do ... end'. But why not address each
    function definition?

    defunc foo
    ...
    end

    I'm curious why the public/private nomenclature was chosen over
    'method/function' and why#funcall is being suggested now (moving away
    from that choice?).

    >From a larger perspective, it strikes me that different approaches were

    taken for variables as opposed to methods. It is equally possible to
    think of instance variables as private attributes. In this case,
    un;like methods, it is the private entities that take precedence and
    public variables are provided via additional interface methods. The
    distiction here is one of syntax made via the @ prefix. Concievably the
    same prefix mechism could have been used for private methods.

    def @foo
    ...
    end

    T.
     
    Trans, Oct 3, 2006
    #18
  19. On 10/3/06, James Edward Gray II <> wrote:
    > On Oct 3, 2006, at 7:20 AM, Tomasz Wegrzanowski wrote:
    >
    > >> |* remove "protected" visibility completely

    > >
    > > Nobody uses "protected" (0 uses in standard library - can anybody
    > > find some
    > > code that actually uses it ?). Nobody understands it.

    >
    > I understand it just fine


    Then could you explain, whether:

    a = Name.new('foo', 'bar')
    a.instance_eval { a.sortable } # correct or not ?
    Name.instance_eval { a.sortable } # correct or not ?

    are supposed to work or not, and why ?

    > and have used it before. Here's an example where it might be needed:

    [example omitted]

    This use is pretty nifty, as it saves you a class check:
    raise ArgumentError.new("comparison of #{self.class} with
    #{other.class} failed") unless oher.is_a? Name

    Except that it breaks later.

    Think how can you make an object that forwards all messages it gets to
    a Name object,
    and use it as if it was real Name. This is often very useful (in
    debugging, logging,
    lazy loading, remote execution, mock objects in unit testing etc.) and
    works with
    pretty much all objects.

    But it won't work correctly with your Name class - forwarding (method_missing)
    must either do public method call (send in 1.9), which fails as
    sortable is not public,
    or private method call (funcall in 1.9 or instance_eval+send in 1.8),
    which removes the class check, and therefore changes behaviour of <=>.

    So Name fails to behave like a nice Ruby class.
    I don't see how such problems can be reasonably fixed.

    To forward protected calls, we would need some way of getting caller
    context, what sounds pretty bad, as caller context is not simply class of
    caller's self, it can be some of its superclasses etc,
    and we need to make a version of send that uses this context.

    Then we would do :
    def method_missing(*args, &blk)
    @obj.send_with_context(caller_context, *args, &blk)
    end

    I think neither accepting unability to delegate nor actually having contexts
    like that is acceptable trade-off for the little use "protected" has.

    --
    Tomasz Wegrzanowski [ http://t-a-w.blogspot.com/ ]
     
    Tomasz Wegrzanowski, Oct 3, 2006
    #19
  20. On Oct 3, 2006, at 11:07 AM, Tomasz Wegrzanowski wrote:

    > On 10/3/06, James Edward Gray II <> wrote:
    >> On Oct 3, 2006, at 7:20 AM, Tomasz Wegrzanowski wrote:
    >>
    >> >> |* remove "protected" visibility completely
    >> >
    >> > Nobody uses "protected" (0 uses in standard library - can anybody
    >> > find some
    >> > code that actually uses it ?). Nobody understands it.

    >>
    >> I understand it just fine

    >
    > Then could you explain, whether:


    These are probably questions better asked of irb, but I'll try...

    > a = Name.new('foo', 'bar')
    > a.instance_eval { a.sortable } # correct or not ?


    I have no idea what "correct" means here, but I can tell you that
    Ruby allows protected methods to be called function-style for the
    current object and method style for another object of the same class:

    >> a.instance_eval { a.sortable } # correct or not ?

    NoMethodError: protected method `sortable' called for #<struct Name
    first="foo", last="bar">
    from (irb):20
    from (irb):20
    from :0
    >> a.instance_eval { sortable }

    => ["bar", "foo"]
    >> a.instance_eval { self.sortable }

    NoMethodError: protected method `sortable' called for #<struct Name
    first="foo", last="bar">
    from (irb):23
    from (irb):23
    from :0

    You do seem to be able to use either style in method definitions for
    the current object though:

    >> class Name < Struct.new:)first, :last)
    >> def full
    >> "#{first} #{last}"
    >> end
    >>

    ?> def last_first
    >> "#{last}, #{first}"
    >> end
    >>

    ?> def sortable
    >> [last, first]
    >> end
    >> protected :sortable
    >>

    ?> def <=>(other)
    >> self.sortable <=> other.sortable
    >> end
    >> end

    => nil
    >> Name.new("James", "Gray") <=> Name.new("Dana", "Gray")

    => 1

    > Name.instance_eval { a.sortable } # correct or not ?


    Well, it blows up and I consider that "correct", yes. You are inside
    the Name class here, not an instance of that class.

    James Edward Gray II
     
    James Edward Gray II, Oct 3, 2006
    #20
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Ben Fidge
    Replies:
    1
    Views:
    369
    Scott Allen
    Feb 17, 2006
  2. Henri
    Replies:
    5
    Views:
    449
    James Hicks
    Jul 22, 2003
  3. qazmlp
    Replies:
    19
    Views:
    818
    Daniel T.
    Feb 4, 2004
  4. Evan M.

    Menu Control Caveats

    Evan M., Apr 11, 2007, in forum: ASP .Net
    Replies:
    1
    Views:
    322
    =?Utf-8?B?UGV0ZXIgQnJvbWJlcmcgW0MjIE1WUF0=?=
    Apr 11, 2007
  5. Trans

    Caveats with #method_missing

    Trans, Oct 1, 2006, in forum: Ruby
    Replies:
    5
    Views:
    132
    David Vallner
    Oct 1, 2006
Loading...

Share This Page