F# class reordering Visual Studio - f#

Im building a sample application where my types hierarchy isnt working with types ordering in Visual Studio. No matter what way i try to arrange the files ( up , down ) I cannot get all the classes be defined.
So in the order they are in f# project
type Artist() =
let mutable artistId = 0
let mutable name = String.Empty
member x.ArtistId
with get() = artistId
and set (value) = artistId <- value
member x.Name
with get() = name
and set ( value ) = name <- value
type Genre() =
let mutable name = String.Empty
let mutable genreId = 0
let mutable description = String.Empty
let mutable albums = [new Album()]
member x.Name
with get() = name
and set (value) = name <- value
member x.GenreId
with get() = genreId
and set ( value ) = genreId <- value
member x.Description
with get() = description
and set ( value ) = description <- value
member x.Albums
with get() = albums
and set ( value ) = albums <- value
and Album() =
let mutable title = String.Empty
let mutable genre = new Genre()
let mutable albumId = 0
let mutable genreId = 0
let mutable artistId = 0
let mutable price : decimal = Decimal.Zero
let mutable albumArtUrl = String.Empty
let mutable artist = new Artist()
member x.Title
with get() = title
and set (value) = title <- value
member x.Genre
with get() = genre
and set (value) = genre <- value
member x.AlbumId
with get() = albumId
and set ( value ) = albumId <- value
member x.GenreId
with get() = genreId
and set ( value ) = genreId <- value
member x.ArtistId
with get() = artistId
and set ( value ) = artistId <- value
member x.Price
with get() = price
and set ( value ) = price <- value
member x.AlbumArtUrl
with get() = albumArtUrl
and set ( value ) = albumArtUrl <- value
member x.Artist
with get() = artist
and set ( value ) = artist <- value
So in above case i get the error "Album" is not defined.
Is there a way to solve this ?. Or i just have to rethink the whole of the hierarchy structure for my types?

