Hacker News new | past | comments | ask | show | jobs | submit login

I personally don't like static factories that much. They have their place, but half the JDK is now `.of` or `.from` or `.newInstance` or `.get`.

I'd really like to be able to define a constructor on sealed interfaces:

    sealed interface Path permits WindowsPath, UnixPath {
        public Path(String p) {
            if (isWindows()) {
                return new WindowsPath(p);
            }

            return new UnixPath(p);
        }
    }

That way user code to construct an object is always the same:

    var p = new Path(s);
Instead of:

    var p = Paths.get(s);



I have two issues with constructors.

1. They don't have a name. That's bad because names are important. It's OK if constructor is primitive and does not do anything but field assignment. But often constructors do something and naming might help.

2. There can't be two constructors with identical types (as a consequence that constructors don't have a name). This might be restricting in some cases.

Factory methods solve both issues.

If anything, I'd prefer to remove constructors completely and use factory methods for anything. Not realistic with Java, of course. But in my code I'm trying to follow this pattern. Constructors are absolutely minimal (usually just initializers for final fields) and any non-trivial code goes into factory method. Of course it causes issues with subclassing, so it's not a silver bullet.


In practice the names are just not descriptive (of, from, newInstance, get) and I suspect this is because they're typically used to dynamically return implementations at runtime so you don't know the name of thing you want. If you know the name of the thing you want ahead of time, isn't the constructor of the named type good enough?


A good example might be static constructors that indicate the semantics of the parameters, such as of(array), copyOf(array), ofSorted(array)

Where perhaps the first wraps, the second copies and the third may wrap and avoid sorting the input. This would all of course depend on some conventions on meaning within the codebase.


An important benefit of static constructor methods is that they allow you to switch class implementations between a final class and an abstract class with private subclasses, without breaking compatibility. With regular constructors, you are prevented from switching to subclass implementations later. Static constructor methods thus decouple client code more from implementation decisions.

Another benefit is being able to name different constructors differently.

If I were to design a new OO language, I would make it so that constructors always work like that in the first place, from the caller perspective.


> An important benefit of static constructor methods is that they allow you to switch class implementations between a final class and an abstract class with private subclasses, without breaking compatibility.

Is this not what I'm describing? Using one way to construct objects would allow you to change from a concrete class to an interface without breaking client code. I just want the syntax to be the same across interface/abstract/concrete so class construction is uniform and discoverable.


I guess yes, although it now means you always need to start with interface plus class to later have the flexibility, even if you’ll never need it. It is kind of even more verbose. In current Java, you can start with a final class with static constructor methods (which is only slightly verbose), and later switch to having subclasses.

It also doesn’t provide the flexibility in naming.


I don't see how it would be more verbose.

   // you can start with a final concrete class
   final class A {}
   var a = new A();

   // and later move to interfaces or abstract types
   sealed interface A permits B, C {
      public A() {
           ...
      }
   }
   var a = new A();

Client code would remain the same with the flexibility to refactor to whatever you want later.


I see, yes, if it is possible to make this binary-compatible in the JVM, that would work. One implication is that `new A()` wouldn't be guaranteed to return a new instance anymore (just as for a static method).

Personally I still prefer having the ability to name the constructors. I'd rather have "new" be the default constructor name, with the option of having it be something else (i.e. Path.new(...) vs. Path.somethingElse(...)).




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: