Looking at various bits of documentation, the way of defining an event in F# is to do something like
type xyz () =
let e = new Event<T>
member x.something_happened : IEvent<T> = x.Publish
Unfortunately, the type of IEvent is really Miscrosoft.FSharp.Control.IEvent<_>, and it is hence difficult to use from within C#. Some articles suggest adding the CLIEvent attribute to member something_happended above but it seems to make no difference as far as its usability from C# without including the F# library goes.
How do I correctly define an event in F# so I can then add a delegate to it in C# code? Many thanks.
There are two event types in F#, Event<'T> and Event<'Delegate, 'Args>. Only the second one is compiled to a .NET event when [<CLIEvent>] is present. Here's a working example:
type T() =
let e = Event<EventHandler<_>,_>()
[<CLIEvent>]
member x.MyEvent = e.Publish
member x.RaiseMyEvent() = e.Trigger(x, EventArgs.Empty)
In some cases the compiler generates a warning if [<CLIEvent>] is used with a non-standard event type. I'm not sure why it doesn't raise a warning for your code (perhaps a bug?).
Related
This question already has answers here:
Why does Visual Studio Type a Newly Minted Array as Nullable?
(3 answers)
Closed 6 months ago.
I'm new to C#10 and the default enabled nullable NRT functionality. In the following simple example I'm curious why VS2022 tells me (via tooltip) that o is object? when the interface definition explicitly states it is object.
Is this standard behavior and what's the reason for it? Is it because the compiler has no way of telling that the interface implementation is null-safe so has to assume the worst?
Further, s is also nullable (string?) but no warnings or errors are given when I use these nullable types. The compiler confidently informs me that "o is not null here" when I call o.ToString.
I can't tell at this stage if NRTs marks a paradigm shift to how we write modern C# or is "just another language tweak?" What's going on here? I want to 'embrace' it but am struggling with the full understanding of another change to the language.
public interface ITest
{
Object GetObject();
}
public class Tester
{
public void Test(ITest i)
{
var o = i.GetObject(); //object?
var s = o.ToString(); //string?
Console.WriteLine(s);
}
}
Although an interface implementation written in C# might not be able to return null, there is no requirement that interface implementations be written only in C#. If an interface is implemented by code written in another language, nothing would prevent that code from returning null.
A similar issue arises, incidentally, with the TryGetValue method of IDictionary<TKey,TValue>. If one has a structure with member m whose constructor invokes:
SomeIDictionary.TryGetValue(someKey, ref m);
the C# compiler will blindly assume that the interface method will not return without storing a value into m (e.g. because the key is not found). This may have the surprising effect of causing a statement like:
myStruct = new myStructType(someParameters);
to leave myStruct.m holding whatever value it held beforehand.
FWIW Rider says the type is object not object?
Also, Rider will refactor the var into object:
Note: the code will compile even if I manually say object?:
Keep in mind nullable reference types are magic sugar sprinkled on top of the type system. Under the hood there's no difference between object and object?; both refer to System.Object. That magical sugar layer is able to deduce that my object? is not null (because its value came from an interface that promises never to return null).
Being pedantic: there's no difference in the type system between a nullable reference type and the same non-nullable reference type. But there is a difference between nullable and non-nullable value types. To be more precise: double is the System.Double struct, but double? is the System.Nullable<System.Double> struct. MS crammed more magic into the language and compiler to support this bifurcation between reference and value types. This would be a great opportunity to start writing glowing things about the type systems in TypeScript or Rust or any of a dozen other languages.
This question already has answers here:
Implicit typing; why just local variables?
(6 answers)
Closed 8 years ago.
class A
{
A()
{
var x = 5; // this is allowed
}
var _x = 5; // the compiler is unhappy
}
I guess the compiler must be able to deduce the type for the member variable just the same way it does it for the local one. So what's the difference?
Eric Lippert answered your question right here: Why no var on fields?
Basically, for the general case it would require re-writing the C# compiler, as the way it currently does type inference would not work for cycles of var field variable assignments.
The var keyword was designed for anonymous types, which can only be used inside of a method.
Also, you're wrong; the compiler cannot always deduce a var field.
What happens if you compile the following:
class A {
public readonly var value = B.value;
}
class B {
public readonly var value = B.value;
}
This situation is impossible to recreate with local variables, since a variable cannot be referenced before it's defined.
The general problem here is that you're asking the compiler to consume type information while it's still generating that information.
Eric Lippert explains in greater depth.
I see two reasons:
It might be desirable to make the declaration of types in a public interface explicit
It's hard to implement. The C# compiler compiles in multiple phases.
At first it parses everything apart from method bodies so it knows about everything outside of function bodies. Then it can use that information to compile method bodies individually. What happens while compiling one method body hasn't much effect on what happens when compiling other method bodies.
If you could use var for fields the expression body of the field initializer would affect the type of the field and thus many other methods. So it doesn't fit the compiler design well.
This is a guess, but initialization of class-level fields must be done as part of the initialization (constructor) process for a Type, whereas initialization of a method-level variable happens when the method's stack frame is constructed. Perhaps the distinction is related to how these processes are compiled (how their implementation is created) inside the framework.
I have a class that contains a variable of indeterminate type, which must be overridden at runtime, how can I do this?
Sorry for the disgusting question(
Example:
public class MyClass
{
public e_Type TypeValue;
public (variable of indeterminate type) Value;
}
public enum e_Type
{
string, int, bool, byte
}
At runtime variable TypeValue should determine the type of variable Value
Depending on what you actually mean, you should use either var or dynamic.
The var keyword simply lets the compiler take care of deciding which type you are actually using. If the data you will be assigning is truly dynamic during runtime, it won't do you much good. You should mostly look at var as syntactic sugar (even if it at times can be very, very helpful sugar) - i.e. it just saves you typing.
The dynamic keyword lets you create an object that is truly dynamic, that is you will not get a compiler or runtime error no matter what you try to assign to it. The runtime errors will happen later down the road when you try to call on a property that doesn't exist on it. This is essentially you telling the compiler "Hey, look, just don't give me any fuss about this object, allow me to assign anything to it and call anything on it. If I mess up, it's my problem, not yours."
I think whenever you are thinking about using dynamic you should consider the problem at hand and see if it can be solved in a better way (interfaces, generics etc).
It sounds like you're really after generics:
class Foo<T>
{
public T Value { get; set; };
}
Then you can create instances for different types:
Foo<string> x = new Foo<string>();
x.Value = "fred";
Foo<int> y = new Foo<int>();
y.Value = 10;
This is still fixing the type at compile-time - but when the code using the type is compiled.
var is completely wrong here - var is just used for implicitly typed local variables. In particular, you can't apply it to fields.
It's possible that you want dynamic, but it's not really clear from your question at the moment.
I know that this must be done using the keyword var
Nope, that isn't what var does. There are 3 things that leap to mind that would work:
object; can store anything, but requires reflection to do anything useful
dynamic; a special-case of object, where the compiler performs voodoo such that obj.SomeMethod() (etc) is resolved at runtime
generics, i.e. have the class be SomeType<T>, with the variable typed as T; generic constraints can make this T more usable by declaring features (interfaces) that it must have
var has the purpose of referencing anything, not to declare anything. It's the other way around.
I acomplished this once leveraging the System.Dynamic.ExpandoObject (C# 4 only!), it allows for properties to be added at will without declaring them, and they will be resolved at runtime (it resembles how PHP treats objects and I'm a huge fan of it).
A quick example:
dynamic myObject = new ExpandoObject();
myObject.myProperty = "You can declare properties on-the-fly inside me !";
Console.WriteLine(myObject.myProperty);
Inspired by this question.
Short version: Why can't the compiler figure out the compile-time type of M(dynamic arg) if there is only one overload of M or all of the overloads of M have the same return type?
Per the spec, §7.6.5:
An invocation-expression is dynamically bound (§7.2.2) if at least one of the following holds:
The primary-expression has compile-time type dynamic.
At least one argument of the optional argument-list has compile-time type dynamic and the primary-expression does not have a delegate type.
It makes sense that for
class Foo {
public int M(string s) { return 0; }
public string M(int s) { return String.Empty; }
}
the compiler can't figure out the compile-time type of
dynamic d = // dynamic
var x = new Foo().M(d);
because it won't know until runtime which overload of M is invoked.
However, why can't the compiler figure out the compile-time type if M has only one overload or all of the overloads of M return the same type?
I'm looking to understand why the spec doesn't allow the compiler to type these expressions statically at compile time.
UPDATE: This question was the subject of my blog on the 22nd of October, 2012. Thanks for the great question!
Why can't the compiler figure out the compile-type type of M(dynamic_expression) if there is only one overload of M or all of the overloads of M have the same return type?
The compiler can figure out the compile-time type; the compile-time type is dynamic, and the compiler figures that out successfully.
I think the question you intended to ask is:
Why is the compile-time type of M(dynamic_expression) always dynamic, even in the rare and unlikely case that you're making a completely unnecessary dynamic call to a method M that will always be chosen regardless of the argument type?
When you phrase the question like that, it kinda answers itself. :-)
Reason one:
The cases you envision are rare; in order for the compiler to be able to make the kind of inference you describe, enough information must be known so that the compiler can do almost a full static type analysis of the expression. But if you are in that scenario then why are you using dynamic in the first place? You would do far better to simply say:
object d = whatever;
Foo foo = new Foo();
int x = (d is string) ? foo.M((string)d) : foo((int)d);
Obviously if there is only one overload of M then it is even easier: cast the object to the desired type. If it fails at runtime because the cast it bad, well, dynamic would have failed too!
There's simply no need for dynamic in the first place in these sorts of scenarios, so why would we do a lot of expensive and difficult type inference work in the compiler to enable a scenario we don't want you using dynamic for in the first place?
Reason two:
Suppose we did say that overload resolution has very special rules if the method group is statically known to contain one method. Great. Now we've just added a new kind of fragility to the language. Now adding a new overload changes the return type of a call to a completely different type -- a type which not only causes dynamic semantics, but also boxes value types. But wait, it gets worse!
// Foo corporation:
class B
{
}
// Bar corporation:
class D : B
{
public int M(int x) { return x; }
}
// Baz corporation:
dynamic dyn = whatever;
D d = new D();
var q = d.M(dyn);
Let's suppose that we implement your feature requiest and infer that q is int, by your logic. Now Foo corporation adds:
class B
{
public string M(string x) { return x; }
}
And suddenly when Baz corporation recompiles their code, suddenly the type of q quietly turns to dynamic, because we don't know at compile time that dyn is not a string. That is a bizarre and unexpected change in the static analysis! Why should a third party adding a new method to a base class cause the type of a local variable to change in an entirely different method in an entirely different class that is written at a different company, a company that does not even use B directly, but only via D?
This is a new form of the Brittle Base Class problem, and we seek to minimize Brittle Base Class problems in C#.
Or, what if instead Foo corp said:
class B
{
protected string M(string x) { return x; }
}
Now, by your logic,
var q = d.M(dyn);
gives q the type int when the code above is outside of a type that inherits from D, but
var q = this.M(dyn);
gives the type of q as dynamic when inside a type that inherits from D! As a developer I would find that quite surprising.
Reason Three:
There is too much cleverness in C# already. Our aim is not to build a logic engine that can work out all possible type restrictions on all possible values given a particular program. We prefer to have general, understandable, comprehensible rules that can be written down easily and implemented without bugs. The spec is already eight hundred pages long and writing a bug-free compiler is incredibly difficult. Let's not make it more difficult. Not to mention the expense of testing all those crazy cases.
Reason four:
Moreover: the language affords you many opportunities to avail yourself of the static type analyzer. If you are using dynamic, you are specifically asking for that analyzer to defer its action until runtime. It should not be a surprise that using the "stop doing static type analysis at compile time" feature causes static type analysis to not work very well at compile time.
An early design of the dynamic feature had support for something like this. The compiler would still do static overload resolution, and introduced a "phantom overload" that represents dynamic overload resolution only if necessary.
Blog post introducing phantom methods
Details on phantom methods
As you can see in the second post, this approach introduces a lot of complexity (the second article talks about how type inference would need to be modified to make the approach work out). I'm not surprised that the C# team decided to go with the simpler idea of always using dynamic overload resolution when dynamic is involved.
However, why can't the compiler figure out the compile-time type if M has only one overload or all of the overloads of M return the same type?
The compiler could potentially do this, but the language team decided not to have it work this way.
The entire purpose of dynamic is to have all expressions using dynamic execute with "their resolution is deferred until the program is run" (C# spec, 4.2.3). The compiler explicitly does not perform static binding (which would be required to get the behavior you want here) for dynamic expressions.
Having a fallback to static binding if there was only a single binding option would force the compiler to check this case - which was not added in. As for why the language team didn't want to do it, I suspect Eric Lippert's response here applies:
I am asked "why doesn't C# implement feature X?" all the time. The answer is always the same: because no one ever designed, specified, implemented, tested, documented and shipped that feature.
I think the case of being able to statically determine the only possible return type of a dynamic method resolution is so narrow that it would be more confusing and inconsistent if the C# compiler did it, rather than having across the board behavior.
Even with your example, what if Foo is part of a different dll, Foo could be a newer version at runtime from a binding redirect with additional M's that have a different return type, and then the compiler would have guessed wrong because the runtime resolution would return a different type.
What if Foo is an IDynamicMetaObjectProvider d might not match any of the static arguments and thus it would fall back on it's dynamic behavior which could possibly return a different type.
I have an interface, written in C#, defined as this :
public interface IWidget
{
object Evaluate();
event EventHandler Invalidated;
}
When I try to implement this interface in F#, I look at what F# thinks the IWidget interface is (by hovering my mouse over it), and I see
type IWidget =
interface
member Evaluate : unit -> obj
end
It appears to ignore the Invalidated event entirely... is this a known issue with F# and if so is there any way to work around it? When implementing my F# version of IWidget, can I just implement this event outside of the IWidget section or what? It seems really nasty that f# handles the "event" keyword so poorly...
UPDATE:
After further fiddling around, studio was then saying things like:
'no implementation was given for IWidget.remove_Invalidate(value:EventHandler):unit'
then, when I added those methods so the whole thing looked like:
interface IWidget with
member w.Evaluate() = new obj()
member w.add_Invalidated(value:EventHandler) = ()
member w.remove_Invalidated(value:EventHandler) = ()
end
it compiled fine, even though the tooltip was still saying the only member of IWidget was Evaluate()... it seems like the way F# (or at least the IDE) handles this stuff is really screwy...
ANOTHER UPDATE:
According to the tooltip in the IDE, the [] tag allows an event to be compiled as a CLI metadata event, by transforming it to a pair of add_/remove_ methods... just FYI for anyone who was as confused by this as I was. In short, either implementing those two methods or using that tag work fine, though the fact that the tooltip view of the IWdiget interface lacks any mention of the Invalidate event, and the necessity of implementing such an event is only noticed when the compiler throws an error, is still a clear bug and is pretty confusing. For anyone curious, the following code works fine:
let invalidated = new DelegateEvent<System.EventHandler>()
interface IWidget with
member w.Evaluate() = new obj()
[<CLIEvent>]
member w.Invalidated = invalidated.Publish
end
Thanks for all the help everyone!
F# does support events.
For example:
let invalidated = new DelegateEvent<System.EventHandler>()
[<CLIEvent>]
member this.Invalidated = invalidated.Publish