Function foo = (int x) => x;
if (foo is Function(Object)) {
print('Bar'); // Doesn't print
}
According to me, Function(int) is a subtype of Function(Object) since type int is subtype of type Object and hence the if condition should return true but it doesn't. Why is that so?
I wasn't getting any good title for this question, feel free to change it.
It is not.
The point of subtypes is that an instance of a subtype can be used everywhere an instance of the supertype is expected (also known as "substitutability").
A Function(Object) can be called with any object as argument. It can be called with both "foo" and 42 as arguments.
A Function(int) cannot be called with a string as argument. That means that a Function(int) cannot be substituted where a Function(Object) is expected, and the type system does indeed not make Function(int) a subtype of Function(Object).
It does make Function(Object) a subtype of Function(int) instead, because if a function which can be called with any argument, then it can be used anywhere a function accepting an int argument is needed - because it accepts an int.
In general, a R1 Function(P1) function type is a subtype of R2 Function(P2) if R1 is a subtype of R2 and P2 is a subtype of P1. Notice the reverse ordering of the parameter type. Parameter types are covariant.
Think of it as: A function can be used in a place where it's given an argument of type P and is expected to return a value of type R if (and only if) it accepts any P argument and possibly more, and the values it might return must all be R values but not necessarily all R values.
That is, a function type is a subtype of R Function(P) if it accepts at least P and returns at most R.
Though it's not immediately intuitive, the subtyping is the opposite: Function(Object) is a subtype of Function(int). Indeed, a type A can be a subtype of B only if anything that holds about B, also holds about A. Function(Object) can always be called with an int argument, but Function(int) cannot be called with an arbitrary Object, so:
Function foo = (Object x) => x;
if (foo is Function(int)) {
print('Bar'); // prints!
}
In other words, functions are contravariant in the parameter type.
Related
In Kotlin I can do something like:
var myType : KClass<String>? = null
and can assign to it like:
myType = String::class
but NOT like:
myType = Int::class // Type mismatch: inferred type in KClass<Int> but KClass<String>? was expected
Is there something similar in Dart? I know of the Type type but it is not generic and while it can represent String or List<int> I seem not to be able to write similar code as my Kotlin example:
Type? t = null;
I can assign to it:
t = String;
AND also:
t = int;
but I want the second example to fail compilation. I would need some kind of Type<String>. Is this possible in Dart?
The Type class is not generic, and doesn't support subtype checks (or any other reasonable type-related operation). There is no way to use it for what you are trying to do.
So, don't. It's useless anyway. However, in Dart you can create your own type representation that is actually useful, because Dart doesn't erase type arguments, and you can then ask people using your code to ass that instead.
Say:
class MyType<T> implements Comparable<MyType>{ // Or a better name.
const MyType();
Type get type => T;
bool operator >=(MyType other) => other is MyType<T>;
bool operator <=(MyType other) => other >= this;
bool isInstance(Object? object) => object is T;
R runWith<R>(R Function<T>() action) => action<T>();
#override
int get hashCode => T.hashCode;
#override
bool operator==(Object other) => other is MyType && T == other.type;
}
With that you can write:
MyType<String?> type;
type = MyType<Null>(); // valid
type = MyType<String>(); // valid
type = MyType<Never>(); // valid
type = MyType<int>; // EEEK! compile-time error
You can use it where you need to store a type as a value.
The thing is, most of the time you can just use a type variable instead ,and creating an actual value to represent a type is overkill.
So, first try to just use a type parameter, instead of passing around Type or MyType objects. Only if that fails should you consider using MyType. Using Type is probably a mistake since it's not good for anything except doing == checks, which is antithetical to object orientation's idea of subtype subsumption.
I think this is the best you can get :
void main() {
aFunction<String>(String, '');
aFunction<String>(String, 1);
}
void aFunction<V>(Type type, V value) {
print(value.toString());
}
if you run this in a dartpad, you will see that
aFunction<String>(type, 1);
Doesn't compile.
But that's not really efficient because the type isn't guessed by Dart, you have to specify the generic type by hand.
I'm using Dart 2.17
i`m learning the flutter, but i do not understand those letters meaning.
map<T>(T f(E e)) → Iterable<T>
Returns a new lazy Iterable with elements that are created by
calling f on each element of this Iterable in iteration order. [...]
so,what do they stand for?
T:
f:
E:
e:
→:
Iterable.map<T>:
map<T>(T f(E e)) → Iterable<T>
Returns a new lazy Iterable with elements that are created by calling
f on each element of this Iterable in iteration order. [...]
T is a language Type in this case the Type of the items of the iterable and is also the type that function f must return.
→ tells you the return type of the whole function (map) in this case an Iterable of T
f is the function applied to the Element e that is passed as the parameter to the function so that the function could do some operation with this current value and then return a new value of type T based on the value of the element e.
If you navigate the Iterable map function definition you will see that:
Iterable<T> map <T>(
T f(
E e
)
)
So I wanna sharpen my answer starting with the exact map<T> function of the OP and then swich to a more complex example.
Just to clarify all these let's take a concrete class of the Iterable class, the Set class choosing a Set of type String in such a scenario:
Set<String> mySet = Set();
for (int i=0; i++<5;) {
mySet.add(i.toString());
}
var myNewSet = mySet.map((currentValue) => (return "new" + currentValue));
for (var newValue in myNewSet) {
debugPrint(newValue);
}
Here I've got a Set of String Set<String> and I want another Set of String Set<String> so that the value is the same value of the original map, but sorrounded with a prefix of "new:". And for that we could easily use the map<T> along with the closure it wants as paraemters.
The function passed as closure is
(currentValue) => ("new:" + currentValue)
And if we want we could write it also like that:
(currentValue) {
return "new:" + currentValue;
}
or even pass a function like that:
String modifySetElement(String currentValue) {
return "new:" + currentValue;
}
var myNewSet = mySet.map((value) => ("new:" + value));
var myNewSet = mySet.map((value) {return "new:" + value;});
var myNewSet = mySet.map((value) => modifySetElement("new:" + value));
And this means that the parameter of the function (closure) is the String value of the element E of the Set we're modifying.
We don't even have to specify the type because its inferred by method definition, that's one of the power of generics.
The function (closure) will be applied to all the Set's elements once at a time, but you write it once as a closure.
So summarising:
T is String
E is the element we are dealing with inside of the function
f is our closure
Let's go deeper with a more complex example. We'll now deal with the Dart Map class.
Its map function is define like that:
map<K2, V2>(MapEntry<K2, V2> f(K key, V value)) → Map<K2, V2>
So in this case the previous first and third T is (K2, V2) and the return type of the function f (closure), that takes as element E parameter the pair K and V (that are the key and value of the current MapEntry element of the iteration), is a type of MapEntry<K2, V2> and is the previous second T.
The whole function then return a new Map<K2, V2>
The following is an actual example with Map:
Map<int, String> myMap = Map();
for (int i=0; i++<5;) {
myMap[i] = i.toString();
}
var myNewMap = myMap.map((key, value) => (MapEntry(key, "new:" + value)));
for (var mapNewEntry in myNewMap.entries) {
debugPrint(mapNewEntry.value);
}
In this example I've got a Map<int, String> and I want another Map<int, String> so that (like before) the value is the same value of the original map, but sorrounded with a prefix of "new:".
Again you could write the closure (your f function) also in this way (maybe it highlights better the fact that it's a fanction that create a brand new MapEntry based on the current map entry value).
var myNewMap = myMap.map((key, value) {
String newString = "new:" + value;
return MapEntry(key, newString);
});
All these symbols are called Generics because they are generic placeholder that correspond to a type or another based on the context you are using them.
That's an extract from the above link:
Using generic methods
Initially, Dart’s generic support was limited to classes. A newer syntax, called generic methods, allows
type arguments on methods and functions:
T first<T>(List<T> ts) {
// Do some initial work or error checking, then...
T tmp = ts[0];
// Do some additional checking or processing...
return tmp;
}
Here the generic type parameter on first () allows you to use the
type argument T in several places:
In the function’s return type (T). In the type of an argument
(List<T>). In the type of a local variable (T tmp).
Follow this link for Generics name conventions.
I started reading the Rust guide on closures. From the guide:
That is because in Rust each closure has its own unique type. So, not only do closures with different signatures have different types, but different closures with the same signature have different types, as well.
Is there a way to explicitly write the type signature of a closure? Is there any compiler flag that expands the type of inferred closure?
No. The real type of a closure is only known to the compiler, and it's not actually that useful to be able to know the concrete type of a given closure. You can specify certain "shapes" that a closure must fit, however:
fn call_it<F>(f: F)
where
F: Fn(u8) -> u8, // <--- HERE
{
println!("The result is {}", f(42))
}
fn main() {
call_it(|a| a + 1);
}
In this case, we say that call_it accepts any type that implements the trait Fn with one argument of type u8 and a return type of u8. Many closures and free functions can implement that trait however.
As of Rust 1.26.0, you can also use the impl Trait syntax to accept or return a closure (or any other trait):
fn make_it() -> impl Fn(u8) -> u8 {
|a| a + 1
}
fn call_it(f: impl Fn(u8) -> u8) {
println!("The result is {}", f(42))
}
fn main() {
call_it(make_it());
}
Quoting the reference, "A closure expression produces a closure value with a unique, anonymous type that cannot be written out".
However, under conditions defined by RFC1558, a closure can be coerced to a function pointer.
let trim_lines: fn((usize, &str)) -> (usize, &str) = |(i, line)| (i, line.trim());
Function pointers can be used in .map(), .filter(), etc just like a regular function. Types will be different but the Iterator trait will be present on the returned values.
I know virtually nothing about F#. I don’t even know the syntax, so I can’t give examples.
It was mentioned in a comment thread that F# can declare functions that can take parameters of multiple possible types, for example a string or an integer. This would be similar to method overloads in C#:
public void Method(string str) { /* ... */ }
public void Method(int integer) { /* ... */ }
However, in CIL you cannot declare a delegate of this form. Each delegate must have a single, specific list of parameter types. Since functions in F# are first-class citizens, however, it would seem that you should be able to pass such a function around, and the only way to compile that into CIL is to use delegates.
So how does F# compile this into CIL?
This question is a little ambiguous, so I'll just ramble about what's true of F#.
In F#, methods can be overloaded, just like C#. Methods are always accessed by a qualified name of the form someObj.MethodName or someType.MethodName. There must be context which can statically resolve the overload at compile-time, just as in C#. Examples:
type T() =
member this.M(x:int) = ()
member this.M(x:string) = ()
let t = new T()
// these are all ok, just like C#
t.M(3)
t.M("foo")
let f : int -> unit = t.M
let g : string-> unit = t.M
// this fails, just like C#
let h = t.M // A unique overload for method 'M' could not be determined
// based on type information prior to this program point.
In F#, let-bound function values cannot be overloaded. So:
let foo(x:int) = ()
let foo(x:string) = () // Duplicate definition of value 'foo'
This means you can never have an "unqualified" identifier foo that has overloaded meaning. Each such name has a single unambiguous type.
Finally, the crazy case which is probably the one that prompts the question. F# can define inline functions which have "static member constraints" which can be bound to e.g. "all types T that have a member property named Bar" or whatnot. This kind of genericity cannot be encoded into CIL. Which is why the functions that leverage this feature must be inline, so that at each call site, the code specific-to-the-type-used-at-that-callsite is generated inline.
let inline crazy(x) = x.Qux(3) // elided: type syntax to constrain x to
// require a Qux member that can take an int
// suppose unrelated types U and V have such a Qux method
let u = new U()
crazy(u) // is expanded here into "u.Qux(3)" and then compiled
let v = new V()
crazy(v) // is expanded here into "v.Qux(3)" and then compiled
So this stuff is all handled by the compiler, and by the time we need to generate code, once again, we've statically resolved which specific type we're using at this callsite. The "type" of crazy is not a type that can be expressed in CIL, the F# type system just checks each callsite to ensure the necessary conditions are met and inlines the code into that callsite, a lot like how C++ templates work.
(The main purpose/justification for the crazy stuff is for overloaded math operators. Without the inline feature, the + operator, for instance, being a let-bound function type, could either "only work on ints" or "only work on floats" or whatnot. Some ML flavors (F# is a relative of OCaml) do exactly that, where e.g. the + operator only works on ints, and a separate operator, usually named +., works on floats. Whereas in F#, + is an inline function defined in the F# library that works on any type with a + operator member or any of the primitive numeric types. Inlining can also have some potential run-time performance benefits, which is also appealing for some math-y/computational domains.)
When you're writing C# and you need a function that can take multiple different parameter sets, you just create method overloads:
string f(int x)
{
return "int " + x;
}
string f(string x)
{
return "string " + x;
}
void callF()
{
Console.WriteLine(f(12));
Console.WriteLine(f("12"));
}
// there's no way to write a function like this:
void call(Func<int|string, string> func)
{
Console.WriteLine(func(12));
Console.WriteLine(func("12"));
}
The callF function is trivial, but my made-up syntax for the call function doesn't work.
When you're writing F# and you need a function that can take multiple different parameter sets, you create a discriminated union that can contain all the different parameter sets and you make a single function that takes that union:
type Either = Int of int
| String of string
let f = function Int x -> "int " + string x
| String x -> "string " + x
let callF =
printfn "%s" (f (Int 12))
printfn "%s" (f (String "12"))
let call func =
printfn "%s" (func (Int 12))
printfn "%s" (func (String "12"))
Being a single function, f can be used like any other value, so in F# we can write callF and call f, and both do the same thing.
So how does F# implement the Either type I created above? Essentially like this:
public abstract class Either
{
public class Int : Test.Either
{
internal readonly int item;
internal Int(int item);
public int Item { get; }
}
public class String : Test.Either
{
internal readonly string item;
internal String(string item);
public string Item { get; }
}
}
The signature of the call function is:
public static void call(FSharpFunc<Either, string> f);
And f looks something like this:
public static string f(Either _arg1)
{
if (_arg1 is Either.Int)
return "int " + ((Either.Int)_arg1).Item;
return "string " + ((Either.String)_arg1).Item;
}
Of course you could implement the same Either type in C# (duh!), but it's not idiomatic, which is why it wasn't the obvious answer to the previous question.
Assuming I understand the question, in F# you can define expressions which depend on the availability of members with particular signatures. For instance
let inline f x a = (^t : (member Method : ^a -> unit)(x,a))
This defines a function f which takes a value x of type ^t and a value a of type ^a where ^t has a method Method taking an ^a to unit (void in C#), and which calls that method. Because this function is defined as inline, the definition is inlined at the point of use, which is the only reason that it can be given such a type. Thus, although you can pass f as a first class function, you can only do so when the types ^t and ^a are statically known so that the method call can be statically resolved and inserted in place (and this is why the type parameters have the funny ^ sigil instead of the normal ' sigil).
Here's an example of passing f as a first-class function:
type T() =
member x.Method(i) = printfn "Method called with int: %i" i
List.iter (f (new T())) [1; 2; 3]
This runs the method Method against the three values in the list. Because f is inlined, this is basically equivalent to
List.iter ((fun (x:T) a -> x.Method(a)) (new T())) [1; 2; 3]
EDIT
Given the context that seems to have led to this question (C# - How can I “overload” a delegate?), I appear not to have addressed your real question at all. Instead, what Gabe appears to be talking about is the ease with which one can define and use discriminated unions. So the question posed on that other thread might be answered like this using F#:
type FunctionType =
| NoArgument of (unit -> unit)
| ArrayArgument of (obj[] -> unit)
let doNothing (arr:obj[]) = ()
let doSomething () = printfn "'doSomething' was called"
let mutable someFunction = ArrayArgument doNothing
someFunction <- NoArgument doSomething
//now call someFunction, regardless of what type of argument it's supposed to take
match someFunction with
| NoArgument f -> f()
| ArrayArgument f -> f [| |] // pass in empty array
At a low level, there's no CIL magic going on here; it's just that NoArgument and ArrayArgument are subclasses of FunctionType which are easy to construct and to deconstruct via pattern matching. The branches of the pattern matching expression are morally equivalent to a type test followed by property accesses, but the compiler makes sure that the cases have 100% coverage and don't overlap. You could encode the exact same operations in C# without any problem, but it would be much more verbose and the compiler wouldn't help you out with exhaustiveness checking, etc.
Also, there is nothing here which is particular to functions; F# discriminated unions make it easy to define types which have a fixed number of named alternatives, each one of which can have data of whatever type you'd like.
I'm not quite sure that understand your question correctly... F# compiler uses FSharpFunc type to represent functions. Usually in F# code you don't deal with this type directly, using fancy syntactic representation instead, but if you expose any members that returns or accepts function and use them from another language, line C# - you will see it.
So instead of using delegates - F# utilizes its special type with concrete or generic parameters.
If your question was about things like add something-i-don't-know-what-exactly-but-it-has-addition-operator then you need to use inline keyword and compiler will emit function body in the call site. #kvb's answer was describing exactly this case.
Could someone please show me why the function below expects integer[] instead of byte[]
type Node =
| InternalNode of int*Node*Node
| LeafNode of int * byte
let weight node =
match node with
|InternalNode(w,_,_) -> w
|LeafNode(w,_)-> w
let createNodes inputValues =
let getCounts (leafNodes:(int*byte)[])=
inputValues |>Array.iter
(fun b-> let (w,v) =leafNodes.[(int)b]
leafNodes.[(int)b]<-(w+1,v))
leafNodes
[|for b in 0uy..255uy -> (0 ,b)|] |>getCounts
|>List.ofArray
|>List.map LeafNode
The only place that tells the F# compiler something about the type of the parameter is inside the lambda function given to Array.iter (from the use of this higher-order function, the compiler infers that you're working with arrays). Inside the lambda function you have:
leafNodes.[(int)b]
As a side-note, int in this code is just a normal F# function (not a special type cast construct), so the usual way to write it would be just:
leafNodes.[int b]
Now, the compiler knows that b (that is, values of the array given as the argument) can be converted to integer, however the int function works with other types (you can write for example int 3.13f. In ambiguous cases like this, the compiler uses int as the default type, so that's the reason why you're seeing a type int[].
You can add type annotations to the declaration like this (and it will work without any other changes, because byte can be converted to integer using the int function):
let createNodes (inputValues:byte[]) =
// ...