If you need to define two types that are mutually recursive (meaning that they can both refer to each other), then you need to place them in a single file and use type ... and ... syntax.
In your example, this means that Genre and Album need to be defined like this:
// Start a definition block using 'type' as normal
type Genre() =
let mutable name = String.Empty
let mutable albums = [new Album()]
member x.Name
with get() = name
and set (value) = name <- value
member x.Albums
with get() = albums
and set ( value ) = albums <- value
// Continue single type definition block using 'and'
and Album() =
let mutable genre = new Genre()
let mutable albumId = 0
let mutable artist = new Artist()
member x.Genre
with get() = genre
and set (value) = genre <- value
member x.AlbumId
with get() = albumId
and set ( value ) = albumId <- value
member x.Artist
with get() = artist
and set ( value ) = artist <- value
However, your example is using F# in a very C#-style, so the code does not really look very elegant and it may not give you many of the benefits of functional programming.
If I wanted to represent a structure that you're using, then I probably wouldn't add reference to the genre into the Album type. When you place a list of albums inside a Genre, you will always be able to recover the genre when you process the data structure (i.e. to turn it into some other structure, maybe an F# record, that can be passed to data-binding). The beneift of F# is that it lets you write the domain on a few lines, but that works only for functional types.
Using discriminated unions with a single case, you can write:
// Type aliases to make code more readable
type Name = string
type AlbumID = int
// Simple type definitions to represent the domain
type Artist = Artist of Name
type Album = Album of AlbumID * Artist
type Genre = Genre of Name * Album list

Related

JSON serialization for option types

I'm running across an issue when I define a field of option type while serializing for JSON.
Before works (without option)
[<DataContract>]
type Article = {
[<field: DataMemberAttribute(Name="version") >]
version: string
}
After throws error (with option)
[<DataContract>]
type Article = {
[<field: DataMemberAttribute(Name="version") >]
version: string option
}
method threw exception:
System.Runtime.Serialization.SerializationException: Expecting state 'Element'.. Encountered 'Text' with name '', namespace ''.
Related Code
let response = request.GetResponse() :?> HttpWebResponse
use reader = new StreamReader(response.GetResponseStream())
use memoryStream = new MemoryStream(ASCIIEncoding.Default.GetBytes(reader.ReadToEnd()))
let result = (new DataContractJsonSerializer(typeof<Article>)).ReadObject(memoryStream) :?> Article
Here is a definition with a nullable int. String can already be null to which the zillions of Null reference exceptions attest...
open System
[<DataContract>]
type Person2 = {
[<DataMember(Name="Name") >]
entityName: Nullable<int>
[<DataMember(Name="Type") >]
entityType: String
}
However if you plan to fill this with a bunch of nulls maybe you should consider a class. This is really horrible but here's how it looks:
let p1 = { entityName = Nullable(10); entityType = "John"}
let p2 = { entityName = System.Nullable(); entityType = null}
val p1 : Person2 = {entityName = 10;
entityType = "John";}
val p2 : Person2 = {entityName = null;
entityType = null;}

Property does not show value

I define a property in a class like:
type Customer() =
let mutable _lastName = String.Empty
member val LastName = _lastName with get
And in the method QueryData I assign a value to _lastName:
member self.QueryData () =
// CODE
let addressData = bp.GetStructure("PE_PERSONALDATA")
_lastName <- addressData.GetString("LASTNAME")
null
| RfcCommunication ex ->
let basedComm = ex :> Exception
basedComm
| RfcLogon ex ->
let basedLogon = ex :> Exception
basedLogon
| RfcAbapRuntime ex ->
let basedAbap = ex :> Exception
basedAbap
In the main function I created an instance of Customer() and read the LastName property:
[<EntryPoint>]
let main argv =
let customer = CustomerBapi.Customer()
let ex = customer.QueryData()
if ex <> null then printfn "%s" ex.Message
printfn "%s" customer.LastName
The result is empty string. I tried to debug the program and see that _lastName is not empty
Why is the LastName property is empty?
Your property should look like this:
member this.LastName with get () = _lastName
The type of property you are using is passing _lastName as the value to initialise it with.
Explanation from MSDN:
Private values that hold the data for properties are called backing
stores. To have the compiler create the backing store automatically,
use the keywords member val, omit the self-identifier, then provide an
expression to initialize the property. If the property is to be
mutable, include with get, set. For example, the following class type
includes two automatically implemented properties. Property1 is
read-only and is initialized to the argument provided to the primary
constructor, and Property2 is a settable property initialized to an
empty string:
type MyClass(property1 : int) =
member val Property1 = property1
member val Property2 = "" with get, set

F# understanding discriminated union

I've kind of asked this question earlier so sorry for asking a bit similar question again. But unfortunately im not able to really understand how to design a discriminated unions.
so i have bunch of data structures which look like
type Artist( artistId : int, name : String ) =
do
if name = null then nullArg String.Empty
new(artistId: int) = Artist(artistId)
member x.ArtistId = artistId
member x.Name = name
and Genre() =
let mutable name = String.Empty
let mutable genreId : int = 0
let mutable description = String.Empty
let mutable albums = List.empty
member x.Description
with get() = description and set( value ) = description <- value
member x.Albums
with get() = albums and set ( value ) = albums <- value
and Album() =
let mutable title = String.Empty
let mutable albumId = 0
let mutable genreId = 0
let mutable artistId = 0
let mutable price : decimal = Decimal.Zero
let mutable albumArtUrl = String.Empty
let mutable genre = new Genre()
let mutable artist = new Artist(artistId)
member x.Title
with get() = title and set (value) = title <- value
member x.Genre
with get() = genre and set (value) = genre <- value
member x.AlbumId
with get() = albumId and set ( value ) = albumId <- value
member x.GenreId
with get() = genreId and set ( value ) = genreId <- value
member x.ArtistId
with get() = artistId and set ( value ) = artistId <- value
member x.Price
with get() = price and set ( value ) = price <- value
member x.AlbumArtUrl
with get() = albumArtUrl and set ( value ) = albumArtUrl <- value
member x.Artist
with get() = artist and set ( value ) = artist <- value
enter code here
I tried defining the above as a Discriminated union based on suggestions by some of F# guru's
which i defined like below
type Name = string
type AlbumId = int
type Artist =
| ArtistId of int
| Artist of Name
type Album =
| Title of string
| Price of decimal
| Album of AlbumId * Artist
| AlbumArtUrl of string
type Genre =
| GenreId of int
| Genre of Name * Album list
enter code here
But now i unable to figure out how would i populate my discriminated union similarly i was doing with my simple F# types which are just properties ?.
Can someone help me to explain this ?. I have been reading on discriminated unions but wont say i fully understand them .
Discriminated unions are used to represent types with multiple different cases, which roughly corresponds to class hierarchies in object oriented langauges. For example, a base class Shape with two inherited classes for Circle and Rectangle might be defined like this:
type Shape =
| Rectangle of (float * float) * (float * float) // Carries locations of two corners
| Circle of (float * float) * float // Carries center and diameter
The way you defined your discriminated unions does not really do what you probably intended. Your types Album, Artist and Genre represent just a single concrete type.
You can represent these with either records (which are just like lightweight classes with just properties) or using discriminated unions with a single case, which corresponds to a single class, but has a pretty lightweight syntax, which is the main benefit. For example:
type Name = string
type Price = decimal
type AlbumId = int
type ArtistId = int
type Artist = Artist of ArtistId * Name
type Album = Album of AlbumId * Name * Price * Artist
To construct an artist together with a few albums, you can write:
let pinkFloyd = Artist(1, "Pink Floyd")
let darkSide = Album(1, "The Dark Side of the Moon", 12.0M, pinkFloyd)
let finalCut = Album(2, "The Final Cut", 11.0M, pinkFloyd)
If you then create a genre, that will contain a list of albums and possibly a list of artists, so you could write something like this:
type Genre = Genre of Name * Artist list * Album list
let rock = Genre("Rock", [pinkFloyd], [darkSide; finalCut])
The question now is, how do you actually want to populate the types. What is your data-source? If you're loading data from a database or from a XML file, you're probably want to write a function that takes some part of the data source and returns Artist or Album and after you load all albums and artists, wrap them inside a Genre and return that as a final result.
PS: It is a bit difficult to answer your questions, because you're not really giving a bigger picture of what you're trying to do. If you can give a small, but concrete example (including the loading of data and their use), then someone can help you to look at the problem from a more functional perspective.

F# alternate constructor assigning values to (mutable) let bindings

Suppose I have this class:
type Pet (name:string) as this =
let mutable age = 5
let mutable animal = "dog"
I want to be able to create a new Pet based on some serialized data, which I represent with this record:
type PetData = {
name : string
age : int
animal : string
}
(TLDR: I can't figure out the syntax to make a constructor that'll take a PetData to populate the let bindings. My various attempts follow.)
So I make a new Pet constructor that'll assign values to the let bindings. I try using the class initializer syntax:
new (data:PetData) =
Pet(name,
age = data.age,
animal = data.animal
)
Hmm, nope: No accessible member or object constructor named 'Pet' takes 1 arguments. The named argument 'age' doesn't correspond to any argument or settable return property for any overload.
I check to make sure I've got all the syntax: no missing commas, correct "assignment" (cough) operator, correct indentation.
Okay the, I'll try the record initializer syntax.
new (data:PetData) =
{
name = data.name;
age = data.age;
animal = data.name
}
Error: The type 'Pet' does not contain a field 'name'
Okay, so I need to call the main constructor. I guess there are probably two places I can put it, so let's try both:
new (data:PetData) =
{
Pet(data.name);
age = data.age;
animal = data.name
}
Nope: Invalid object, sequence or record expression
new (data:PetData) =
Pet(data.name)
{
age = data.age;
animal = data.name
}
And nope: This is not a valid object construction expression. Explicit object constructors must either call an alternate constructor or initialize all fields of the object and specify a call to a super class constructor.
I didn't want to have to do this, but maybe since the fields are mutable anyway, I can just assign values to the object after initializing it:
new (data:PetData) =
let p = Pet(data.name)
p.age <- data.age
p.animal <- data.animal
p
Type constraint mismatch. The type Pet is not compatible with type PetData The type 'Pet' is not compatible with the type 'PetData'
Lol, what??
Okay, let's try this:
let assign(data:PetData) =
this.age <- data.age
this.animal <- data.animal
new (data:PetData) =
let p = Pet(data.name)
p.assign(data)
p
The field, constructor or member 'assign' is not defined
Right, so it can't access let bindings from outside.
Let's try a member then:
new (data:PetData) =
let p = Pet(data.name)
p.Assign(data)
p
member x.Assign(data:PetData) =
this.age <- data.age
this.animal <- data.animal
This is not a valid object construction expression. Explicit object constructors must either call an alternate constructor or initialize all fields of the object and specify a call to a super class constructor.
Okay... let's try this whole thing differently then, using explicit fields:
type Pet =
[<DefaultValue>]val mutable private age : int
[<DefaultValue>]val mutable private animal : string
val private name : string
new(name:string) =
{ name = name }
new(data:PetData) =
{
name = data.name;
age = data.age;
animal = data.animal
}
Extraneous fields have been given values
And that's when I punch my elderly cat in the face.
Any other ideas? These error messages are throwing me off. I can't even find half of them on Google.
You could do this.
type Pet =
val mutable private age : int
val mutable private animal : string
val private name : string
new (name:string) =
{
name = name;
age = 5; // or age = Unchecked.defaultof<_>;
animal = "dog"; // or animal = Unchecked.defaultof<_>;
}
new (data:PetData) =
{
name = data.name;
age = data.age;
animal = data.animal;
}
F# has its own style which looks like this.
type Pet(name:string, age:int, animal:string) =
let mutable age = age
let mutable animal = animal
new (name:string) =
Pet(name, 5, "dog")
new (data:PetData) =
Pet(data.name, data.age, data.animal)
Edit
Added an event used in do per comment request.
type Pet(name:string, age:int, animal:string, start:IEvent<string>) =
let mutable age = age
let mutable animal = animal
// all three constructors will call this code.
do start.Add (fun _ -> printf "Pet was started")
new (name:string, start:IEvent<_>) =
// an example of different logic per constructor
// this is called before the `do` code.
let e = start |> Event.map (fun x -> x + " from 'name constructor'")
Pet(name, 5, "dog", e)
new (data:PetData, start:IEvent<_>) =
Pet(data.name, data.age, data.animal, start)
Let bindings in a type are private and there's not much you could do about that. As such you cannot use Named Arguments. By creating properties you can do it like so, but not from inside the Pet type:
type Pet (name:string) =
let mutable age = 5
let mutable animal = "dog"
member x.Age with get () = age and set v = age <- v
member x.Animal with get () = animal and set v = animal <- v
type PetData = {
name : string
age : int
animal : string
}
with
member x.ToPet =
new Pet (x.name, Age = x.age, Animal = x.animal)
The other option would be to create a more general constructor like Gradbot suggested, either accepting a PetData object directly or all three parameters.

Overloading constructor without initialization

I'm writing a generic class that has two constructors: the first one initializes every field, the second (parameter-less) should not initialize anything.
The only way I found to achieve this is calling the main constructor with "empty" arguments, i.e. Guid.Empty and null. Besides not looking good functional style to my untrained eyes, this means that I have to put a a' : null constraint on the second parameter, which I don't want:
type Container<'a when 'a : null>(id : Guid, content : 'a) =
let mutable _id = id
let mutable _content = content
new() = Container<'a>(Guid.Empty, null)
member this.Id
with get() = _id
and set(value) = _id <- value
member this.Content
with get() = _content
and set(value) = _content <- value
I see two ways to solve this:
use something like the default c# keyword instead of null (does such a thing exist in F#?)
use a different syntax to specify constructors and private fields (how?)
What is the best way to implement this class?
The F# analog to default is Unchecked.default<_>. It is also possible to use explicit fields which you don't initialize:
type Container<'a>() =
[<DefaultValue>]
val mutable _id : Guid
[<DefaultValue>]
val mutable _content : 'a
new (id, content) as this =
new Container<'a>() then
this._id <- id
this._content <- content
However, in general, your overall approach is somewhat unidiomatic for F#. Typically you'd use a simple record type (perhaps with a static method to create uninitialized containers, although this seems to have questionable benefit):
type 'a Container = { mutable id : Guid; mutable content : 'a } with
static member CreateEmpty() = { id = Guid.Empty; content = Unchecked.defaultof<_> }
In many situations, you could even use an immutable record type, and then use record update statements to generate new records with updated values:
type 'a Container = { id : Guid; content : 'a }
[<GeneralizableValue>]
let emptyContainer<'a> : 'a Container =
{ id = Guid.Empty;
content = Unchecked.defaultof<_> }
let someOtherContainer = { emptyContainer with content = 12 }
If the type will be used from languages other than F#, the following provides a natural interface in F#, and C#, for example.
type Container<'a>(?id : Guid, ?content : 'a) =
let orDefault value = defaultArg value Unchecked.defaultof<_>
let mutable _id = id |> orDefault
let mutable _content = content |> orDefault
new() = Container(?id = None, ?content = None)
new(id : Guid, content : 'a) = Container<_>(?id = Some id, ?content = Some content)
member this.Id
with get() = _id
and set(value) = _id <- value
member this.Content
with get() = _content
and set(value) = _content <- value
If it will only be used from F#, you can omit the following constructor overloads
new(id : Guid, content : 'a) = Container<_>(?id = Some id, ?content = Some content)
new() = Container()
because the overload accepting optional args handles both these cases equally well in F#.

Resources