Why factory constructor can't be used in invoking superclass? - dart

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.

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.

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.

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.

Related

Why must the _internal() be called in the class?

Even though I am familiar with singleton, Dart's factory is confusing. I have seen an existing question, but the only thing I got from the answer is that the name can be whatever identifier that starts with an _. Even though the person had asked why it should be called, the answer does not seem to be explaining that.
If I comment out the Dog._internal(); line, I get Method not found: 'Dog._internal'. It looks like calling a method, but is it like C's function prototype? But it has no return type. Can someone explain the Dog._internal(); line to me?
class Dog
{
static final Dog dog = Dog._internal();
//Dog._internal();
factory Dog()
{
return dog;
}
}
There are multiple concepts going on so lets go through the example:
factory Dog()
{
return dog;
}
This defines a factory constructor. Factory constructors are much like normal static methods but must always return an object which are compatible with the type of which the factory constructor is part of. In our example the factory constructor must return a Dog object.
It is not a constructor in that sense that we already have created a object when we enter this method. Again, it can be compared to static Dog Dog() but is allowed to override the default constructor. So we must create the object manually and return it.
This allows us to control the behavior of when objects are created and in our case allows us to have a singleton pattern so when somebody are trying to create an instance of Dog they will always get the same object.
Dog._internal();
This is called a named constructor. Constructors in Dart can have given names which makes it easier to distinguish different constructors. But also because Dart does not allows us to override methods with different number of parameters.
Also, because of the name starting with _ it means this constructor is marked private and cannot be used outside of the library it is part of. So if your code is part of a library, the code importing your library are not allowed to call your private constructor.
This is again a nifty trick to allow us to make a singleton since we don't want other than our own code to create a new instance (which are the only instance we want to create).
static final Dog dog = Dog._internal();
This is essential creating the singleton. The reason for this is that static variables in Dart are lazy-evaluated so the value dog does not really have any value before it is called. After first call, the value are "cached" so Dog._internal(7) are only called once as long our application (or more specific, our isoleate instance) are running.
I would properly call the variable _instance or _dog so it is also private.
Dog.foo(); defines a named constructor named foo that takes no arguments and has no body. It's equivalent to Dog.foo() {}. Similarly, Dog._internal(); defines a named constructor named _internal. This would be more obvious if the constructor took arguments and did work, for example:
class Dog {
static final Dog dog = Dog._internal(7);
Dog._internal(this.years) {
registerAnimal(this);
}
factory Dog() {
return dog;
}
int years;
}

dart advantage of a factory constructor identifier

