What is the different between these two void methods in Dart? - dart

Code:
void main() { runApp(MyApp());}
And
Code:
Void main() => runApp(MyApp());

I will go with the detailed explanation it might help you with depth.
Functions in Dart behave much like function in JavaScript. They can be defined as a method similar to our void function, as well as, they behave like first-class objects meaning they can be stored in a variable, passed as an argument or returned like a normal return value of a function.
As you can see from the above example, there are many ways to create a function. A function that does not define a return type (like using var syntax) has a return type of dynamic. If parameters in function definition have no types, they implicitly have the dynamic type.
Fat Arrow Expression
Fat Arrow Expression or Lambda Function Expression is a syntax to write a function on a single line using => syntax AKA fat arrow. This resembles the ES6 Fat Arrow function syntax of JavaScript. This is a cleaner way to write functions with a single statement.

There is very little difference.
A function of the form SomeType name(args) => expression; is almost entirely equivalent to SomeType name(args) { return expression; }.
Dart's void type is slightly different from other similar language's use of void. The type is not an empty type, instead it's equivalent to Object? in that it can contain any value, it just statically prevents you from using the value.
This design was chosen originally in Dart 1 because it allowed a method returning a useful value to override a method which returned void.
Dart generally disallows a return value; statement in a void returning function, because it's probably a mistake, unless the type of value is itself void (or dynamic or Null).
So
void main() => runApp(MyApp());
is equivalent to
void main() {
return runApp(MyApp());
}
but since main has a return type of void (and because it's the main method), no-one is ever going to look at the returned value.
So, in short, you can use => voidExpression; as shorthand for { voidExpression;} because no-one is going to notice the returned value.

There isn't a difference in terms of logic.
We use:
void main() => runApp(MyApp());
when the function just uses a single line. However, we use the angle brackets "{}" to indicate a complication of different lines.
For example:
void main() {
runApp(MyApp());
}
Notice the use of more than one line.
Usually in your case, you wouldn't use the second method and id suggest you stick to the first one.
Hope it helped! :)

Related

Specify callback function in dart/flutter that accepts two possible sets of parameters

Is there a way to create a callback function that accepts one of two different sets of parameters? Or have two separate callback functions as options, and make sure at least one of them is specified?
I have a view that I want to pass a callback function, that either includes a Goal or a title and description (which would end up being put together into a goal).
void Function({required String title, String? description}) onGoalPopupCompletionWithString;
void Function({required Goal goal}) onGoalPopupCompletionWithGoal;
I want one, but not both of these callbacks to be required - if there is a function with a goal as a parameter, I'd execute that, but if not, I'd execute the one with a String title and a String description. Something like this:
if (onGoalPopupCompletionWithGoal != null) {
// execute this callback function
} else {
// execute onGoalPopupCompletionWithString
}
That's not something which can be expressed in the Dart type system.
A single function which can be called as void Function({required String title, String? description}) or void Function({required Goal goal}) will have a signature of:
void Function({String title, String? description, Goal goal})
Any implementation of that type will either have to make title and goal optional, or provide them with default values.
In either case, there is no way, in the type system, to ensure that the function is always invoked as one of the original types.
Also, it'll be highly annoying to write, you'd probably be better off with two different callbacks.
You can provide two callback parameters, one of each kind, and require that at least one of them is required ... but not in the type system. You'd have to make both optional, and check at runtime that at least one was provided.
Having as single parameter which accepts either function type, that requires a union type. A union type allows either one type or another, in this case either void Function({required String title, String? description}) or void Function({required Goal goal}). Dart does not have union types in general.
If you need to pass both of these types through the same currently valid Dart type, the type needs to be a supertype of both.
The closest common supertype of those two types is Function.
(The only function types that void Function({required Goal goal}) can be assigned to are void Function({required X goal}) where X is a subtype of Goal. I guess you can also change the void to another, equivalent, top-type.
Any other function type allows its functions to be called in a way that void Function({required Goal goal}) does not.)
Dart does have one kind of type union: Classes with subclasses.
You can declare a callback class:
abstract class MyCallback {
}
class TitleCallback extends Callback {
final void Function({required String title, String? description}) callback;
TitleCallback(this.callback);
}
class GoalCallback extends Callback {
final void Function({required Goal goal}) callback;
GoalCallback(this.callback);
}
Then you can require one such callback, and dispatch on it as necessary.

Dart: How to require function to pass constant values as arguments

I have a function fun that requires a constant value val of type MyType (that can be constant), something like this:
/// [val] should only accept constant values
void fun(MyType val) {
...
}
So, for example, this would work:
fun(const MyType('Hello'));
But not this:
var randomValue = Random().nextDouble().toString();
fun(MyType(randomValue));
Is fun possible in Dart?
According to Christopher Moore in a comment, this is not possible. As a result, an alternative solution is needed and it will vary depending on your particular use case.
For my specific use case, the alternative that I came up with is to use a class that uses the singleton and builder patterns.

Generic paramater that itself is generic

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>;
}

What does that 2 dots mean? What is the difference between 1 and 2?

I have seen a lot of tutorials using dot, while some use 2. What is the actual meaning of this?
Example,
Array().add()
Animation()..addListener(() {})
The .. operator is dart "cascade" operator. Useful for chaining operations when you don't care about the return value.
This is also dart solution to chainable functions that always return this
It is made so that the following
final foo = Foo()
..first()
..second();
Is strictly equals to this:
final foo = Foo();
foo.first();
foo.second();
Just to be a nitpicker, .. isn't actually an operator in Dart, just part of Dart's syntactic sugar.
In addition to the mentioned use of cascades for chaining calls to functions, you can also use it to access fields on the same object.
Consider this code, taken from the Dart documentation:
querySelector('#confirm') // Get an object.
..text = 'Confirm' // Use its members.
..classes.add('important')
..onClick.listen((e) => window.alert('Confirmed!'));
The first method call, querySelector(), returns a selector object. The code that follows the cascade notation operates on this selector object, ignoring any subsequent values that might be returned.
For more information about cascades, check out Dart's outstanding documentation!

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';
}

Resources