typedef car = void Function(String name, String type);
typedef String car (String name, String type);
What is the difference between this two syntaxes of typedef?
From the Dart language specification:
Note that the type alias syntax without ‘=’ can only express function types, and it cannot express the type of a generic function. When such a type alias is generic, it always expresses a family of non-generic function types. These restrictions exist because that syntax was defined before generic functions were added to Dart.
https://dart.dev/guides/language/specifications/DartLangSpec-v2.2.pdf
So in short, the syntax of your second example is from before generic functions was introduced in Dart and the syntax are therefore deprecated.
Related
I'm confused as to the uses of "as" keyword.
Is it a cast operator or alias operator?
I encountered the following code on the internet which looked like a cast operator:
var list = json['images'] as List;
What does this mean?
as means different things in different contexts.
It's primarily used as a type cast operator. From the Dart Language Tour:
as: Typecast (also used to specify library prefixes)
It links to an explanation of how as is also used to add a prefix to an imported library to avoid name collisions. (as was reused to do different things to avoid needing extra keywords.)
just to add the as keyword is now flagged by the linter and they prefer you to use a check like is
if (pm is Person)
pm.firstName = 'Seth';
you can read more here https://github.com/dart-lang/linter/issues/145
As the language tour says:
Use the as operator to cast an object to a particular type if and only if you are sure that the object is of that type.
Following with your example:
var list = json['images'] as List;
You would use as here to cast or convert json['images'] into a <List> object.
From another SO post (talking about explicit cast vs. as):
as ... is more like an assertion, if the values type doesn't match as causes a runtime exception.
You can also use it when importing packages. A common example is the dart:convert as JSON which then can be reached final foo = JSON.jsonDecode(baz)
It's casting, your code is similar as:
List list = json['images'];
I'm trying to pass a type in order to make use of the type information, but that types doesn't appear to be pass through.
I went back to the docs to double check that Dart generics are in fact reified and according to the docs, they are:
I call hydrate on a response which morphs the content of response object:
response.hydrate<BoqVO>();
I'm expecting T to be of type BoqVO:
class Response {
...
void hydrate<T>() {
print(T.runtimeType); // always prints _Type
if (T is BoqVO) {
print("IF");
} else {
print("ELSE"); // always goes into ELSE block
}
}
...
}
... but it's not.
Replacing response.hydrate<BoqVO>(); with response.hydrate(new BoqVO()); and changing the method signature to
void hydrate(T t) {
works if i now use lowercase t, but one shouldn't have to instantiate the object in order for reified generics to be available.
Any ideas why Dart is doing this or what i'm missing for reified generics to work correctly?
PS: I'm not on Dart 2 yet, currently on Dart 1.24.3
As Günther Zöchbauer has said, the type parameter doesn't work in Dart 1.24.
The following explains what would happen if you tried the same code in Dart 2.0, where it would also not work, because it uses the type parameter incorrectly.
The code T.runtimeType treats T as an expression. When a type, including a type parameter, is used as an expression, it evaluates to an instance of the class Type. What you print is the runtime type of that Type object (where _Type is an internal platform implementation of Type).
To print the real type, just print(T) (that still converts T to a Type object, but one representing the type BoqVO and with a toString that includes the BoqVO name).
Likewise for T is BoqVO, you evaluate T to a Type object, and since Type doesn't implement BoqVO, that test is always false. There is no simple way to test if the type of a type parameter implements a specific other type, but you can hack around it as <T>[] is List<BoqVO>.
Generic collections were supported from the beginning and they got some type support, but generic methods were only experimental in Dart 1 and reified type parameters were only added in Dart 2 pre releases.
What does a colon that's positioned after a tuple but before another type mean within a method signature?
Here's the syntax:
member this.Post (portalId : string, req : PushRequestDtr) : IHttpActionResult =
Here's the context:
type PushController (imp) =
inherit ApiController ()
member this.Post (portalId : string, req : PushRequestDtr) : IHttpActionResult =
match imp req with
| Success () -> this.Ok () :> _
| Failure (ValidationFailure msg) -> this.BadRequest msg :> _
| Failure (IntegrationFailure msg) ->
this.InternalServerError (InvalidOperationException msg) :> _
Specifically, what does this method signature mean?
Does this method take two parameters or one parameter?
I understand this:
(portalId : string, req : PushRequestDtr)
But I'm confused about this syntax that's appended to the end of it:
: IHttpActionResult
That would be the return type, i.e. the type of the value returned by the method.
From the F# online docummentation:
https://learn.microsoft.com/en-us/dotnet/articles/fsharp/language-reference/members/methods
// Instance method definition.
[ attributes ]
member [inline] self-identifier.method-nameparameter-list [ : return-type ]=
method-body
In this case return_type is IHttpActionResult, which means this method will return an object that implements the IHttpActionResult interface.
Also, although (portalId : string, req : PushRequestDtr) looks like a tuple (and in a certain way it is syntax-wise) it is not, in fact, treated as a tuple. In this case, this is a specific F# syntax for declaring method arguments while defining a method of a F# object. This is the part represented by method-nameparameter-list in the F# method template declaration. This means that the Post method receives two arguments: portalId and req, not a single argument as a tuple.
Specifically, this syntax of a list of arguments that looks like a tuple but that they are not a tuple has to be used when declaring method arguments instead of function arguments. The member keyword is the one that makes this line a method declaration instead of a function declaration.
--
Regarding the :> operator: This is a cast operator. More specifically a upcasting operator (which changes the type of a more derived type to the type of some higher type in the type hierarchy).
In this case, it is being used to explicitly tell the compiler that each branch in the match expression will return some type that is derived (or that implements) IHttpActionResult. I am not quite sure why this cast is needed (something to do with F# not being able to infer the correct type in this context, see this other question: Type mismatch error. F# type inference fail?) but in fact, it is casting every possible return value to IHttpActionResult which is the method's return type.
https://learn.microsoft.com/en-us/dotnet/articles/fsharp/language-reference/casting-and-conversions
In a fsyacc based project, I have this line:
type 'a cucomment = string
This is the full error description I'm getting:
CALast.fs(117,9): error FS0035: This construct is deprecated: This
type abbreviation has one or more declared type parameters that do not
appear in the type being abbreviated. Type abbreviations must use all
declared type parameters in the type being abbreviated. Consider
removing one or more type parameters, or use a concrete type
definition that wraps an underlying type, such as 'type C<'a> = C of
...'.
Any idea how to solve this?
F# no longer allows type aliases that add generic type parameters to a type without declaring a new type. If you want to define a generic type that wraps some other type, you have to use some constructor. For example, you can use single-case discriminated union:
type 'a Cucomment = CC of string
Unfortunately, this means that you'd have to change all code that uses the type to unwrap the value using pattern matching or by adding Value member to the type.
The only case where generic type aliases are allowed is when you declare a version of type with units of measure, which requires a special attribute. However, this is probably not going to work for you (because units behave quite differently):
[<MeasureAnnotatedAbbreviation>]
type 'a Cucomment = string
If this is in some code generated by fsyacc, then that's a bug in fsyacc that should be fixed (I think this was quite recent change). In that case, report it to fsbugs at microsoft dot com.
I have a generic function where it's easy to get the compiler to infer the wrong type parameters. The type parameters only control the return type, and if I accidentally miss off a type annotation, the compiler infers obj.
How can I make it a compile-time error to call my function without giving it explicit type parameters? The Unchecked.defaultof function works the way I'd like:
> Unchecked.defaultof;;
Unchecked.defaultof;;
^^^^^^^^^^^^^^^^^^^
stdin(1,1): error FS0685: The generic function 'defaultof' must be given explicit type argument(s)
The defaultof function uses a special attribute. The F# source code is, once again, useful. The implementation of the function is in prim-types.fs, but the attribute is added in the interface file prim-types.fsi. A combined declaration would be:
[<RequiresExplicitTypeArguments>]
let inline unsafeDefault<'T> : 'T = (# "ilzero !0" type ('T) : 'T #)
The inline IL (# ... #) is limited to F# core, but the declaration is something anybody can use.
You can find the attribute in section 16 (page 217) of the F# specification:
When applied to an F# function or method, indicates that the function or method must be given explicit type arguments when used. For example, typeof<int>.
This attribute should be used only in F# assemblies.
RequiresExplicitTypeArgumentsAttribute should help