I've been investigating JSON parsing for my Flutter app and have a question about factory constructors that I can't resolve. I'm trying to understand the advantage of using a factory constructor versus a plain constructor. For example, I see quite a few JSON parsing examples that create a model class with a JSON constructor like this:
class Student{
String studentId;
String studentName;
int studentScores;
Student({
this.studentId,
this.studentName,
this.studentScores
});
factory Student.fromJson(Map<String, dynamic> parsedJson){
return Student(
studentId: parsedJson['id'],
studentName : parsedJson['name'],
studentScores : parsedJson ['score']
);
}
}
I've also seen an equal number of examples that DON'T declare the constructor as a factory. Both types of classname.fromJSON constructors create an object from the JSON data so is there an advantage to declaring the constructor as a factory or is using a factory here superfluous?
A normal constructor always returns a new instance of the current class (except when the constructor throws an exception).
A factory constructor is quite similar to a static method with the differences that it
can only return an instance of the current class or one of its subclasses
can be invoked with new but that is now less relevant since new became optional.
has no initializer list (no : super())
So a factory constructor can be used
to create instances of subclasses (for example depending on the passed parameter
to return a cached instance instead of a new one
to prepare calculated values to forward them as parameters to a normal constructor so that final fields can be initialized with them. This is often used to work around limitations of what can be done in an initializer list of a normal constructor (like error handling).
In your example this code
studentId: parsedJson['id'],
studentName : parsedJson['name'],
studentScores : parsedJson ['score']
could be moved to the body of a normal constructor because no final fields need to be initialized.
In the particular example in the question, there's no advantage to using a factory constructor. It makes no difference to callers (there is no expectation to receive an already-existing object), and this particular factory constructor could have been a normal constructor that delegated to the main constructor instead.
In general, the factory keyword is not very useful and provides an advantage only in special circumstances.
A factory constructor vs. a normal constructor
A factory constructor invokes another constructor.
Since a factory constructor does not directly create a new instance, it cannot use a constructor initializer list.
A normal constructor always returns a new instance of the class. A factory constructor is permitted to return an existing instance, an instance of a derived class, or null. (However, some people dislike returning null from a factory constructor. Note that returning null from a factory constructor is disallowed with null-safety.)
Due to the above, an extending class cannot invoke a factory constructor as the superclass constructor. A class that provides only factory constructors therefore cannot be extended with derived classes.
A factory constructor vs. a static method
A factory constructor can be the unnamed, default constructor of a class.
A factory constructor can be used with new. (But using new is now discouraged.)
Until Dart 2.15, constructors could not be used as tear-offs (i.e., they could not be used as callbacks), whereas static methods could.
Static methods can be async. (A factory constructor must return a type of its class, so it cannot return a Future.)
Factory constructors can be declared const.
In null-safe Dart, a factory constructor cannot return a nullable type.
In generated dartdoc documentation, a factory constructor obviously will be listed in the "Constructors" section (which is prominently at the top) whereas a static method will be in the "Static Methods" section (which currently is buried at the bottom).
After I've been noticing and wondering the same, and given I don't think the other answers actually answer the question ("I've been investigating JSON parsing [...] I'm trying to understand the advantage of using a factory constructor verses a plain constructor"), here my try:
there's no advantage or difference that I could see or understand, when parsing json, in using a factory constructor instead of a plain constructor. I tried both, and both works fine, with all the types of parameters. I decided eventually to adopt the factory constructor, because of the convenience of how the code is written, and readability, but it's a matter of choice and both will work fine in all the cases.
One of the uses of factory constructor is, we can decide which instance to create, at run-time and move all the logic to the parent's factory constructor
let's say you have 1 parent class and 2 subclasses
class GolderRetriever extends Dog{
GolderRetriever(String name):super(name);
}
class Labrador extends Dog{
Labrador(String name):super(name);
}
Then we have the parent class
class Dog{
final String name;
Dog(this.name);
factory Dog.createInstance({required String name,DogType type=DogType.UNKNOWN}){
if(type==DogType.GOLDEN_RETRIEVER){
return GolderRetriever(name);
}
else if(type==DogType.DALMATION){
return Labrador(name);
}else{
return Dog(name);
}
}
}
and also I have enum DogType
enum DogType{
GOLDEN_RETRIEVER,DALMATION,UNKNOWN
}
Then in the main Method, you just delegate which subclass instance you want to create to the parent Dog class
main() {
Dog myDog = Dog.createInstance(name:"Rocky",type:DogType.DALMATION);
Dog myNeighboursDog = Dog.createInstance(name:"Tommy",type:DogType.GOLDEN_RETRIEVER);
Dog strayDog = Dog.createInstance(name:"jimmy");
}
you can't do this with a named constructor as you can create only the instance of that class(Dog class), not its subtypes.
Now the responsibility of which instance to create is delegated to the parent class. This can remove a lot of if-else boilerplate code. When you want to change the logic, you just change that in Animal class alone.

Can I get an InstanceMirror of a class without using any constructor in Dart?

Can I get an InstanceMirror without using any constructor in Dart?
More precisely: I have a class with or without any special constructor, yet I'd like to get an InstanceMirror without having to provide a constructor or any arguments at all.
For example PHP offers ReflectionClass::newInstanceWithoutConstructor
Cheers
Why do you need an InstanceMirror and why can't you use a ClassMirror?
Just list all the available constructors from the ClassMirror and then use a constructor with 0 arguments to create a new instance.
The PHP Version says: "Creates a new class instance without invoking the constructor.". For me this totally makes no sense. That's why there are constructors: To be called at creation time.
New
If the class doesn't have a constructor, a default constructor with no arguments is implicitly created for this class and you can use it.
If a class has one or more explicit constructors, you can create a new instance only by using one of them.
Old
I'm not sure if I fully understand your questions, but basically - no. If your class doesn't have a constructor an implicit default constructor is used.
An instance of a class is created with new SomeClass which creates a new instance and calls the constructor. There are other ways like literals {'x': 1, 'y': 2} but I'm pretty sure this way a constructor is called as well.

Why doesn't the Delphi compiler throw a warning when a class method uses self?

At my workplace, we have some code where class functions refer to Self, effectively creating a potential access violation, should the object not be initialised. Does the meaning of Self change in a class method as to refer the class rather than the object?
I assume the only reason this is working is because the Self refers to another class function and not a regular method.
I created the following test class:
constructor TTest.Create;
begin
FTest := 'Hej';
end;
procedure TTest.GoTest;
begin
ShowMessage(FTest);
end;
class procedure TTest.Test;
begin
Self.GoTest;
end;
However, compiling this throws an error:
[dcc32 Error] Unit1.pas(51): E2076 This form of method call only allowed for class methods or constructor
I also testing referring to FTest directly, which gave another error:
[dcc32 Error] Unit1.pas(51): E2124 Instance member 'FTest' inaccessible here
But I wonder, however, whether it is possible to have a case where Self is potentially dangerous in class methods.
I know, that referring to global objects and assume they are there is always bad.
Does the meaning of Self change in a class method as to refer the class rather than the object?
In a class method Self refers to the class. The documentation says:
In the defining declaration of a class method, the identifier Self represents the class where the method is called (which can be a descendant of the class in which it is defined.) If the method is called in the class C, then Self is of the type class of C. Thus you cannot use Self to access instance fields, instance properties, and normal (object) methods. You can use Self to call constructors and other class methods, or to access class properties and class fields.
A class method can be called through a class reference or an object reference. When it is called through an object reference, the class of the object becomes the value of Self.
The compiler won't object to you using Self since it is a legal and supported thing to do. It just complains when you try to use instance members, instance methods etc.
Self has this meaning in class methods for exactly the same reason it exists in instance methods. It allows you to fully specify a symbol and thus avoid scoping ambiguity. What's more it allows you to access the actual class on which the method is called. This may be a descendant of the class in which the method is defined.
I wonder, however, whether it is possible to have a case where Self is potentially dangerous in class methods.
I don't see any particular danger inherent in this part of the language. In fact the use of Self reduces scope and so reduces the danger of inadvertently referring to a local variable rather than a class member.

Understanding this way of instantiating a new object

I just started BlackBerry development and I follow some of the tutorials to become familiar with the UI objects and so on and I saw/tried this:
private MenuItem menuItemClose = new MenuItem(new StringProvider("Contacts"), 0, 0) {
public void run() {
onClose();
}
};
I have not seen this way of instantiating an object before (thinking about new MenuItem), could someone explain what is happening?
And what is the difference between instantiating objects inside method definitions and in "instance variable section" like this?
That's called an "anonymous inner class."
Anonymous inner classes are classes which are created within another class but not named. They are instantiated by their interface or abstract base class definition and given their missing implementation inline with the instantiation.
In this case, MenuItem is abstract - it's missing its run() method. You're providing the implementation of its run() method here on lines 2-4.
Take a look at this JavaWorld article for more information about the various types and uses of inner classes.
As for the second part of your question "what is the difference between instantiating objects inside method definitions and in "instance variable section" like this?" -- the difference is scope, and when the object is instantiated.
Non-static member variables with initial values are created when the object which contains them is instantiated. The initial value assignment (initialization) executes at that time as well.
Static member variables with initial values are created and initialized when the class is loaded by the VM's class loader. With eager ClassLoading, this will occur at the start of the application. With lazy ClassLoading, this will occur the first time the class is referenced by the application. I believe by default most classes that aren't part of the Java runtime are loaded lazily.
Both static and non-static member variables have object-level scope and are accessible by other objects according to their access modifier (public/private/protected).
Non-static member variables are part of an object instance, and as such they are marked for garbage collection when that instance is orphaned or goes out of scope. Static member variables are only garbage collected if the class that contains them is unloaded. This only occurs if the ClassLoader instance which loaded said class is garbage collected. See this question for more info about that.
Local variables (variables which are defined within a method) with initial values are created and initialized when that line is executed as part of normal method execution. They are marked for garbage collection (destroyed) once they go out of scope (after the method in which they're contained finishes executing).
This creates an anonymous inner class which extends MenuItem and overrides the run method. It is standard Java and has nothing to do with Blackberry.
When you define a new inner class inside the method call, it's known as an 'anonymous inner class'. Anonymous inner classes are useful when you don't really need a reference to the object after the initial method call.
final Object obj = new Object(); // Standard instantiation
System.out.println(obj); // Prints java.lang.Object#5c005c
// Anonymous inner class
System.out.println(new Object() { }); // Prints Foo$1#2500250
// Anonymous inner classes work with interfaces too
new Thread(new Runnable() {
#Override
public void run() {
// Runnable is an interface
}
}).start();
This is quite a common pattern and can be useful to define 'one-time-use' objects, perhaps at the expense of readability.

Resources