1. 6
  1.  

  2. 2

    There is a public_send method that respects method visibility - to be completely honest I’m not sure how it deals with protected status, though, since protected is not typically seen in idiomatic Ruby afaict.

    I do like the perspective of looking at method dispatch in terms of sending messages, though. Decent write up!

    1. 2

      public_send does not call protected methods. And, yeah, protected rarely happens in Ruby. I consider it a mild code smell as it implies the use of inheritance.

      1. 1

        And, yeah, protected rarely happens in Ruby. I consider it a mild code smell as it implies the use of inheritance.

        I’ve always considered private to be the wrong choice, in any language, because it signals that I think I know every way anyone might ever want to extend my class. Inheritance may not always (or even often) be the right solution, but making certain extension options impossible is just going to drive future coders crazy.

        1. 2

          I use private to lower the cost for future internal refactors, and upgrades, by providing a signal that “Hey, this method is not part of the public API, I do not condone its external use, and reserve the right to change it wildly.”

          It communicates that there consciously was no consideration for what might happen if external objects began to depend on said private method. Later changes by anyone (not just the original author) can and will be free to change the private method at will: refactor, upgrade, remove entirely, and there is less to hold in your head and worry about when upgrading them later.

          However, behavior of a private method that is observable through the a public method is fair game, and test cases should exist for those. The flip side of this is that, except in some rare cases, I favor not testing private methods. Any behavior that is possible via a private method, but which cannot be exercised or observed through use of public methods, should not be considered as supported behavior on the object. That does not preclude a new public method from exposing more of the private method’s behavior later, but at that point it is part of the public interface, and should be presented and documented as such.

          As for making certain extension options impossible, at least in the context of Ruby, private does not do this.

          class PrivateGreeter
            private
            def greeting
              "Hello."
            end
          end
          
          class PublicGreeter < PrivateGreeter
            def speak
              greeting
            end
          end
          
          irb> PrivateGreeter.new.greeting
          # => NoMethodError: private method `greeting' called for #<PrivateGreeter>
          irb> PublicGreeter.new.speak
          # => "Hello."
          

          You can even give it the same name as the parent class’ private method if you really, truly need to let external objects utilize the method as part of the subclass’ public API with the exact same name:

          class PublicGreeter < PrivateGreeter
            def greeting
              super
            end
          end
          
          irb> PrivateGreeter.new.greeting
          # => NoMethodError: private method `greeting' called for #<PrivateGreeter>
          irb> PublicGreeter.new.greeting
          # => "Hello."
          

          Since an inherited class can make use of its parent class’ private method, the question then becomes: should it? If we have a stipulation that the parent class reserves the right to refactor its private methods or change them wildly, should we rely on a parent class’ private method?

          I think the answer differs between application code and library code. If the parent class comes from a library, or some internal, but still cross-domain, utility code, I would not want to rely on the existence, the arity, or the behavior of a private method. If the behavior is so critical, I would rather capture the behavior permanently as part of the subclass by copying the code itself over to the subclass (or not use inheritance at all, but I would still definitely copy the code). Everything I have seen makes me agree that duplication is far cheaper than the wrong abstraction.

          In the case of application code, it is more acceptable to rely on a parent class’ internals. I still would fight the urge, but it can be expected that the author modifying the subclass and parent class has access and authority to work on both in order to get their job done, that the tests for both classes live in the same suite, and other niceties that make maintaining that dependency across time situation more tenable.

      2. 1

        Thanks for your great feedback ! That’s motivates me to do even more :-)