Are there now two ways to use typedef in Dart? - flutter

I see multiple forms of typedef throughout dart and flutter libraries, but I can't quite make sense of it. There's this example in framework.dart:
typedef ElementVisitor = void Function(Element element);
And there's this example (https://medium.com/#castellano.mariano/typedef-in-dart-40e96d3941f9):
typedef String Join(String a, String b);
I don't quite understand the difference of their uses. Maybe this has something to do with why I can't find the definition of "Function" anywhere in the Dart or Flutter libraries. But then again I can find other typedef's just fine in the framework.dart file.

As docs refers
There is an old and new way of typedef
in general: the new way is a bit clearer and more readable.
in details:
typedef G = List<int> Function(int); // New form.
typedef List<int> H(int i); // Old form.
Note that the name of the parameter is required in the old form, but the type may be omitted. In contrast, the type is required in the new form, but the name may be omitted.
As well as
The reason for having two ways to express the same thing is that the new form seamlessly covers non-generic functions as well as generic ones, and developers might prefer to use the new form everywhere, for improved readability.
There is a difference between declaring a generic function type and declaring a typedef which takes a type argument. The former is a declaration of a single type which describes a certain class of runtime entities: Functions that are capable of accepting some type arguments as well as some value arguments, both at runtime. The latter is a compile-time mapping from types to types: It accepts a type argument at compile time and returns a type, which may be used, say, as a type annotation. We use the phrase parameterized typedef to refer to the latter. Dart has had support for parameterized typedefs for a while, and the new syntax supports parameterized typedefs as well. Here is an example of a parameterized typedef, and a usage thereof:
typedef I<T> = List<T> Function(T); // New form.
typedef List<T> J<T>(T t); // Old form.
I<int> myFunction(J<int> f) => f;
For more info

A typedef can be used to specify a function signature that we want specific functions to match. A function signature is defined by a function’s parameters (including their types). The return type is not a part of the function signature.
typedef function_name(parameters)
A variable of typedef can point to any function having the same signature as typedef.
typedef var_name = function_name
One declared a type while other assigns it to a typedef variable
https://dart.dev/guides/language/language-tour#typedefs

Related

Dart/Flutter : The meaning of "whether some code is annotated or inferred is orthogonal to whether it is dynamic or some other type"

https://dart.dev/guides/language/effective-dart/design#types
If the code is type annotated, the type was explicitly written in the
code.
If the code is inferred, no type annotation was written, and Dart
successfully figured out the type on its own. Inference can fail, in
which case the guidelines don’t consider that inferred.
If the code is dynamic, then its static type is the special dynamic
type. Code can be explicitly annotated dynamic or it can be inferred.
In other words, whether some code is annotated or inferred is
orthogonal to whether it is dynamic or some other type.
The above explanation is extremely abstract and I'm not sure exactly what this means.
Especially the last sentence, does it mean that "it may be inferred as another type even though it is type-annotated as'dyanmic'"?
But maybe I feel it's not right.
Because I remember being told by the IDE during development that something like "because it's a dynamic type, you can't access that member."
If not, I would like a more specific explanation of what it means after all.
It would be helpful if you could get some clues.
Basically, a variable can be type annotated:
int x = 1;
also, it can be inferred:
var x = 1; // dart knows x is an integer because you assigned 1 to it.
A variable can be dynamic, meaning it's type can change.
That's what the three first sentences mean, the last sentence is saying that a dynamic variable can be either inferred or annotated:
dynamic someFunction() {
return 1;
}
dynamic x = 'aaa'; // annotated
var y = someFunction(); // inferred
So weather a variable is annotated or inferred has nothing to do with weather it is dynamic or not.

Should I mark all method parameters as final and specify type

