67
class A
private
  def initialize
    puts "wtf?"
  end
end

A.new #still works and calls initialize

and

class A
private
  def self.new
    super.new
  end
end

doesn't work altogether

So what's the correct way? I want to make new private and call it via a factory method.

3
  • I'm not sure what you want is possible, but even if it was, in theory, you wouldn't be able to call it from a factory method because it would be private. Are you trying to create a singleton? Or do an inversion-of-control pattern? Commented Oct 14, 2009 at 16:27
  • Restricting constructor access is helpful when an instance has state that should not be shared across operations, and you want to prevent the caller from accidentally using an object for more than one operation. A file importer or parser, for example, where you could have a static method parse or import (or call). The instance is an implementation detail not relevant to the caller. Commented Aug 31, 2020 at 16:59
  • @Matt Maybe I don't understand you completely, but I don't think that's true. If you paste this into irb, and then input A.create, an instance is created: class A; private_class_method :new; def self.create; self.new; end; end. Commented Aug 31, 2020 at 17:02

3 Answers 3

102

Try this:

class A
  private_class_method :new
end

More on APIDock

Sign up to request clarification or add additional context in comments.

8 Comments

In case you are looking to implement a Singleton class (the only reason I can think of wanting a private constructor), Ruby will do it for you. apidock.com/ruby/Singleton
And even then someone could do A.send(:new). (BTW, shouldn't "class" be lower case?)
@adurity, you might also want to have specialized factory methods.
You might want a private constructor to allow the class to create instances of itself in ways you wouldn't trust external callers to - e.g. directly assigning to protected variables that should be immutable to or hidden from other initializers
@adurity: Maybe you want to implement a strict way to create the object. For example: Quote.for_truck(truck) and Quote.for_car(car) but you don't want to allow people building Quotes from scratch.
|
15

To shed some light on the usage, here is a common example of the factory method:

class A
  def initialize(argument)
    # some initialize logic
  end

  # mark A.new constructor as private
  private_class_method :new

  # add a class level method that can return another type
  # (not exactly, but close to `static` keyword in other languages)
  def self.create(my_argument)
     # some logic
     # e.g. return an error object for invalid arguments
     return Result.error('bad argument') if(bad?(my_argument))

     # create new instance by calling private :new method
     instance = new(my_argument)
     Result.new(instance)
  end
end

Then use it as

result = A.create('some argument')    

As expected, the runtime error occurs in the case of direct new usage:

a = A.new('this leads to the error')

Comments

13

The second chunk of code you tried is almost right. The problem is private is operating in the context of instance methods instead of class methods.

To get private or private :new to work, you just need to force it to be in the context of class methods like this:

class A
  class << self
    private :new
  end
end

Or, if you truly want to redefine new and call super

class A
  class << self
    private
    def new(*args)
      super(*args)
      # additional code here
    end
  end
end

Class-level factory methods can access the private new just fine, but trying to instantiate directly using new will fail because new is private.

1 Comment

Upvoted because this is an entirely valid way of making a class private method. I didn't know about opening classes' classes six years ago. :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.