I have a factory class that is generic over T extends SomeClass<A>. But the thing is that A isn't known at the class level but only at the method level. To make myself a bit clearer with some code:
class Factory<T extends SomeClass<A>> { // Don't know A here
T<A> Function<A>(A arg) _constructor; // Function that produces my T's and is generic over A
Factory(this._constructor);
T<String> newString(String arg){ // A is only known here
return _constructor(arg);
}
T<int> newInt(int arg){
return _constructor(arg);
}
}
This obviously isn't legal Dart code, but is something to that effect even possible with Dart's generics, or does it require code generation? I tried to use extension methods, but they don't solve the problem that _constructor has the return type T<A>. And I explicitly don't want to / can't use T constructor<A, T extends SomeClass<A>>(A args).
Edit: I think what I was actually asking for is higher kinded types, which categorically aren't possible in Dart, and there is ongoing discussion on this matter (https://github.com/dart-lang/language/issues/1655). Excuse me if my understanding of the matter is incorrect.
That's not directly possible the way Dart currently works.
Dart's generics are only first order, so you cannot pass what is essentially a function from type to type as a type argument. Only plain types can be type arguments.
What you have here is a generic factory class. The kind of object it creates is defined at the class level (for ease, let's just assume that SomeClass here is Iterable, so it's a collection factory class, and you can choose, e.g., List or Set or Queue as the kind of collection to create), and then the element type of those collections are chosen when you call the factory methods.
That cannot work, because there is no type that the class can store in the class type argument which can allow that usage later.
I'd probably use separate classes and normal inheritance for this:
abstract class Factory {
Iterable<T> Function<T>(T) _constructor;
Factory(Iterable<T> Function<T>(T) constructor)
: _constructor = constructor;
Iterable<String> newString(String arg) => _constructor<String>(arg);
Iterable<int> newINt(int arg) => _constructor<int>(arg);
}
class ListFactory extends Factory {
ListFactory(List<T> Function<T>(T) constructor) : super(constructor);
List<String> newString(String arg) =>
super.newString(arg) as List<String>;
List<int> newInt(int arg) =>
super.newInt(arg) as List<int>;
}
Related
Say I have the abstract class A
abstract class A {
A.someConstructor(Foo foo);
}
and all subclasses of A should then implement such constructor:
class B extends A {
#override
B.someConstructor(Foo foo) {
// ...
}
}
So basically what I want is some kind of abstract constructors.
Is there any way of achieving this (of course the above code does not work) or do I need a normal abstract method which then creates the object and sets its properties?
EDIT: Ok so it looks like the only way to create at least a similar behaviour would be something like this:
abstract class A {
A.someConstructor(Object foo);
}
class B extends A {
B.someConstructor(Object foo) : super.someConstructor(foo) {
// ...
}
}
This isn't exactly useful, and after some thinking about my problem I realized that in fact my original goal itself is not really neccessary, so this questions is now answered.
You want to enforce a pattern on the constructors of subclasses. The Dart language has no support for doing that.
Dart has types and interfaces which can be used to restrict values and class instance members.
If a class implements an interface, then its instance members must satisfy the signatures declared by the super-interface. This restricts instance members.
If a variable has a type, for example a function type, then you can only assign values of that type to it. This restricts values. Because a class is a subtype of its interfaces, the subclass restriction means that class typed variables can be used safely (the subtype can be used as its supertype because it has a compatible interface).
There is no way to restrict static members or constructors of classes, or members of libraries, because there is no way to abstract over them. You always have to refer directly to them by their precise name, so there is no need for them to match a particular pattern.
(Which may explain why you found the goal not necessary too).
In this situation, your subclasses must call the A.someConstructor constructor, but they are free to choose the signature of their own constructors. They can do:
class B extends A {
B.someConstructor(Object foo) : super.someConstructor(foo);
}
// or
class C extends A {
C.differentName(Object foo) : super.someConstructor(foo);
}
// or even
class D extends A {
D() : super.someConstructor(new Object());
}
Constructors aren’t inherited
Subclasses don’t inherit constructors from their superclass. A
subclass that declares no constructors has only the default (no
argument, no name) constructor.
Source
Say I have the following:
class SomeObject<TModel> extends StatelessWidget {
final TModel someModel;
final Widget Function(TModel model) builder;
SomeObject({required this.someModel, required this.builder});
}
and I use this like this:
return SomeObject(someModel: SomeModel(), builder: (model) => {do something});
What I'm seeing is that SomeObject doesn't get the type of TModel inferred by SomeModel() setting someModel as I would see automatically happen in C# and thus builder: (model) is Object? instead of the correct type of someModel
How does one annotate to get dart to know that someModel being set defines the overall type of TModel for all of SomeObject and thus assign the builder: (model) to the right SomeObject automatically?
(I am not an expert on how Dart's type inference system works, so this is an educated guess.)
Given:
var object = SomeObject(someModel: SomeModel(), builder: (model) => ...);
SomeObject's type parameter isn't specified, so it must be inferred from its arguments. Its argument types are SomeModel and Function(Object). Should SomeObject be inferred from the someModel argument to be SomeObject<SomeModel>, or should it be inferred from the builder argument to be SomeObject<Object>? Both seem equally valid.
For the builder argument to be inferred as Function(SomeModel), inference would need to flow from the someModel argument out to the construction of SomeObject and then back down to the builder argument. Dart argument type inference doesn't work that way.
Additionally, since your problematic line is specifically a return statement, I suspect that the function it's from looks like:
SomeObject someFunction() {
return SomeObject(someModel: SomeModel(), builder: (model) => ...);
}
If so, you should be aware that the SomeObject return type without an explicit type parameter is shorthand for SomeObject<dynamic>1. Inference then will flow from the return type to the returned object, making it the equivalent of return SomeObject<dynamic>(...). To fix this, you should explicitly specify the return type to be SomeObject<SomeModel>, which should cause type inference to flow to the construction arguments and fix your problem.
Incidentally, you also should specify a return type for Function(TModel model) builder; declaration.
1 This can be caught by the Dart analyzer by setting strict-raw-types: true in analysis_options.yaml. See https://github.com/dart-lang/language/blob/master/resources/type-system/strict-raw-types.md for more details.
I need to implement a solution using generics that implements 3 interfaces, but as far as I can tell, generics in dart only supports 1 upper bound?
I have a model that looks like this:
abstract class Category implements Built<Category, CategoryBuilder>, Identifiable, Mapable {
...
}
The contents of the 3 interfaces is not really relevant, and what I'm trying to do, is construct a class that can process this in generic form.
What I want is something like this:
abstract class BaseDB<T extends Built<T, R> & Identifiable & Mapable, R extends Builder<T, R>> {
process(T entity) {
print(entity.id); // From Identifiable
entity.toMap(); // From Mapable
// ... etc
}
}
I know this is possible in both Typescript and Java, but I'm fairly new at Dart. Anyone know?
This is not possible in Dart. You can only put one bound on a type variable.
The bound of a Dart type variable is used to check which operations you can do on an object of the type parameter type. Example:
String something<T extends num>(T value) {
return value.abs().toString();
}
You are allowed to call abs() on value because we know that all instances of value are numbers, and num has an abs method.
If you can write <T extends Foo & Bar>, then there is no simple type in the Dart type system that can describe objects of type T. Dart does not have intersection types (the intersection type Foo & Bar would be a supertype of all types that are subtypes of both Foo and Bar, and a subtype of both Foo and Bar).
If Foo declares Baz method(), Bar declares Qux method(), and value has type T, what is the type of value.method()?
(It would either be disallowed, or the type would be Baz & Qux). This shows that allowing & in type variable bounds leaks intersection types into the remaining type system, and since Dart does not have intersection types, it also does not have multiple bounds on type variables.
When you declare a class, FooBar, implementing both Foo and Bar, you have the same issue: You need to figure out what method returns. However, the language requires you to write that solution into your class, to find some valid return type for FooBar.method, because otherwise the FooBar class declaration is not valid. It requires a user to find a solution to "find a subclass of both Baz and Qux".
A common question, specifically since Dart 2, is if it is possible to require some or all generic type arguments on some or all types - for example List<int> instead of List or MyType<Foo> instead of MyType.
It's not always clear what the intention is though - i.e. is this a matter of style (you/your team likes to see the types), to prevent bugs (omitting type arguments seems to cause more bugs for you/your team), or as a matter of contract (your library expects a type argument).
For example, on dart-misc, a user writes:
Basically, if I have this:
abstract class Mixin<T> {}
I don't have to specify the type:
// Works class Cls extends Object with Mixin<int> {} // ...also works
class Cls extends Object with Mixin {}
Is there some way to make the second one not allowed?
Strictly speaking, yes, and no.
If you want to enforce that type arguments are always used in your own projects (instead of relying on type inference or defaults), you can use optional linter rules such as always_specify_types. Do note this rule violates the official Dart style guide's recommendation of AVOID redundant type arguments on generic invocations in many cases.
If you want to enforce that generic type arguments are always used when the default would be confusing - such as List implicitly meaning List<dynamic>, no such lint exists yet - though we plan on adding this as a mode of the analyzer: https://github.com/dart-lang/sdk/issues/33119.
Both of the above recommendations will help yourself, but if you are creating a library for others to use, you might be asking if you can require a type argument to use your class. For example, from above:
abstract class Mixin<T> {}
abstract class Class extends Object with Mixin {}
The first thing you could do is add a default bounds to T:
// If T is omitted/not inferred, it defaults to num, not dynamic.
abstract class Mixin<T extends num> {}
If you want to allow anything but want to make it difficult to use your class/mixin when T is dynamic you could choose a different default bound, for example Object, or even better I recommend void:
In practice, I use void to mean “anything and I don’t care about the elements”
abstract class Mixin<T extends void> {
T value;
}
class Class extends Mixin {}
void main() {
var c = Class();
// Compile-time error: 'oops' isn't defined for the class 'void'.
c.value.oops();
}
(You could also use Object for this purpose)
If this is a class under your control, you could add an assertion that prevents the class from being used in a way you don't support or expect. For example:
class AlwaysSpecifyType<T> {
AlwaysSpecifyType() {
assert(T != dynamic);
}
}
Finally, you could write a custom lint or tool to disallow certain generic type arguments from being omitted, but that is likely the most amount of work, and if any of the previous approaches work for you, I'd strongly recommend those!
If you can figure out how to rename this question, I'm open for suggestions.
In the Dart language, one can write a class with final fields. These are fields that can only be set before the constructor body runs. That can be on declaration (usually for static constants inside a class), in an initialiser list syntax when declaring the constructor or using the this.field shorthand:
class NumBox{
final num value;
NumBox(this.value);
}
Let's say I actually needed to do some processing on instance creation and can't just initialise the field before the constructor. I can switch to using a private non-final field with a getter:
class NumBox{
num _value;
NumBox(num v) {
_value = someComplexOperation(v);
}
num get value => _value;
}
Or I can get a similar behavior using a factory constructor:
class NumBox{
final num value;
factory NumBox(num v) {
return new NumBox._internal(someComplexOperation(v));
};
NumBox._internal(this.value);
}
I hit a similar bump when I tried learning Dart a few years back and now that I have more baggage, I still don't know. What's the smarter way to do this?
A factory constructor is a good way, it allows to pre-calculate without limitations any values that you then pass to a normal constructor to forward to final fields.
An alternative way is initializer list which is executed before the constructor body and therefore allows to initializer final fields:
class NumBox{
final num value;
NumBox(num v) : value = someComplexOperation(v)
}
In the initializer list you are not allowed to read this because the instance isn't fully initialized yet.
DartPad example
You should design your API with your user in mind, then implement it in whatever way is simpler and more maintainable to you. This question is about the latter part.
Making fields final is great when it's possible, and when it isn't, making them private with a public getter is a good alternative. It's your choice what to do, because it's you who is going to maintain your class, nobody else should need to look behind the public API.
If you need a complex computation, Günther Zöchbauer's suggestion is the first to turn to: Use a helper function. In some cases, you can even do it inline
class MyThing {
final x;
MyThing(args) : x = (() { complex code on args; return result;} ());
}
It gets ugly quickly, though, so having it as a static helper function is usually better.
If your complex computation doesn't match this, which ususally means that there is more than one field being initialized with related values, then you need a place to store an intermediate value and use it more than once when initializing the object.
A factory constructor is the easy approach, you can compute everything you need and then call the private generative constructore at the end. The only "problem" is that by not exposing a generative constructor, you prevent other people from extending your class. I quoted "problem" because that's not necessarily a bad thing - allowing people to extend the class is a contract which puts restrictions on what you can do with the class.
I tend to favor public factory constructors with private generative constructors even when it's not needed for any practical reason, just to disable class extension.
class MyClass {
const factory MyClass(args) = MyClass._; // Can be const, if you want it.
const MyClass._(args) : ... init .. args ...;
}
If you need a generative constructor, you can use a forwarding generative constructor to introduce an intermediate variable with the computed value:
class MyClass {
final This x;
final That y;
MyClass(args) : this._(args, _complexComputation(args));
MyClass._(args, extra) : x = extra.theThis, y = extra.theThat, ...;
}
All in all, there is no strict rule. If you prefer final fields, you can do extra work to make them final, or you can just hide the mutability behind a getter - it's an implementation and maintainability choice, and you're the one maintaining the code.
As long as you keep the abstraction clean, and keeps track of what you have promised users (generative constructor? const constructor?) so you won't break that, you can change the implementation at any time.