
Submitted by minam (Fri Jan 09 00:01:05 UTC 2004)
Also, there are times when you want a particular set of methods of a class to be private, and yet be accessible to members of a specific class (or set of classes). This is similar to the "friend" accessibility as implemented in C++, but more robust and with finer control over the granularity of the access.
Consider the "State" design pattern, as described in the "Design Patterns" book by Erich Gamma, et. al. You have some class A that has some internal state. At some point in your program, you want to take a snapshot of A's internal state, so that you can later restore A to that state. The State design pattern suggests creating some class B that encapsulates the internal state of A. B would have a "private" interface that A would be able to query, but no other class, allowing A to set and retrieve its internal state via B. Currently, there is no mechanism for doing this easily in Ruby.
feature in this RCR for compatibility with Eiffel, but it may be called anything in practice, perhaps allow or access). This method would act much like the private and public methods act in current versions of Ruby, but would instead accept a list of class names. All subsequently declared methods of the class would then be accessible only to the declaring class and to any descendent class of any of the classes given in the list.
The current private, protected, and public methods would remain, for backwards compatibility, since they are easily converted to the corresponding idioms in the new model.
Here is an example using the proposed syntax:
class Demo
feature :Demo # grants visibility only to Demo and its descendents,
# i.e., "protected" visibility
def method1
...
end
feature :Object # grants visibility to all classes, i.e., "public"
def method2
...
end
feature :NilClass # grants visibility to no classes except the declaring
# class, i.e. "private" visibility
def method3
...
end
feature :OtherClass, :YetAnotherClass
# "friend" visibility, granting access only to the declaring class and
# to the classes
def method4
...
end
end
The usage of :Object and :NilClass to represent "everything" and "nothing" (respectively) correspond to Eiffel's use of Any and None. Perhaps a clearer system would be to have :Any and :None simply be aliases for :Object and :NilClass. Perhaps there's an even clearer way to represent the "None" scenario.
It is also desirable from a design point-of-view. The whole point of the "encapsulation" aspect of object-oriented design and programming is to hide certain parts of a class from outside clients (and sometimes even from descendents of the class itself). By guaranteeing that clients cannot access a given method (or set of methods), you can more easily guarantee the consistent behavior of your class. Also, private, internal methods can forego parameter checking and other "sanity checks", since the implementor does not need to worry about a client passing incorrect data to them.
Adding this feature does not mean that every implementor of a class must use it. By default, all methods of a class will be public, just as they currently are in Ruby. But it does give the ability to those implementors that want it to use a more robust encapsulation mechanism.
Ruby already supports feature visibility, via the "public" and "private" methods. By increasing the power of this feature, more consistent programs may be written, without sacrificing the current Ruby feature visibility mechanism.
This proof-of-concept, however, is not sufficent, since it is both easily circumvented (all it does is rename the original method and make a "wrapper" method that enforces the visibility) and fragile (it uses the set_trace method to detect when the calling method changes). The language itself needs to know about and be able to enforce the visibility of various method features.

| Comments | Current voting | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
|


RCRchive copyright © David Alan Black, 2003-2005.
Powered by .
When I was in school, I read Meyer's "Object-oriented Software Construction", and was influenced a lot. And this particular feature (selective export) is the feature I felt *agaist* most, after the research.
I mean, the basic concept of selective export is good, but the particular design in Eiffel seems ugly, because its against the policy of extensibility: the service provider should not restrict its clients, otherwise it would restrict the future use of the service. So, I designed the selective exporting feature in publish-and-subscribe model instead in the past.
Let me explain.
If the provider specifies classes for features to export, classes not known to the provider will never be able to access the "private" features. The workaround would be exporting features to (possibly) empty classes, and clients inherit these empty classes to "buy" features.
But why not be more direct? So I defined set of features, which I named "profile", and clients use profiles to gain visibility to the class.
class Demo { method_1 { ...; } method_2 { ...; } profile DemoProfile1 { method_1; } profile DemoProfile2 { method_1; method_2; } } class Client { first(DemoProfile1 demo) { demo.method_1; # valid demo.method_2; # invalid } second(DemoProfile2 demo) { demo.method_1; # valid demo.method_2; # valid } } d = Demo.new d.method_1 # invalid; because default visibility is private Client.new.first(d) # DemoProfile1 = Demo assignment is validI designed a statically typed object-oriented language in my graduation thesis, which had this selective export (the above example in that language). Although it has not been published to anybody, I still think my design is superior than Meyer's in this aspect.
Note that the design is based on static typing, so that it cannot be directly applied to Ruby.
I am not sure whether Ruby needs this level of visibility control, but if it does, it should be much better than Eiffel's selective export.
- matz.
Matz: thanks for your excellent comment. It gave me a lot to consider, and after a lot of thought I can see that your approach is much more flexible than Eiffel's. To that end, I am going to withdraw this RCR and submit another one, with a proposed implementation for your publish/subscribe approach to selective export.
Thanks for helping me to "see the light." :)
- Jamis