Dart Language
What is the equivalent operator for the "as" operator in type checking during runtime?
var foo = new Teacher();
var bar = new Student();
like (foo as Teacher);
Output
Instance ofTteacher
The equivalent operator is "is"
(foo is Teacher) should return true or false accordingly if foo is of type Teacher or otherwise.
Key word as is used for type conversion.
If you want to check foo is Teacher or not:
print(foo is Teacher);
print(bar is Student);
If you just want to get Type of foo:
final fooType = foo.runtimeType;
final barType = bar.runtimeType;
print(fooType == barType);
Both fooType and barType is instance of Type.
Related
Can I get strongly typed value from an Object, something like this:
Object obj;
final fooOrBar = obj as (flag ? Foo : Bar); // Error
fooOrBar should be either of type Foo or Bar but this gives me an error.
Note:
I don't want to do things like:
if (flag) {
final foo = obj as Foo;
} else {
final bar = obj as Bar;
}
You cannot do what you are asking for.
A variable has one type, determined at compile-time.
Since flag is not known at compile-time, it cannot affect the type of the variable fooOrBar.
You also cannot abstract over types like that. The thing after as must be a single type.
You can do
var fooOrBar = flag ? obj as Foo : obj as Bar;
but the static type of fooOrBar will likely be Object anyway, or at least some common supertype of Foo and Bar. Then you might as well just cast directly to that: var castObj = obj as CommonSupertypeOfFooAndBar;.
You can use helper functions:
Foo asFoo(Object o) => o as Foo;
Bar asBar(Object o) => o as Bar;
//...
var fooOrBar = (flag ? asFoo : asBar)(obj);
Again, the type won't be Foo or Bar, but some supertype of both.
If you actually care about the type of fooOrBar being either precisely Foo or precisely Bar, you need two different variables.
Can someone clarify when to use typedefof<'T> vs. typeof<'T>?
Both typedefof<System.String> and typeof<System.String> return the same Type instance.
However, they return different instances and different information for System.Collections.Generic.List<_>.
Can I think of typedefof as a new and improved typeof? Should I just switch to always using typedefof? Or is it more subtle than that?
This ought to illustrate the difference. When you use typeof, the compiler infers type arguments and constructs a concrete type. In this case, the inferred type argument is System.Object:
let t1 = typeof<System.Collections.Generic.List<_>>
let t2 = typedefof<System.Collections.Generic.List<_>>
printfn "t1 is %s" t1.FullName
printfn "t2 is %s" t2.FullName
Output:
t1 is System.Collections.Generic.List`1[[System.Object, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
t2 is System.Collections.Generic.List`1
Because typeof can only return a constructed type, typedefof is necessary if you need a type object representing a generic type definition.
typeof is used when you want to get the System.Type object for a given type. typedefof is used when you want to get the System.Type that represents the type definition for a generic type. As an example that uses both, suppose you had a type called Generic<'a>, and you wanted to create a function that returned the System.Type object for the Generic of any given type.
type Generic<'a> = Value of 'a
let makeGenericOf<'a> () =
typedefof<Generic<_>>.MakeGenericType(typeof<'a>)
Here, you would use the typedefof function to get the type defintion, and typeof to get the type of 'a for constructing the generic Generic<'a> Type.
I really appreciate the answers from phoog, Aaron, and JLRishe. Here is what I have learned, based on their answers and my own experimentation.
There are two Type instances associated with generics.
There is a Type associated with a generic that has specific type parameters. For example, there is a Type associated with List<int> and a different Type associated with List<string>. This is what you get when you use typeof<>.
> typeof<List<string>>.ToString();;
val it : string = "Microsoft.FSharp.Collections.FSharpList`1[System.String]"
> typeof<List<int>>.ToString();;
val it : string = "Microsoft.FSharp.Collections.FSharpList`1[System.Int32]"
There is a Type associated with the generic type definition itself. For example, there is a single Type associated with List<'T>, which is the same for List<int>, List<string>, and List<_>. This is what you get when you use typedefof<>.
> typedefof<List<string>>.ToString();;
val it : string = "Microsoft.FSharp.Collections.FSharpList`1[T]"
> typedefof<List<int>>.ToString();;
val it : string = "Microsoft.FSharp.Collections.FSharpList`1[T]"
> typedefof<List<_>>.ToString();;
val it : string = "Microsoft.FSharp.Collections.FSharpList`1[T]"
By the way, the Type class has an instance method to GetGenericTypeDefinition(). That means, the following two return the same instance:
> Object.ReferenceEquals(typeof<List<int>>.GetGenericTypeDefinition(), typedefof<List<int>>);;
val it : bool = true
What happens if you call typeof<List<_>>? You get back the Type definition for List<Object>, as phoog mentioned.
> typeof<List<_>>.ToString();;
val it : string = "Microsoft.FSharp.Collections.FSharpList`1[System.Object]"
This is all helpful to understand. For example, suppose I need to know if an object is a generic list (of any type).
// does not give me the answer I naively expected
> o.GetType() = typeof<List<_>>;;
val it : bool = false
// does this reference point to a List<'T>?
> o.GetType().IsGenericType && o.GetType().GetGenericTypeDefinition() = typedefof<List<_>>;;
val it : bool = true
Additionally, if you want to late-bound instantiate a generic type, you can use the MakeGenericType(...) method which Aaron mentioned.
> let myList = typedefof<List<_>>.MakeGenericType(typeof<int>);;
val myList : Type = Microsoft.FSharp.Collections.FSharpList`1[System.Int32]
Is it possible to test the type of an object in Dart using an instance of Type stored in a variable? e.g.
Foo foo = new Foo();
Type testtype = Foo;
if (foo is testtype) {
print("foo matched testype");
}
This gives me the following warning:
The name 'testtype' is not a type and cannot be used in an 'is' expression
Is there a way of doing this?
Ultimately I want to pass the Type into a function as a parameter which then performs the "is" type test using this.
Foo foo = new Foo();
Type testtype = Foo;
if (foo.runtimeType == testtype) {
print("foo matched testype");
}
If (foo.runtimeType == testtype.runtimeType)
type SQLConn =
val mutable private connection : string option
member this.Connection
with get() : string = this.connection.Value
and set(v) = this.connection <- Some v
new (connection : string) = {connection = Some connection;}
new() = SQLConn #"Data Source=D:\Projects\AL\Service\ncFlow\dbase\dbflow.db3; Version=3;Password=432432434324"
I want to use "let x = 5+5" there or something like that, so how can I use private functions in my type (class) (record) , I know that I can use them if I do SQLConn() , but then I can't use val, I want to use both : val and let ...
thank you
As Tim explains, you can only use local let bindings with the implicit constructor syntax. I would definitely follow this approach as it makes F# code more readable.
Do you have any particular reason why you also want to use val in your code? You can still use them with the implicit constructor syntax, but they have to be mutable and initialized using mutation:
type SQLConn(connection:string) as x =
let mutable connection = connection
// Declare field using 'val' declaration (has to be mutable)
[<DefaultValue>]
val mutable a : int
// Initialize the value imperatively in constructor
do x.a <- 10
member this.Connection
with get() = connection and set(v) = connection <- v
new() = SQLConn #"Data Source=.."
As far as I can tell val is only needed to create fields that are not private (which may be required by some code-gen based tools like ASP.NET, but is otherwise not really useful).
The error message explains the problem:
error FS0963: 'let' and 'do' bindings are not permitted in class definitions unless an implicit construction sequence is used. You can use an implicit construction sequence by modifying the type declaration to include arguments, e.g. 'type X(args) = ...'.
The error message is suggesting that you declare your class as type SQLConn(connection) =. If you do this, you probably ought to remove the member this.Connection property, since you'll no longer have a mutable field.
A more likely workaround would be to declare x as val x : int, then put the x = 5 + 5; initializer inside your constructor.
What about the following?
type SQLConn(conn:string) =
// could put some other let bindings here...
// ex: 'let y = 5 + 5' or whatever
let mutable conn = conn
new() = SQLConn(#"some default string")
member __.Connection
with get () = conn and set v = conn <- v
Consider my first attempt, a simple type in F# like the following:
type Test() =
inherit BaseImplementingNotifyPropertyChangedViaOnPropertyChanged()
let mutable prop: string = null
member this.Prop
with public get() = prop
and public set value =
match value with
| _ when value = prop -> ()
| _ ->
let prop = value
this.OnPropertyChanged("Prop")
Now I test this via C# (this object is being exposed to a C# project, so apparent C# semantics are desirable):
[TestMethod]
public void TaskMaster_Test()
{
var target = new FTest();
string propName = null;
target.PropertyChanged += (s, a) => propName = a.PropertyName;
target.Prop = "newString";
Assert.AreEqual("Prop", propName);
Assert.AreEqual("newString", target.Prop);
return;
}
propName is properly assigned, my F# Setter is running, but the second assert is failing because the underlying value of prop isn't changed. This sort of makes sense to me, because if I remove mutable from the prop field, no error is generated (and one should be because I'm trying to mutate the value). I think I must be missing a fundamental concept.
What's the correct way to rebind/mutate prop in the Test class so that I can pass my unit test?
As a side-note, I would probably use if .. then instead of the match construct as it makes the code more succinct (patterh matching is especially valuable when you need to test the value agains multiple complex patterns). Also, public is the default access for member, so you can make the code a bit more succinct:
type Test() =
inherit BaseImplementingNotifyPropertyChangedViaOnPropertyChanged()
let mutable prop : string = null
member this.Prop
with get() = prop
and set(value) =
if value <> prop then
prop <- value
this.OnPropertyChanged("Prop")
Try this:
type Test() =
inherit BaseImplementingNotifyPropertyChangedViaOnPropertyChanged()
let mutable prop: string = null
member this.Prop
with public get() = prop
and public set value =
match value with
| _ when value = prop -> ()
| _ ->
prop <- value
this.OnPropertyChanged("Prop")
You need to make the binding mutable and then alter its value in your setter. In your initial code, you were just creating a new binding (also called prop) within your setter, so no change was visible.
In your pattern match you are actually binding a new value with
let prop = value
When you bind a value like this with the same name, it will shadow the other value for the scope of the newly declared one. I believe what you actually want to do is this:
prop <- value