Creating F# discrimated union type in C# - c#-to-f#

I'm trying to add F# project to my C# solution. I created a F# project and wrote some F# code, now I'm trying to use it from my C# projects.
I successfully referenced F# project and can access it's types, but having issues with discriminated unions. For example I have following types defined in F#:
namespace Sample
type NotificationReceiverUser = NotificationReceiverUser of string
type NotificationReceiverGroup = NotificationReceiverGroup of string
type NotificationReceiver = NotificationReceiverUser | NotificatonReceiverGroup
I can create NotificationReceiverUser object directly as follows:
var receiver = NotificationReceiverUser.NewNotificationReceiverUser("abc");
,but I need NotificationReceiver object, and I'm not getting NotificationReceiver.NewNotificationReceiverUser or NotificationReceiver.NewNotificationReceiverGroup static methods. Looking at some other SO questions it looks like these methods should be available by default. Would appreciate any pointers on why they are missing for me.

What you're trying to do is not a "discriminated union". It's an indiscrimnated union. First you created two types, and then you're trying to say: "values of this third type may be either this or that". Some languages have indiscriminated unions (e.g. TypeScript), but F# does not.
In F#, you can't just say "either this or that, go figure it out". You need to give each case of the union a "tag". Something by which to recognize it. That's why it's called a "discriminated" union - because you can discriminate between the cases.
For example:
type T = A of string | B of int
Values of type T may be either string or int, and the way to know which one is to look at the "tags" assigned to them - A or B respectively.
The following, on the other hand, is illegal in F#:
type T = string | int
Coming back to your code, in order to "fix" it the mechanical way, all you need to do is add case discriminators:
type NotificationReceiverUser = NotificationReceiverUser of string
type NotificationReceiverGroup = NotificationReceiverGroup of string
type NotificationReceiver = A of NotificationReceiverUser | B of NotificatonReceiverGroup
But my intuition tells me that what you actually meant to do was this:
type NotificationReceiver =
| NotificationReceiverUser of string
| NotificatonReceiverGroup of string
Two cases of the same type (weird, but legal), still distinguished by tags.
With such definition, you would access it from C# thusly:
var receiver = NotificationReceiver.NewNotificationReceiverUser("abc");

Related

Elm Language What do the Multiple Types in a row (without the arrow) in a signature mean?

In the Elm language, I'm having a hard time explaining my question...
In these snippets in elm:
I understand the signature in something like
update : Msg -> Model -> Model
where the parameters / output is separated by arrows, but how do I read / grok things like:
Sub Msg
Program Never Model Msg
In:
main : Program Never Model Msg
main =
program
{ init = init
, view = view
, update = update
, subscriptions = subscriptions
}
subscriptions : Model -> Sub Msg
subscriptions model =
Sub.none
In a type signature, parameter types are separated by ->, with the last type being the return value.
If there are no -> symbols, then it means it is a value of that type. In your main example, the type of main is Program Never Model Msg. It has no arrows, so it takes no parameters.
Now, each parameter and the return value in the type annotation may have several things separated by spaces, as in your main example. The leftmost is the type, followed by type parameters separated by spaces.
Program Never Model Msg
| | | |
| ------|-----
type type parameters
A type parameter is similar to Generics in a language like C#. The equivalent syntax in C# would be:
void Program<Never, Model, Msg>()
C# doesn't directly correlate because it has a different way of constraining generic type parameters, but the general idea holds.
The Elm guide doesn't currently have a great deal of info, but here is the section talking about types.
Sub Msg, List Int, Program Never Model Msg
Sub, List and Program are type constructors. You can think about them as functions that take a type and return another type.
By themselves, Sub, List and Program are not complete type. They are like a puzzle missing a piece. When one adds the missing piece, the puzzle is complete.
I usually read them in my head using the word of as in a List of Ints, a Program of Never, Model and Msg.

Get a name of a method parameter using Javassist

