I'm not particularly interested in settling on a bikeshed color, but am 
interested in the general mood for pursuing this direction at all. (And not 
necessarily right away, just—is this a direction we think we'll be going?)

A few observations/questions:

- 'new Foo()' traditionally guarantees fresh instance creation for identity 
classes. Primitive classes relax this, since of course there is no unique 
identity to talk about. Would we be happy with a language that relaxes this 
further, such that 'new Foo()' can return an arbitrary Foo instance (or maybe 
even null)? Or would we want to pursue a different, factory-specific invocation 
syntax? (And if so, should primitive classes use it too?)

Let me offer some context from Amber that might be helpful, regarding whether we might want "factory" to be a language feature.

Example 1 -- records.  One of the complaints about records is that you have to instantiate them through constructors, not factories; over the decades, people have come to view exposed constructors as "dirty" and therefore would rather see

    List.of(Foo.of(a, b), Foo.of(c, d))

than

    List.of(new Foo(a, b), new Foo(c, d))

This is a cosmetic concern, but it still does elicit "but why" comments from developers when they first encounter records.  The reason, of course, is that records are a language feature, and therefore have to be built on top of other language features. Constructors are a language feature, but factories are not, they are just a library structuring convention.  If the language had some way to declare factories, we might have (but still might not have) encapsulated the constructor and exposed a factory instead. (Though, since we'd have to make up a name for the factory, and we try to avoid magic naming, we might still have gone with ctors.)

Example 2 -- "with" expressions / reconstructors.  A number of interesting features come out of the pairing of constructors and deconstruction patterns with the same (or compatible) argument lists, such as `with` expressions (`point with { x = 3 }`). Handling this involves doing multiple overload selection operations, first to find a deconstructor that yields the right bindings, and then to find a compatible constructor that accepts the resulting exploded state.

Among the many problems of doing this (including the fact that parameter names are not required to be stable or meaningful), we also have the problem of "what if the class doesn't have a constructor, but a factory."  This would require the language to have a notion of factory method (e.g., `factory newPoint(int x, int y)`) so the compiler could try to match up a compatible factory with the deconstructor.

The same questions apply here -- what constraints do we put on a "factory" at the source level?  Implicit null checks on exit?  Do we want to pun `new Foo()` with factory invocation, or treat them separately?  Many questions (which I'm not trying to answer here.)


I'll just note that there is already an asymmetry in primitive classes here, in that the user writes a constructor, but the compiler generates a factory in the classfile.


Reply via email to