Why Array.zeroCreate still fills null for non nullable type? - f#

Does it imply that whenever I am passed an array of a non nullable type, I should still check if it is null? Actually it is not even possible to check <> null but have to use operator.unchecked .How is it better than C#?
type test=
{
value: int
}
let solution = Array.zeroCreate 10
solution.[0] <- {value = 1}
solution.[1].value // System.NullReferenceException: Object reference not set to an instance of an object
type test =
{value: int;}
val solution : test [] =
[|{value = 1;}; null; null; null; null; null; null; null; null; null|]
val it : unit = ()

It depends where the array is being passed from.
If the array is created and used only within F#, then no, you don't need to check for null; in fact, you shouldn't check for null (using Unchecked.defaultOf) because the F# compiler optimizes some special values like [] (and None, in certain cases) by representing them as null in the compiled IL.
If you're consuming an array being passed in by code written in another language (such as C#), then yes, you should still check for null. If the calling code just creates the array and doesn't mutate it any further, then you'll only need to perform the null checks once.
EDIT : Here's a previous discussion about how the F# compiler optimizes the representation of certain values using null: Why is None represented as null?

As the documentation for Array.zeroCreate indicates, it initializes the elements to Unchecked.defaultof<_>. This therefore carries with it all of the same caveats that direct use of Unchecked.defaultof does. Generally, my advice would be to use Array.create/Array.init whenever possible, and to treat Array.zeroCreate as a possible performance optimization (requiring care whenever dealing with non-nullable types).

You're creating a record type, which is implemented as a class, which is indeed nullable. If you intended to create a struct, your code should look something like this:
type test =
struct
val value: int
new(v) = { value = v }
override x.ToString() = x.value.ToString()
end
let solution = Array.zeroCreate 10
solution.[0] <- test(1)
This outputs: val solution : test [] = [|1; 0; 0; 0; 0; 0; 0; 0; 0; 0|]
You could also write the type using the Struct attribute, saving you a level of indentation.
[<Struct>]
type test =
val value: int
new(v) = { value = v }
override x.ToString() = x.value.ToString()

Related

How to return two specific types from a generic method?

