Search code examples
rubyconstantsprivateencapsulation

Why would you private encapsulate a private constant?


I ran into this code:

class Foo < Bar
  SM_CONSTANT = { 'a' => 'A', 'b' => 'B' }.freeze
  private_constant :SM_CONSTANT

  private

  def some_constant
    SM_CONSTANT
  end

I cannot figure out the purpose of encapsulating a private constant in a private method. Why would I do this?


Solution

  • The reason for private_constant is to prevent other code from accessing the constant directly.

    some_constant might return the constant today, but it's not obligated to do that. If programming-by-contract then it's obligated to return a hash in that form, the origin of which is irrelevant.

    For example, you have that code today, but what about tomorrow it evolves to:

    class Foo < Bar
      SM_CONSTANT = {
        a: { name: 'A', priority: 2 },
        b: { name: 'B', priority: -1 }
      }.freeze
      private_constant :SM_CONSTANT
    
    private
      def some_constant
        SM_CONSTANT.map { |k,o| [ k.to_s, o[:name] ] }.to_h
      end
    end
    

    Where the internals have completely changed but to outside code nothing has, the same calls produce the same results. This is why encapsulation is important. It gives you the freedom to iterate and rework code within a particular context without concerning yourself about breaking other things.

    If code accessed SM_CONSTANT directly it'd have to be re-written to accept this new structure.