1

Minimal reproducible code:

class Foo { Foo(); factory Foo.named() => Foo(); } class Bar extends Foo { Bar() : super.named(); // Error } 

As there's no async-await thing in the factory constructor, and it instantly invokes the concrete constructor, so why isn't it allowed to use factory constructor like that?

Before null safety, null could be returned from a factory constructor but it is no longer a case. So, I think a factory constructor should now be allowed.

0

3 Answers 3

3

Calling a generative constructor creates a new object, then runs the constructor and super-class constructors to initialize that new object. They are initializers which initialize the object created by the (now often implicit) new operator.

The super-constructor chained by the (non-redirecting) generative constructor is called to initialize the same object, and ensure that its fields are fully initialized, before ever giving anyone access to that object.

Calling a factory constructor does not create any new object, it just executed the body of that constructor which can do anything that normal code can. (That may or may not include calling a generative constructor to create an object. It can also just throw and never create any object.) A factory constructor cannot access this, because there is no "current object" before it returns one.

Let's assume that Foo has an int foo = 42; field. A factory constructor like the Foo.named here creates a new object by calling Foo() - the generative constructor. When you do new Bar(), you create a new Bar object and ask the super-constructors to initialize that object. The named factory constructor has no access to that new object that would be created by calling new Bar(), it cannot access this and it cannot help initialize the foo field of that object. It creates a new, unrelated, Foo object and now you have 1) a partially initialized Bar object and 2) a Foo object, neither of which can be the result of calling a Bar constructor.

Your generative constructors must call a super-class generative constructor, which does the same until reaching the Object constructor. That's the only way to ensure that the newly generated object is fully initialized.

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

6 Comments

"The named constructor has no access to the object that would be created by calling new Bar()" -- I got lost in this line. Can you please explain it a bit further.
It's hard to describe a hypothetical that doesn't make sense. I've added some more text. Basically, a generative constructor imlicitly gets a "this" object to initialize, using its initializer list, and a factory constructor does not get that, so it cannot initialize the object being created. So you cannot chain a generative initialization step through a factory constructor, because it cannot do what a generative constructor must do: Initialize the new object.
Thanks, it's much clear now. Although I didn't get one basic thing in this line ... ask the super-constructors to initialize that object. Which object are we talking about here, Bar? And if it is Bar, then is this how things work in Dart that when we do super(...) from a base class constructor, it basically passes the base class instance to super class for initialization i.e. does super class initialize base class instance? I think this is what you also mentioned in the comment (since I'm not from CS background it's slightly difficult for me to grasp things in first read).
When you do new Bar(), a new Bar object is immediately created in an uninitialized state. The the generative constructor for Bar is invoked, which must initialize any fields introduced by Bar, using either field initializers, initializing formals or initializer list assignments. Then the superclass generative constructor is invoked to initialize the same object, only for any fields introduced by the superclass, Foo here. Then its superclass constructor is invoked (which is the Object constructor here). Only then is the object ready.
In short: generative constructors do not create objects. The new operator on a generative constructor creates the object, then the generative constructors initialize the object, with each superclass getting its turn to initialize its own fields. That's why there needs to be a chain of generative (initializing) constructors all the way back to Object.
|
3

factory function can return subclass, which means can call subclass's init function.

if subclass self can call super.factory function, then it become cycling.

Comments

1

One of the main purposes of a factory constructor is to allow returning an existing instance. That's basically incompatible with a derived class constructor that must create a new object. (I suppose it doesn't necessarily have to be; you could imagine a design where two derived instances virtually inherit from a shared instance of a base class. However, that would be a lot of extra work for something of little benefit and that could be very confusing.)

Additionally, one of the other main purposes of a factory constructor is precisely to prevent a class from being subclassed by making all non-factory constructors private.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.