Restricting method access to classes, NOT methods of classes
8 views (last 30 days)
I am trying to understand some method access capabilities, so that methods can only my accessed by objects of a certain class, NOT one of its subclasses. I had thought that this restriction could be done using (Access = private), but that seems to restrict any external calls to the method, NOT calls by objects belonging to the subclass. I also don't see (Access = ?className) working, since an object of the subclass will also belong to the current class.
If the above made sense, and you can help, great! If not, below is a more practical example.
I am attempting to solve the following type of problem. I have a hierarchy of classes and subclasses, and I want to determine the lowest level of this hierarchy that a given object might belong to. As a thought example: I have phylogeny classes in the class hierarchy:
with numerous other branchings. I have some object with a number of properties, and at each level of the hierarchy I have methods that check whether we have enough information to classify the object to a lower level (such as looking for hasSpine and makesMilk). At some point, we may simply run out of information (filled properties) to further classify our object, so it may be stuck as a 'vertebrates' class object, rather than the lowest level 'mammals'.
In order to do this check, I am storing a list of subclasses in each class. The current class hands each listed subclass in turn all of the available properties, and subclass methods then determine whether the current class is a member of that subclass. If it is, the object is recast as that subclass. This procedure is then repeated until either we run out of branches to head down, or no branch reports that the object is a member (let's ignore multiple branches saying the object is a member, for now).
OK. So with the above story, I want to prevent 'vertebrates' objects from calling certain 'animals' methods, namely the method that asks "what are the subclasses I need to check". At the moment, I am stuck in a loop with one of two issues; either,
- I have no method defined at the sub-class level to overload the super-class methods. The object thus calls the super-class method for getSubclasses and winds up in a horrible loop (since it is checking the same subclasses again and again, and we already know the object is a member of at least one).
- I tried (Access = private), but that also blocks s = getSubclasses(obj) from working, since I am not calling the method with another method of that class, but with the object itself as the argument.
Now, there are some kludgey workarounds I can imagine: making sure I overload the super-class methods at EVERY level of the hierarchy, some more advanced use of 'isa' to make sure the object does NOT belong to one of the subclasses listed, etc. But I think there should be a way of doing this using access properties. Is there?
Steven Lord on 20 Jul 2018
I am storing a list of subclasses in each class.
That makes your system tightly coupled and seems like it's going to cause you to have to do a LOT of work if you add a new lowest-level class. You're going to need to touch ALL its superclasses.
I want to prevent 'vertebrates' objects from calling certain 'animals' methods
This is a violation of the Liskov substitution principle.
I think instead you should consider using the Factory method design pattern. Encapsulating the logic to determine the lowest level class that can represent the object in question in one factory function instead of having it scattered through the class hierarchy will hopefully reduce the number of places you need to modify code when adding / removing / modifying a class in your hierarchy.
You may even be able to use the introspection and metadata capabilities to help automate some of the decision making (if you have a list of all the classes in your hierarchy, because they are in a directory on which you can call dir or are in a package, you can find which of those classes has a Constant property hasSpine with a default value of true AND a Constant property makesMilk with a default value of true.)
Note that I haven't fully designed this, but I think you should be able to use meta.class, meta.property, and findobj to achieve what you want.