-
Notifications
You must be signed in to change notification settings - Fork 2
Step 2 Tres
As we make the leap to F#, we're changing things around significantly. Remember our discussion about the flat structure of an F# project? Instead of an Entities
directory with a lot of little files, we'll define a single Entities.fs
file in the root of the project. Don't forget to add it to the list of compiled files in project.json
; it should go above HomeModule.fs
.
We are also going to change from class types to record types. Record types can be thought of as struct
s, though the comparison is not exact; record types are reference types, not value types, but they cannot be set to null in code (huge caveat which we'll see in the next step) unless explicitly identified. We're also going to embrace F#'s immutability-by-default qualities that will save us a heap of null checks (as well as those pesky situations where we forget to implement them).
As a representative example, consider the Page
type. In C#, it looks like this:
namespace Uno.Entities
{
using Newtonsoft.Json;
using System.Collections.Generic;
public class Page
{
[JsonProperty("id")]
public string Id { get; set; }
public string WebLogId { get; set; }
public string AuthorId { get; set; }
public string Title { get; set; }
public string Permalink { get; set; }
public long PublishedOn { get; set; }
public long UpdatedOn { get; set; }
public bool ShowInPageList { get; set; }
public string Text { get; set; }
public ICollection<Revision> Revisions { get; set; } = new List<Revision>();
}
}
It contains strings, for the most part, and a Revisions
collection. Now, here's how we'll implement this same thing in F#:
namespace Tres.Entities
open Newtonsoft.Json
...
type Page = {
[<JsonProperty("id")>]
Id : string
WebLogId : string
AuthorId : string
Title : string
Permalink : string
PublishedOn : int64
UpdatedOn : int64
ShowInPageList : bool
Text : string
Revisions : Revision list
}
with
static member Empty =
{ Id = ""
WebLogId = ""
AuthorId = ""
Title = ""
Permalink = ""
PublishedOn = 0L
UpdatedOn = 0L
ShowInPageList = false
Text = ""
Revisions = []
}
The field declarations immediately under the type
declaration mirror those in our C# version; since they are fields, though, we don't have to define getters and setters.
F# requires record types to always have all fields defined. F# also provides a with
statement (separate from the one in the code above) that allows us to create a new instance of a record type that has all the fields of our original ones, only replacing the ones we specify. So, in C#, while we can do something like
var pg = new Page { Title = "Untitled" };
, leaving all the other fields in their otherwise-initialized state, F# will not allow us to do that. This is where the Empty
static property comes in; we can use this to create new pages, while ensuring that we have sensible defaults for all the other fields. The equivalent to the above C# statement in F# would be
let pg = { Page.Empty with Title = "Untitled" }
. Note the default values for Permalink
: in C#, it's null, but in F#, it's an empty string. Now, certainly, you can use String.IsNullOrEmpty()
to check for both of those, but we'll see some advantages to this lack of nullability as we continue to develop this project.
Before continuing on to Quatro, you should familiarize yourself with the types in this step.