Why a dart class constructor could have no body? - dart

I'm new to dart and came across code like below:
class Foo {
Foo._internal();
static final Foo instance = Foo._internal();
// other stuff
}
I was confused by that the function _internal is called twice(in line2 and line3 respectively).
Later I realized the first one is actually not an invocation but a definition of a constructor.
It's just that the body of the definition is omited(allowing this is really bad a syntax rule of Dart IMHO).
So my question become that in what cases a function of dart can omit body?

Dart provides a lot of syntactic sugar for constructors, including the ability to use a semicolon in place of an empty constructor body. Since initialization lists should be preferred when possible, it's not uncommon for constructors to have empty bodies, so the shorthand is useful. Additionally, redirecting constructors and const constructors aren't allowed to have bodies at all.
Constructors aren't functions, so that shorthand does not apply to functions and methods in general. (As another example of a distinction between constructors and functions, only constructors can be used with new and const.) For methods, distinguishing between no body and an empty body is important:
abstract class AbstractInterface {
void mustBeOverridden();
void optionallyOverridden() {}
}
I agree that a constructor like Foo._internal(); looks weird, but I think it's not a common situation since it requires the intersection of a number of cases to make it look like a method call:
The class uses a named constructor.
That constructor takes no arguments.
That constructor does not use an initializer list.
That constructor does not use a constructor body.

Related

Why does dart not allow method overloading?

I tried to use method overloading in some dart code and quickly learned that overloading is not offered in dart.
My questions are: why is it not offered, and what is the recommended alternative? Is there a standard naming convention since methods that do the same thing but with different inputs must have different names?
Is it standard to use named parameters and then check that the caller has supplied enough information to complete the calculation?
Say I have a method that returns how much money someone makes in a year, called yearlyIncome.
In Java, I would create a method like this
double yearlyIncome(double hourlyRate, double hoursWorkedPerYear)
And maybe another method like this
double yearlyIncome(double monthlyRate, int monthsWorkedPerYear)
and so on. They're all used to calculate the same thing, but with different inputs. What's the best, standardized way to do this in dart?
Thanks so much in advance.
Function overloading is not supported in Dart at all.
Function overloading requires static types. Dart at its core is a dynamically typed language.
You can either use different names for the methods or optional named or unnamed parameters
// optional unnamed
void foo(int a, [String b]);
foo(5);
foo(5, 'bar');
// optional named
void foo(int a, {String b});
foo(5);
foo(5, b :'bar');
Optional parameters can also have default values. Optional named and unnamed parameters can not be used together (only one or the other for a single function)
In the case of a constructor you can use named constructors as an alternative
Dart did not support overloading originally because it was a much more dynamic language where the declared types did not have any semantic effect. That made it impossible to use static type based overload resolution.
Dart has since changed to be more statically type, and there is nothing fundamentally preventing Dart from adding overloading today, except that it would be a huge work and a huge change to the language. Or so I'd assume, because there isn't any obvious design that isn't either highly complicated or hugely breaking.
What you do instead in Dart is to use optional parameters. A method like:
String toString([int radix]);
effectively have two signatures: String Function() and String Function(int). It can act at both signatures.
There are definite limits to how far you can go with just optional parameters, because they still need to have exactly one type each, but that is the alternative that Dart currently provides. (Or use different names, but that's not overloading, you can do that in languages with overloading too).
Optional parameters is also one of the complications if we wanted to add overloading to the Dart language - would existing functions with optional parameters would count as multiple overloadings? If you declare a class like:
abstract class WithOverloading {
String toString();
String toString(int radix);
}
is that then the same signature as:
abstract class WithoutOverloading {
String toString([int radix]);
}
Probably not because you can tear off the latter and get one function with an optional parameter, and you might not be able to tear off both functions from the former and combine them into one function. Or maybe you can, that's why it's not a trivial design question how to include overloading into the existing Dart language.

Is it possible to require generic type arguments on a Dart class?

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!

When should final fields, factory constructors or private fields with getters be used in dart?

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.

In Dart's Strong-Mode, can I leave off types from function definitions?

For example, I'd like to just be able to write:
class Dog {
final String name;
Dog(this.name);
bark() => 'Woof woof said $name';
}
But have #Dog.bark's type definition be () => String.
This previously wasn't possible in Dart 1.x, but I'm hoping type inference can save the day and avoid having to type trivial functions where the return type is inferable (the same as it does for closures today?)
The language team doesn't currently have any plans to do inference on member return types based on their bodies. There are definitely cases like this where it would be nice, but there are other cases (like recursive methods) where it doesn't work.
With inference, we have to balance a few opposing forces:
Having smart inference that handles lots of different cases to alleviate as much typing pain as we can.
Having some explicit type annotations so that things like API boundaries are well-defined. If you change a method body and that changes the inferred return type, now you've made a potentially breaking change to your API.
Having a simple boundary between code that is inferred and code that is not so that users can easily reason about which parts of their code are type safe and which need more attention.
The case you bring up is right at the intersection of those. Personally, I lean towards not inferring. I like my class APIs to be pretty explicitly typed anyway, since I find it makes them easier to read and maintain.
Keep in mind that there are similar cases where inference does come into play:
Dart will infer the return type of an anonymous function based on its body. That makes things like lambdas passed to map() do what you want.
It will infer the return type of a method override from the method it is overriding. You don't need to annotate the return type in Beagle.bark() here:
class Dog {
String bark() => "Bark!";
}
class Beagle extends Dog {
final String name;
Dog(this.name);
bark() => 'Woof woof said $name';
}

Why is Dart's Datetime.parse not a factory constructor?

Dart's Datetime class has a number of named constructors, but DateTime.parse() is not one of them. Instead, DateTime.parse() is a static method which returns a DateTime. To me, it makes sense as a constructor (since you are generating a new DateTime object in a manner not too different from the Datetime.utc() constructor).
Theories I've come up with are to mirror the fact that int.parse is not a constructor or to allow easier chaining (you don't need to use the cascade operator with a static method). But maybe there is another reason that I'm not thinking of. Does anyone know why they didn't make it a named constructor?
More explanation for the same change for Uri.parse: http://permalink.gmane.org/gmane.comp.lang.dart.general/17081
"parse" is special. The question is: do you see parsing as an
operation that does something and ends up giving you the result, or do
you see the string as data to construct a new element. If you see it
as the earlier, then "parse" should be a static function. If you see
the string as the data, then it should be a named constructor.
And then, of course, there is consistency.

Resources