Reputation: 640
So when ever im creating some properties in my F# code , as F# doesn't support auto properties , as far as i know. I have to create backing fields and initialize them to null, which doesn't seems right in functional programming terms. For e.g.
let mutable albums : DbSet = null
let mutable genres : DbSet = null
member x.Albums
with get() = albums
and set(value) = albums <- value
member x.Genres
with get() = genres
and set (value) = genres <- value
Is there a better way of doing this ?. Many thanks for your suggestions.
Upvotes: 6
Views: 1220
Reputation: 41290
Unless you're doing something complex, I would recommend to use records instead of classes. Basically, they are classes with extra features: immutability, structural equality, pattern matching, etc:
type Playlists = {
Albums: DbSet;
Genres: DbSet
}
You can get record's fields easily:
let p = {Albums = ...; Genres = ...}
let albums = p.Albums
let genres = p.Genres
In default records fields are immutable; you can declare mutable fields in records, but it is considered as a bad practice. Though you cannot set properties, you can create a new record from an old one. Default immutability is normally not a problem, furthermore it makes the code more functional and easier to reason about:
let p = {Albums = a; Genres = g}
// Create new records by updating one field
let p1 = {p with Albums = a1}
let p2 = {p with Genres = g2}
If you insist to create classes, using a constructor with explicit parameters is recommended:
type Playlists(a: DbSet, g: DbSet) =
let mutable albums = a
let mutable genres = g
// ...
When a default constructor is necessary, you can use Unchecked.default<'T>
for non nullable fields, or better use their default constructors:
// Set fields using dump values
let mutable albums = new DbSet()
let mutable genres = new DbSet()
But make sure that you set those fields before actually using them.
Upvotes: 5
Reputation: 47904
FYI - auto-properties are planned for F# 3.0. See the preview documentation [MSDN]. Looks like your example would become:
type Music() =
member val Albums : DbSet = null with get, set
member val Genres : DbSet = null with get, set
Upvotes: 5
Reputation: 243051
F# does not support auto properties when you need a mutable property, but it supports a lightweight syntax when you need just a readonly property. If you're writing some functional code, then using readonly properties might actually be more appropriate:
type Music(genres : DbSet, albums : DbSet) =
member x.Albums = albums
member x.Genres = genres
This is essentially the same as records suggested by pad, but it may be more appropriate if you want to have better control over how the types look (and how they appear in C#, or for data-binding).
If DbSet
is a mutable type, then you probably can just use the above type and initialize it just once (you'll still be able to modify the DbSet
values). If you want to change the DbSet
value, you can add a method that returns a cloned object:
member x.WithAlbums(newAlbums) =
Music(genres, newAlbums)
Using null
or Unchecked.defaultOf<_>
in F# is considered a very bad practice and you should always try to create fully initlized object. If the value may be missing, you can use option
type to represent that, but then you have to always write handler for missing value, to make your program safe.
Upvotes: 11