Effective dart specifies that top-level variables should be final when applicable:
https://dart-lang.github.io/linter/lints/prefer_final_fields.html
However, I could not find any information about method parameters.
Flutter repo's code functions are mostly ones with parameters not marked final, that includes all the overridden build methods I've seen.
Which of the following is better in terms of performance and app weight:
#override build(context)
#override build(BuildContext context)
#override build(final BuildContext context)
Perhaps overridden functions should be defined the same way as the super function? Is there any difference between overridden functions like build above which can infer the type, and other named/unnamed functions (other than not setting the type makes the variable dynamic), which Flutter repo also writes this way:
static double _flingDistancePenetration(double t) { // t is not final, although treated as immutable
return (1.2 * t * t * t) - (3.27 * t * t) + (_initialVelocityPenetration * t);
}
I've seen this question about Java: Why would one mark local variables and method parameters as "final" in Java?, and, while I agree with the top answer, I'm completely in the dark about why does Flutter repo not do that.
Regarding parameter types: yes, always include them. Otherwise your parameter is likely to be dynamic1, which incurs runtime overhead and no type safety. You also want your API to clearly specify what argument types it expects.
Regarding final: That is an opinion-based question, and my opinion is that while I agree with the prefer_final_fields lint, I disagree with the prefer_final_locals lint. I think that adding final for local variables (including function/method parameters) is pointless.
Contrary to what the top-voted answer to the related Java question says, any half-decent compiler should be able to easily determine whether a local variable is reassigned. If there's any optimization opportunity there, the compiler should be able to do it for you.
In languages such as Dart where implementation usually is inline with the interface (as opposed to languages such as C or C++, which have separate header files to declare interfaces), adding final to parameters is visual noise. It provides no useful information to callers.
You shouldn't unilaterally mark all function/method parameters as final anyway. Sometimes reassigning parameters is appropriate. For example, if your function needs to perform some sort of normalization on its arguments:
void foo(File file) {
file = file.absolute;
...
}
in such a case, using a final File file would mean you'd need a separate local variable for the normalized version, and now the code would be error-prone since it could accidentally use the original variable.
final for a field is an important part of an API. It tells callers that the field will not be reassigned; the object referred to by the field will always be the same object. final for local variables and for function/method parameters affects only the person implementing the function. If the implementor doesn't want to reassign a variable, they can choose to simply not reassign it.
Some people will claim that having final local variables helps code readability since they know that the variable will not be reassigned. However, I instead think that final can be misleading since it says only that a variable cannot be reassigned, not that it won't be mutated, and knowing the latter is much more important.
1 For overridden methods, parameter types are constrained by the corresponding parameter types declared by the base class. Therefore omitting a parameter type in an overridden method will use the parameter type from the base class.
Answer to the author of the question.
You should not mark all method parameters as final
You should specify the type
Examples:
foo(Baz baz)
void main(List<String> args)
An exception to these rules.
You can omit the type indication if the type is dynamic
You can don't specify type if the type can be inferred automatically by the compiler, in the case of using an function-expression.
foo(Baz baz, bar)
list.sort((x, y) => x.compareTo(y))
Some useful information:
From Dart specification:
Dart Programming Language Specification
5th edition draft
Version 2.2
A final variable is a variable whose binding is fixed upon initialization; a final variable v will always refer to the same object after v has been initialized. A variable is final iff its declaration includes the modifier final or the modifier const. A mutable variable is a variable which is not final.
Variable immutability does not make an object immutable in Dart.
This is a very common misconception when variable immutability is confused with object immutability.
P.S.
A common misconception is that Dart users get the impression that function parameters in Dart are passed by reference.
This is not true.
Parameters are passed by value (not by reference).
But due to the fact that (as indicated in the specification) any variable already contains a reference (refers) to the object (but not the object itself), in fact, this reference is passed, by value (as normal value).
That is, a value is passed, but the value itself is of the Referernce type, which is indicated in the language specification.
From Dart specification:
a final variable v will always refer to the same object
That is, the variable stores the reference, but not the value itself.
It is this reference that is passed by value, because there is no reason to pass this reference by reference.

What's the proper way to declare a field holding a function in dart?