I have a CtMethod instance, but I don't know how to get names of parameters (not types) from it. I tried getParameterTypes, but it seems it returns only types.
I'm assuming it's possible, because libraries I'm using don't have sources, just class files and I can see names of method parameters in IDE.
It is indeed possible to retrieve arguments' names, but only if the code has been compiled with debug symbols otherwise you won't be able to do it.
To retrieve this information you have to access the method's local variable table. For further information about this data structure I suggest you to check section 4.7.13. The LocalVariableTable Attribute of the jvm spec. As I usually say, JVM spec may look bulky but it's an invaluable friend when you're working at this level!
Accessing the local variable table attribute of your ctmethod
CtMethod method = .....;
MethodInfo methodInfo = method.getMethodInfo();
LocalVariableAttribute table = methodInfo.getCodeAttribute().getAttribute(javassist.bytecode.LocalVariableAttribute.tag);
You now have the the local variable attribute selected in table variable.
Detecting the number of localVariables
int numberOfLocalVariables = table.tableLenght();
Now keep in mind two things regarding the number in numberOfLocalVariables:
1st: local variables defined inside your method's body will also be accounted in tableLength();
2nd: if you're in a non static method so will be this variable.
The order of your local variable table will be something like:
|this (if non static) | arg1 | arg2 | ... | argN | var1 | ... | varN|
Retriving the argument name
Now if you want to retrieve, for example, the arg2's name from the previous example, it's the 3rd position in the array. Hence you do the following:
// remember it's an array so it starts in 0, meaning if you want position 3 => use index 2
int frameWithNameAtConstantPool = table.nameIndex(2);
String variableName = methodInfo.getConstPool().getUtf8Info(frameAtConstantPool)
You now have your variable's name in variableName.
Side Note: I've taken you through the scenic route so you could learn a bit more about Java (and javassists) internals. But there are already tools that do this kind of operations for you, I can remember at least one by name called paranamer. You might want to give a look at that too.
Hope it helped!
If you don't actually want the names of the parameters, but just want to be able to access them, you can use "$1, $2, ..." as seen in this tutorial.
It works with Javaassist 3.18.2 (and later, at least up to 3.19 anyway) if you cast, like so:
LocalVariableAttribute nameTable = (LocalVariableAttribute)methodInfo.getCodeAttribute().getAttribute(LocalVariableAttribute.tag);

OCaml This function is applied to too many arguments

This is just a simple program I wrote to try to get a better understanding about modules. I'm trying to call the toS function with Id("a",Int) but it seems like I can write a type ast like this. What may be the problem?
module Typ =
struct
type typ = Int | Bool
end
module Symbol =
struct
type t = string
end
module Ast =
struct
type ast = Const of int * Typ.typ | Id of Symbol.t * Typ.typ
let rec toS ast = match ast with Id(a,b) -> "a"
|_->"b"
end
Ast.toS Id("a",Int)
You are getting an error because you did not surround your type constructor with parens in the function application. However, you must also reference type constructors by fully qualified names outside the module they're defined in. I.e.
Ast.toS (Ast.Id("a",Typ.Int))
Alternatively, you can open the modules. But this is considered bad practice. I.e.
open Id
open Typ
Ast.toS (Id("a",Int))

Value of type <anonymous type> cannot be converted to <anonymous type>

I am sure i am doing something terribly wrong, but i should better ask the experts.
At the third line i get the error Value of type <anonymous type> cannot be converted to <anonymous type>
Dim Query = (From c In Db.web Select New With {.AA = c.AA}).ToList
Dim v = New With {.Amount = 108}
Query.Add(v)
What am i missing here?
Because you have named your fields differently (and maybe it has different type as well, I don't know, cause I don't know what type c.AA is), compiler has created different type for v, so you have 2 anonymous classes, with different fields (even if they have same type, but their name differs) and they are not compatible with each other.
I don't know VB.Net well, but something like this:
Dim Query = (From c In Db.web Select New With {.Amount = CInt(c.AA)}).ToList
Dim v = New With {.Amount = 108}
Query.Add(v)
Should solve the problem, at least works in C#.
Anonymous type identity is based not just on the types of the members, but on their names as well. So these two objects are of different types, even though to human eyes they have the 'same' structure:
Dim a = New With { .Name = "Bob" }
Dim b = New With { .Moniker = "Robert" }
So even if c.AA is an Integer, that's not enough for Query and v to be type-compatible.
Obviously your code is distilled from your real problem, so I can't say exactly what you should be doing instead, but perhaps using a named rather than an anonymous type will solve your problem.
This is documented in the VB.NET Spec (from eg version 9.0 here), section 11.10.4 "Anonymous Object-Creation Expressions" (my emphases) :
If two anonymous class creation expressions occur within the same
method and yield the same resulting shape—if the property order,
property names, and property types all match—they will both refer to
the same anonymous class.
Annotation
It is possible that a compiler may choose to unify anonymous types further, such as at the assembly level, but this cannot be relied upon at this time.
By contrast to the annotation, I believe that for C#, the compiler does guarantee anonymous type identity across an assembly when everything matches.

GetType on generic types

I'm trying register presenters with Windsor using the convention based method but trying to do this in VB.NET, but the problem is it does not want to compile this statement:
Dim type = GetType(AbstractPresenter(Of))
I am getting : Too few type arguments to AbstractPresenter(Of TView, TPresenter)
Which I don't understand because this is a valid statement according to question. Also showing valid in other C# to VB.NET converters when converting typeof(AbstractPresenter<>).
Any ideas?
There are two type arguments, and you need to specify this, just as you would do for multi-dimensional arrays:
Dim type = GetType(AbstractPresenter(Of ,))
Looks weird, but now the compiler knows that AbstractPresenter expects two type arguments.
By the way, C# has the same requirement. So the above would be written as:
var type = typeof(AbstractPresenter<,>);