T getValue<T>(int i) {
if (T == String) return '$i'; // Error
return i; // Error
}
void main() {
var s = getValue<String>(1);
var i = getValue<int>(1);
}
I want getValue to return string if T is String and int otherwise. How to do that?
You can't restrict the type parameter to just int or String, so it will have to accept more than that (at least their least common supertype, Object, so basically any type).
It's not a particularly helpful way to code. It's possible, but not recommended:
T getValue<T>(int i) {
if (i is T) return i;
return "$i" as T;
}
This will return the int if T allows it (so T being any of int, or a super type of int, which is num, Object, dynamic or void, or any number of Comparable<X> wrappings around any any of those supertypes), and otherwise try to return a string. That will fail with a type error unless T is String (since we've already ruled out all supertypes of String).
You can still call it as getValue<bool>(42) and watch it fail, so the type argument doesn't help with correctness.
It's not particularly effective. I'd rather do:
dynamic getValue(int i, {bool toString = false}) {
if (toString) return "$i";
return i;
}
and call it as:
String x = getValue(42, toString: true); // Add `as String` if you disable downcasts.
int y = getValue(42); // And `as int` here.
The type parameter is really just making things harder. You are going to cast or type-check the result anyway, so might as well do it at the call point, rather than introduce type variables that aren't actually preventing misuse anyway.
(I'd probably just do two different functions, but I assume that there is a reason for wanting one function).
As I mentioned in the comments, I don't see any way that you could use your generic as the return type of your getValue function. Even assuming the return under the if statement worked, there is nothing that can be done about trying to return int i when List is passed as the type. You'll be trying to return an int as a List.
If you change it to dynamic, your code will work fine as it's just using the generic as another parameter.
dynamic getValue<T>(int i) {
if (T == String) return '$i';
return i;
}
void main() {
var s = getValue<String>(1);
var i = getValue<int>(1);
}

MYTYPE of type?

I have the type declaration
type MYVAL = INT of int
and want to perform arithmetic operations on constants and variables of type MYVAL, like
let a : MYVAL = 10
let b : MYVAL = 25
let c = a+b
However, when I run it, it claims that MYVAL does not support the operator +. Isn't MYVAL treated as an integer type? If it is not, what does INT of int do? How would you perform arithmetic operations of variables and constants of type MYVAL?
MYVAL is not treated as an integer type. If that's what you want, you can use a type abbreviation; type MYVAL = int. I'm not sure why you would want to do that, but it's definitely possible.
In your current definition, MYVAL is a single case discriminated union. It wraps a given type, but doesn't inherit any of the underlying type's operators. By the way, the way to construct a an INT is let a = INT 10, not let a : MYINT = 10.
If you want, you can implement your own addition operator, like so
type MYVAL = INT of int with
static member (+) (INT a, INT b) = INT(a+b)
which would allow you to do
let a = INT 10
let b = INT 25
let c = a+b
You would need to do this for any operator you want to use, e.g. (-), (*), etc.
This might all seem a bit confusing, I mean why wouldn't we want the operators to be generated automatically? Well, if you're writing a parser, you might want to be able to read either an int or a string. Such a parser might output a value of a type type MYVAL = INT of int | STRING of string. How would (+) be defined, then? How about (-)?
In the parser example, MYVAL would no longer be a single case discriminated union, as it has multiple cases. A natural question to ask is, why are single case discriminated unions interesting, then? Who would want to use anything like that? Turns out, it's quite neat for subtyping. Say you want to represent a number that's higher than 10. One way to do this is
type HigherThan10 = private Value of int with
static member TryCreate(x: int) =
if x >= 10
then Some(Value(x))
else None
let x = Value(1) // Error
let y = HigherThan10.TryCreate(1) // None
let z = HigherThan10.TryCreate(10) // Some
I know it's not the most interesting example, but it may be used for representing an email adress as a 'subtype' of string. Notice, by the way, how this avoids using exceptions for control flow by returning a HigerThan10 option.
The reason why a simple sum doesn't work was already explained. I'll just show another option: you could define a map2 function for your type:
type MYVAL =
| INT of int
static member map2 f (INT x) (INT y) = INT (f x y)
//This is the correct way to initialize MYVAL, since it is a single-case discriminated union
let a = INT 10
let b = INT 25
//sum
MYVAL.map2 (+) a b //INT 35
//mult
MYVAL.map2 (*) a b //INT 250
//mod
MYVAL.map2 (%) a b //INT 5

Using an 'is' expression when the right-hand operand is a variable?

I am trying to write a function that takes two arguments: givenType and targetType. If these two arguments match, I want givenType to be returned, otherwise null.
For this objective, I am trying to utilize Dart's is expression (maybe there is a better way to go about it, I am open to suggestions). Initially, I thought it would be as simple as writing this:
matchesTarget(givenType, targetType) {
if (givenType is targetType) {
return givenType;
}
return null;
}
But this produces an error:
The name 'targetType' isn't a type and can't be used in an 'is'
expression. Try correcting the name to match an existing
type.dart(type_test_with_non_type)
I tried looking up what satisfies an is expression but cannot seem to find it in the documentation. It seems like it needs its right-hand operand to be known at compile-time (hoping this is wrong, but it does not seem like I can use a variable), but if so, how else can I achieve the desired effect?
I cant guess the purpose of the function (or the scenario where it would be used, so if you can clarify it would be great). First of all, I don't know if you are passing "types" as arguments. And yes, you need to specify in compile time the right hand argument of the is function.
Meanwhile, if you are passing types, with one change, you can check if the types passed to your function at runtime.
matchesTarget(Type givenType, Type targetType) {
print('${givenType.runtimeType} ${targetType.runtimeType}');
if (givenType == targetType) {
return givenType;
}
return null;
}
main(){
var a = int; //this is a Type
var b = String; //this is also a Type
print(matchesTarget(a,b)); //You are passing different Types, so it will return null
var c = int; //this is also a Type
print(matchesTarget(a,c)); //You are passing same Types, so it will return int
}
But if you are passing variables, the solution is pretty similar:
matchesTarget(givenVar, targetVar) {
print('${givenVar.runtimeType} ${targetVar.runtimeType}');
if (givenVar.runtimeType == targetVar.runtimeType) {
return givenVar.runtimeType;
}
return null;
}
main(){
var a = 10; //this is a variable (int)
var b = "hello"; //this is also a variable (String)
print(matchesTarget(a,b)); //this will return null
var c = 12; //this is also a variable (int)
print(matchesTarget(a,c)); //this will return int
}
The Final Answer
matchesTarget(givenVar, targetType) {
print('${givenVar.runtimeType} ${targetType}');
if (givenVar.runtimeType == targetType) {
return givenVar;
}
return null;
}
main(){
var a = 10; //this is a variable (int)
var b = String; //this is a type (String)
print(matchesTarget(a,b)); //this will return null because 'a' isnt a String
var c = int; //this is also a type (int)
print(matchesTarget(a,c)); //this will return the value of 'a' (10)
}
The as, is, and is! operators are handy for checking types at runtime.
The is operator in Dart can be only used for type checking and not checking if two values are equal.
The result of obj is T is true if obj implements the interface specified by T. For example, obj is Object is always true.
See the below code for an example of how to use the is operator
if (emp is Person) {
// Type check
emp.firstName = 'Bob';
}
Even the error message that you're getting says that
The name 'targetType' isn't a type and can't be used in an 'is'
expression.
So the bottomline is that you can use is only for checking if a variable or value belongs to a particular data type.
For checking equality, you can use the == operator if comparing primitive types, or write your own method for comparing the values. Hope this helps!

When should I use let, member val and member this.?

F# has many different ways to define variables/members in types. When should I use let, member val and member this. in F#, and what is the difference between them? How about static and mutable members?
The answer from #meziantou already gives a nice overview of the options (and how they behave differently), so let me just give a brief summary, or list of recommendations:
Use let or let mutable if you want to define a local value that is visible only within the type (essentially a private field or a private function). Inside a module at top-level, these are publicly accessible and evaluated once. let mutable at module level creates a single writable field with no backing value.
You can use val to create an auto-property, it is short for member val Foo = .. with get. From F# this is seen as a field, but it's internally implemented as a get-property with a backing field to prevent mutation.
You can use val mutable to define a public field, but I wouldn't recommend this unless you actually need a public field (e.g. some .NET library may require types with this structure).
Using member x.Foo = ... is the best way to expose (read-only) state from a type. Most F# types are immutable, so this is perhaps the most common public member. It is short for a get-only instance property.
Using member x.Foo with get() = .. and set(value) ... is useful when you need to create a get/set property with your own custom code in the gettor and settor. This is sometimes useful when you're creating a mutable object.
Using member val Foo = ... with get, set is basically the same thing as auto-implemented properties in C#. This is useful if you need a mutable property with a getter and setter that just reads/writes a mutable backing field.
Using static let on a type creates a static (class-level) read-only field, which internally creates a property with a backing field. Use static mutable let ... for a read/write static field without a backing field.
Using static val mutable private creates a static read/write auto-property with a backing field, it cannot be public.
I found out easier to just decompile what's happening, so:
type Region() =
let mutable t = 0.0f
member val Width = 0.0f
member x.Height = 0.0f
member val Left = 0.0f with get,set
member x.Top with get() = 0.0f and set(value) = t <- value
is actually the following:
public class Region
{
internal float t;
internal float Width#;
internal float Left#;
public float Width
{
get
{
return this.Width#;
}
}
public float Height
{
get
{
return 0f;
}
}
public float Left
{
get
{
return this.Left#;
}
set
{
this.Left# = value;
}
}
public float Top
{
get
{
return 0f;
}
set
{
this.t = value;
}
}
public Region() : this()
{
this.t = 0f;
this.Width# = 0f;
this.Left# = 0f;
}
}
This sample explains the difference between syntaxes:
type MyClass() =
let random = new System.Random()
[<DefaultValue>] val mutable field : int
member val AutoProperty = random.Next() with get, set
member this.ExplicitProperty = random.Next()
let c = new MyClass()
// c.random is not accessible
c.field <- 42 // 'field' is accessible
// An automatic property is only evaluated upon initialization, and not every time the property is accessed
printfn "AutoProperty = %d" c.AutoProperty // x
printfn "AutoProperty = %d" c.AutoProperty // Still x
// The value of the explicit property is evaluated each time
printfn "ExplicitProperty = %d" c.ExplicitProperty // y
printfn "ExplicitProperty = %d" c.ExplicitProperty // The value is re-evaluated so you'll get a different value

Difference between "var" and "dynamic" type in Dart?

According to this article:
As you might know, dynamic (as it is now called) is the stand-in type when a static type annotation is not provided.
So, what is the difference between dynamic and var? When to use?
dynamic is a type underlying all Dart objects. You shouldn't need to explicitly use it in most cases.
var is a keyword, meaning "I don't care to notate what the type is here." Dart will replace the var keyword with the initializer type, or leave it dynamic by default if there is no initializer.
Use var if you expect a variable assignment to change during its lifetime:
var msg = "Hello world.";
msg = "Hello world again.";
Use final if you expect a variable assignment to remain the same during its lifetime:
final msg = "Hello world.";
Using final (liberally) will help you catch situations where you accidentally change the assignment of a variable when you didn't mean to.
Note that there is a fine distinction between final and const when it comes to objects. final does not necessarily make the object itself immutable, whereas const does:
// can add/remove from this list, but cannot assign a new list to fruit.
final fruit = ["apple", "pear", "orange"];
fruit.add("grape");
// cannot mutate the list or assign a new list to cars.
final cars = const ["Honda", "Toyota", "Ford"];
// const requires a constant assignment, whereas final will accept both:
const names = const ["John", "Jane", "Jack"];
dynamic: can change TYPE of the variable, & can change VALUE of the variable later in code.
var: can't change TYPE of the variable, but can change VALUE of the variable later in code.
final: can't change TYPE of the variable, & can't change VALUE of the variable later in code.
dynamic v = 123; // v is of type int.
v = 456; // changing value of v from 123 to 456.
v = 'abc'; // changing type of v from int to String.
var v = 123; // v is of type int.
v = 456; // changing value of v from 123 to 456.
v = 'abc'; // ERROR: can't change type of v from int to String.
final v = 123; // v is of type int.
v = 456; // ERROR: can't change value of v from 123 to 456.
v = 'abc'; // ERROR: can't change type of v from int to String.
try this in DartPad:
void main() {
dynamic x = 'hal';
x = 123;
print(x);
var a = 'hal';
a = 123;
print(a);
}
you can change the type of x, but not a.
var, like final, is used to declare a variable. It is not a type at all.
Dart is smart enough to know the exact type in most situations. For example, the following two statements are equivalent:
String a = "abc"; // type of variable is String
var a = "abc"; // a simple and equivalent (and also recommended) way
// to declare a variable for string types
On the other hand, dynamic is a special type indicating it can be any type (aka class). For example, by casting an object to dynamic, you can invoke any method (assuming there is one).
(foo as dynamic).whatever(); //valid. compiler won't check if whatever() exists
(foo as var).whatever(); //illegal. var is not a type
var a ;
a = 123;
print(a is int);
print(a);
a = 'hal';
print(a is String);
When defined without initial value, var is dynamic
var b = 321;
print(b is int);
print(b);
//b = 'hal'; //error
print(b is String);
When defined with initial value, var is int in this case.
To clarify some of the previous answers, when you're declaring a variable as dynamic, it's type changes depending on what you assign to it. When you're declaring a var, the type is set once it's assigned something, and it cannot be changed after that.
For example, the following code:
dynamic foo = 'foo';
print('foo is ${foo.runtimeType} ($foo)');
foo = 123;
print('foo is ${foo.runtimeType} ($foo)');
will return the following result when run in DartPad:
foo is String (foo)
foo is int (123)
But the following code won't even compile:
var bar = 'bar';
print('bar is ${bar.runtimeType} ($bar)');
bar = 123; // <-- Won't compile, because bar is a String
print('bar is ${bar.runtimeType} ($bar)');
Long story short - use dynamic if you want a non-typed variable, use var when you want a typed variable with whatever type you assign to it.
Looking at the previous answers I hope this can clarify/summarize everything:
There are the keywords var, final, and const. These are to declare a variable (to indicate its existence) (Side note: Declaration vs Initialization)
Then there are types like String, int, List, dynamic, etc. (The type indicates what kind of value the variable should hold, this is for type safety)
Usually, we declare a variable by explicitly stating its type:
String a; // a is now a String type
int b; // b is now an int type
But we can also use the var keyword. By default, this sets the type of the variable to whatever it is initialized with. (This is called type inference)
var a = "hello"; // a is now a String type
var b = 5; // b is now an int type
Now what happens when you try to declare a variable with the var keyword, but don't initialize a value? How is it supposed to infer a type? Well, there is also a type called dynamic. This is different than the usual String or int in the sense that it allows for the variable to be assigned a value of any type (Usually there will be an error).
String a = "hello"; // a is now a String type
// var a = "hello"; // Alternative way; same as the line above because its type is inferred to be String
a = 5 // error: A value of type 'int' can't be assigned to a variable of type 'String'
dynamic b; // b is now a dynamic type
b = "hello"; // still a dynamic type, but now its value is of type String (You can use b.runtimeType to check)
b = 5; // dynamic type, but now its value is of type int
So to address the original confusion regarding the quote from the article,
As you might know, dynamic (as it is now called) is the stand-in type when a static type annotation is not provided.
It just means that if you don't explicitly state its type (you use var to declare a variable) and do so without initialization, it simply infers its type as dynamic:
var b; // b is now a dynamic type, the following will not have any errors.
b = "hello";
b = 5;
b = true;
Other notes:
Not sure why people started talking about final and const, but I think the accepted answer here explains it well if you want to know more.
dynamic a; and var a; is effectively the same: They both declare a variable of dynamic type.
Two ways of checking the type of a variable is using the is operator and using .runtimeType which works differently. See the following example:
dynamic b; // b is now a dynamic type, no value
print(b is dynamic); // true
print(b is Null); // true
print(b is String); // false
print(b is int); // false
print(b.runtimeType); // Null
b = "hello"; // dynamic type, String value
print(b is dynamic); // true
print(b is Null); // false
print(b is String); // true
print(b is int); // false
print(b.runtimeType); // String
b = 5; // dynamic type, int value
print(b is dynamic); // true
print(b is Null); // false
print(b is String); // false
print(b is int); // true
print(b.runtimeType); // int
One of aspect than can consider in comparison dynamic vs var is taking into account behavior when using var declaration with initialization at the same time there is not possibility to change type which in case of dynamic is.
But dynamic vs var is not the question what I would ask.
I would ask more what is difference between dynamic vs Object.
Here is a DO annotate with Object instead of dynamic to indicate any object is allowed.
It is hard to feel it at the beginning, but dynamic I would relate to generic type argument.
Both in dynamic and var,the variable can hold data of any data type, i.e., int , float,string,etc
If a variable is declared as a dynamic and if even initialised, its type can change over time.Try this code in https://dartpad.dev/
void main() {
dynamic x = 'abc';
x = 12345;
print(x);
}
If you declare variable as a var, once assigned type can not change.
void main() {
var x = 'abc';
x = 12345;
print(x);
}
The above code will result in the error stating that A value of type 'int' can't be assigned to a variable of type 'String' - line 3
BUT, if you state a var without initializing, it becomes a dynamic:
void main() {
var x ;
x = 'abc';
x=12345;
print(x);
}
A dynamic variable can change his type and a var type can't be changed.
For example :
var myVar = 'hello';
dynamic myDynamicVar = 'hello';
myVar = 123; // not possible
myDynamicVar = 123; // possible
dynamic is a data type that indicates all data types in dart
var is a variable declaration way like "final" that takes the data type of its value
If you use var you can't change the data type of the variable. But if you use dynamic you can change it freely.
for ex.
dynamic x = 12; // type: integer
x= "Hello world"; // type: string
This will work with no issues if you do the same using var instead of dynamic you will get an error since you can't change the data type because it is automatically assigned to the variable when initialized.
dynamic: can change the TYPE of the variable, & can change the VALUE of the variable later in the code.
var: can't change the TYPE of the variable, but can change the VALUE of the variable later in code

Resources