Imagine a silly class like this:
class ConditionalWorker{
var validityChecker= (inputs)=>true;
ConditionalWorker(this.validityChecker)
...
Now my question is, what is the proper way of declaring the validityChecker field?
This tutorial suggests using typedefs. But that's not very practical. Firstly it's a chore to write a lot of typedefs that would only be used once. And secondly these typedefs show up and pollute the autocompletion of my IDE.
The var works best, with custom setters/constructor arguments to keep it always of a specific kind, but I know it's discouraged by the style guide.
I could do Function<bool> but that just a more glorified var and the amount of work is the same.
It's a shame because it's perfectly legal to have a function like this:
bool every(bool test(E element));
where the parameter is a very well defined function, but I can't have a field declared the same way:
bool test(E element);
But hopefully there is something just as good that I didn't figure out. Right?d
If you want a function type more specific than Function, you need a typedef.
If you don't like to have named typedefs for every return type, you can define generic function types yourself.
typedef R function0<R>();
typedef R function1<S,R>(S arg1);
typedef R function2<S,T,R>(S arg1. T arg2);
typedef R function3<S,T,U,R>(S arg1, T arg2, U arg3);
Then you can write:
function1<int,int> curryAdd(int x) => (int y) => x + y;
Or if function0 looks bad to you, you can name them NullaryFunction, UnaryFuncytion, BinaryFunction, TernaryFunction, or any other name that you like.
If Function<bool> is not specific enough (you also want to specify the number and type of the arguments you have to use typedefs. There are no other ways.
I'm not sure why you think it is not practical. If you want to specify the type for a field that references a value you have to use one of the existing classes or create a new one. It's the same for fields referencing functions.
With Dart 2 we can use inline function types and we need to use it instead of typedefs where possible.
With inline function types we now can define a function as a field or a property as simple as this:
final bool Function(E) test;

Does Vala have typedefs?

Does Vala have some capability to do something similar to typedef in C or alias in D? I've checked its sporadic documentation, and couldn't find anything related to this.
Not a typedef as such, but you can extend most types, including the primitives:
public struct foo : int8 { }
This will generate a typedef in the generated C, but, strictly speaking, it isn't one in Vala because it isn't a type alias (i.e., int8 and foo are not automatically interconvertible).
This doesn't work for delegates.

When do I have to specify type <T> for IEnumerable extension methods?

I'm a bit confused about the use of all the IEnumerable<T> extension methods, intellisense is always asking for <T>, but I don't think it's necessary to specify <T> at all times.
Let's say I have the following:
List<Person> people = GetSomePeople();
How is this:
List<string> names = people.ConvertAll<string>(p=>p.Name).Distinct<string>().ToList<string>();
different from this:
List<string> names = people.ConvertAll<string>(p=>p.Name).Distinct().ToList();
I think the two lines of code above are sxactly the same, now the question:
How do I know when to specify <T> and when to skip it?
The simplest way is obviously to omit it and see if it compiles.
In practice, you can omit type parameters wherever they are inferred; and they can normally be inferred when they are used in the type of a method parameter than you specify. They cannot be inferred if they're used only in the return type of the method. Thus, for example, for Enumerable.Select<T>, T will be inferred from the type of first argument (which is of type IEnumerable<T>). But for Enumerable.Empty<T>(), will not be inferred, because it's only used in return type of the method, and not in any arguments (as there are none).
Note that the actual rules are more complex than that, and not all arguments are inferable. Say you have this method:
void Foo<T>(Func<T, T> x);
and you try to call it with a lambda:
Foo(x => x);
Even though T is used in type of argument here, there's no way to infer the type - since there are no type specifications in the lambda either! As far as compiler is concerned, T is the same type x is, and x is of type T...
On the other hand, this will work:
Foo((int x) => x);
since now there is sufficient type information to infer everything. Or you could do it the other way:
Foo<int>(x => x);
The specific step-by-step rules for inference are in fact fairly complicated, and you'd be best off reading the primary source here - which is C# language specification.
This feature is known as type inference. In your example, the compiler can automatically determine the generic argument type implicitly for you because in the method call to ConvertAll, the parameter lambda returns a string value (i.e. Name). So you can even remove the <string> part of ConvertAll call. The same is with Distict(), as ConvertAll returns a List<string> and the compiler can declare the generic argument for you.
As for you answer, when the compiler can determine the type itself, the generic argument is redundant and unnecessary. Most of the times, the only place where you need to pass the generic argument is the declaration, like, List<string> list = new List<string>();. You can substitute the first List<string> with var instead or when you are using templates as parameters in lambdas too.