If I try this type definition in Visual Studio Express 2013, I get an error:
type Foo(bar : int) =
struct
member x.bar = bar
end
If I change it so that it is a class instead, I don't get any errors:
type Foo(bar : int) =
class
member x.bar = bar
end
The error I get is:
The member 'bar' can not be defined because the name 'bar' clashes with the field 'bar' in this type or module"
The error goes away if I change the constructor parameter's name slightly. I understand the differences between CLR structs and classes in general, but I don't quite understand the reason for this difference in behaviour. Can anyone explain it?
I'm mostly asking in case the answer dispels some deeper misunderstanding that I have about F#. Thanks.
Although I can't find a pertinent reference in the spec offhand, a little experimentation with a decompiler shows that primary constructor parameters on structs are always compiled as fields with the same name. For classes, a more complex set of rules (see §8.6.1.3) is used to determine their compiled form, which includes munging field names when they would otherwise clash with members.
Compare the compiled forms of this struct and class:
type S(bar: int) = struct end
type C(bar: int) =
member x.bar = bar
public class C
{
internal int bar#12;
public int bar
{
get
{
return this.bar#12;
}
}
public C(int bar)
{
this.bar#12 = bar;
}
}
public struct S : IEquatable<Program.S>, IStructuralEquatable, IComparable<Program.S>, IComparable, IStructuralComparable
{
internal int bar;
public S(int bar)
{
this.bar = bar;
}
}
The struct's primary constructor parameter is compiled as a field (and assigned!) even though it's unused. The class, on the other hand, allows a member and parameter with the same name. Admittedly, this doesn't explain why, but may help to clarify the observed behavior.
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
In a c# dll I have a method, that takes func parameters:
public static AttrDiffRule Create<T>(string a_attr, string b_attr, Func<IAttrProxy,IAttrProxy,T,bool> parametricRule, T ruleParam, string desc = null)
and some predefined default methods intended for it:
public static bool NumberEqualsWithTolerance(IAttrProxy a, IAttrProxy b, double tolerance)
Now when using this in C#, I can write the following and it works:
var tmp = DefaultRules.Create("fds", "fds", DefaultRules.NumberEqualsWithTolerance, 10.0);
But, in F# this:
let attrRule = DefaultRules.Create("fd","fdsa", DefaultRules.NumberEqualsWithTolerance, 89.)
gives syntax error: "Error FS0002 This function takes too many arguments, or is used in a context where a function is not expected"
What would be the correct way to pass a C# static method into a parameter expecting a Func<> in F#?
It is important to actually pass in the function, and not a lambda wrapper, because the Create method's job is to use the argument function's MethodInfo, which gets hidden by the lambda wrapper's one.
The passed in function does not have overloads, also tried with specifying the type in place like
(DefaultRules.NumberEqualsWithTolerance : Func<IAttrProxy,IAttrProxy,float,bool>)
This is a case of F# being very thoughtful on your behalf - by helping you write more idiomatic F#.
In .NET, you are not actually passing in the function, as if it's a member reference, rather you are passing in a delegate object of type Func<>. The construction of the delegate object is done implicitly by C# when it has the necessary type information.
We can see this more clearly if we refactor this into an actual delegate type:
public delegate bool ParametricRule<T>(IAttrProxy a, IAttrProxy b, T value);
public static AttrDiffRule Create<T>(string a_attr, string b_attr, ParametricRule<T> parametricRule, T ruleParam, string desc = null)
{
return default;
}
If you try to construct a ParametricRule in F#, you'll see that its type is:
ParametricRule(IAttrProxy -> IAttrProxy -> 'a -> bool)
The rationale is that this way you can use regular F# functions, instead of some un-F#ish tupled input function. And this why it doesn't work in your case.
Because you're trying to throw the tupled version from C# right back at it.
So if you refactor your C# implementation to:
protected static bool NumberEqualsWithToleranceImpl(IAttrProxy a, IAttrProxy b, float tolerance)
{
return default;
}
public static ParametricRule<float> NumberEqualsWithTolerance => NumberEqualsWithToleranceImpl;
you'll see that it works like you'd expect it to, both from F# and C#.
let attrRule = DefaultRules.Create("fd","fdsa", DefaultRules.NumberEqualsWithTolerance, 89.0f) //compiles, yay!
Sometimes the type resolution has trouble when passing a method as a function parameter, because there can be overloads on the method that make the signature ambiguous. You can just wrap the function in a lambda that passes the parameters.
let attrRule =
DefaultRules.Create(
"fd",
"fdsa",
(fun a b tolerance -> DefaultRules.NumberEqualsWithTolerance(a, b, tolerance)),
89.0)
I need clarity on how objects are declared and assigned a definition in F#.
What's happening in this code?
let service = {
new IService with
member this.Translate(_) = raise error }
My guess is we're creating an object that will implement some interface on the fly even though there is no actual class that's backing this object. Hence, we're removing the ceremony involved with creating an object by not having to declare a separate class to use it. In this case, we're minimizing the ceremony involved for implementing a mock object that could be used within a unit test.
Is my understanding accurate?
I tried to research my question and found the specification for F# 3.0 (Section - 6.3.8 Object Expressions)
6.3.8 Object Expressions An expression of the following form is an object expression: { new ty0 args-expropt object-members interface
ty1 object-members1 … interface tyn object-membersn } In the case
of the interface declarations, the object-members are optional and are
considered empty if absent. Each set of object-members has the form:
with member-defns endopt Lexical filtering inserts simulated $end
tokens when lightweight syntax is used. Each member of an object
expression members can use the keyword member, override, or default.
The keyword member can be used even when overriding a member or
implementing an interface.
For example:
let obj1 =
{ new System.Collections.Generic.IComparer<int> with
member x.Compare(a,b) = compare (a % 7) (b % 7) }
You can get a pretty good picture of what is happening behind the scenes if you look at the generated IL using a decompiler like ILSpy. For the example involving IComparer, it generates a hidden class, which implements the interface:
internal sealed class obj1#2 : IComparer<int> {
public obj1#2() : this() { }
int IComparer<int>.System-Collections-Generic-IComparer(int x, int y) {
int num = x % 7;
int num2 = y % 7;
if (num < num2) { return -1; }
return (num > num2) ? 1 : 0;
}
}
Inside the body of the method, it then creates a new instance:
IComparer<int> obj1 = new obj1#2();
The following code works:
typedef num MyFunc(num);
class ObjectThatIsLikeFunc {
call(x) => x;
}
var obj = new ObjectThatIsLikeFunc();
MyFunc g = obj; //works
If, however, ObjectThatIsLikeFunc doesn't have the call method, but defines noSuchMethod instead, it doesn't work.
typedef num MyFunc(num);
class ObjectThatIsLikeFunc {
noSuchMethod(InvocationMirror) => 100;
}
I'm getting "is not a subtype of type 'MyFunc'".
My Question:
Is there a way to tell the type checker that ObjectThatIsLikeFunc with noSuchMethod can act as MyFunc?
Short answer, not that I'm aware of. The generalized case is, "how can I have a class that implements noSuchMethod act like any type?" I think I heard some talk of how Dart might allow this, but I couldn't find a reference to it.
So I have this class in C#:
public class Foo : IFoo {
public bool TryConnect(out Status status) {
...
}
}
And I want to consume it with F#.
Unfortunately I had to use some hackery such as:
type FooService (foo : IFoo) =
member x.Execute() =
let mutable status = Unchecked.defaultof< ^Status>
foo.TryConnect(&status) |> ignore
(...do something with status...)
Is there a way to not use "mutable" here? In the end, I'm not actually using the first initialization value at all.
(I'm using F# 2.0, but if you have hints that only apply to F# 3.0, I'll be happy to hear them.)
Thanks
out params are automatically tuplized. So, you can do:
let res, status = foo.TryConnect()
For more info, see Passing by Reference on MSDN.