Setting a property of a class when the containing class is constructed - f#

A class Test which upon construction creates an instance of another class and sets a property would look something like this (I suppose):
type Test() as this =
let a = new A()
do this.Init()
member this.Init() =
let a.Size = 10
However, I get a Block following this 'let' is unfinished. Expect an expression.
What is the correct and preferred way of doing this?

If you want to mutate the Size property, you'll have to use the assignment operator:
type Test() as this =
let a = new A()
do this.Init()
member this.Init() =
a.Size <- 10
However, you can write it much more succinctly like this:
type Test() =
let a = A (Size = 10)

Related

F# - Class member does not keep state

I wrote a wrapper around List. I expect the internal list to keep state but it doesn't. What am I doing wrong? The methods are definitely executed but the internal list is always empty.
open System
open System.Collections.Generic
open NUnit.Framework
type MyList() =
member this.List = List<char>()
member this.AddX =
printfn "AddX called"
this.List.Add('X')
member this.CountX: int =
printfn "CountX called"
this.List.Count
[<Test>]
let TestX () =
let mylist = MyList()
mylist.AddX
mylist.AddX
Assert.AreEqual(2, mylist.CountX)
Tried putting a mutable keyword in different places (no success)
The problem is that every time you call the List member of MyList, it creates a new list, so the class isn't keeping internal state the way you want. (You can verify this by adding a printfn statement to the List method.)
To fix this problem, change the List member to be a value, which is initialized only once per class instance:
type MyList() =
member val List = List<char>()
...
Alternatively, you can use a let-bound value instead:
type MyList() =
let list = List<char>()
member this.AddX = list.Add('X')
member this.CountX = list.Count

Calling F# constructor with properties initialization from secondary constructors

Given
type A() =
member val Prop: int = 0 with get, set
There are multiple ways to create an instance
let a0 = A() // Prop = 0
let a1 = A(Prop = 1)
let a2 = A()
a2.Prop <- 2
Now we want to enhance our class and allow passing the prop value in the constructor, but without losing the parameterless constructor we already have
type A1() =
member val Prop: int = 0 with get, set
new(prop: int) = A1(Prop = prop) //Error
However this is an error
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.
which doesn't seem correct as the new constructor is actually calling an alternate constructor.
There are alternatives/workarounds to achieve the result, for example:
type A2() =
member val Prop: int = 0 with get, set
static member Create(prop: int) = A(Prop = prop)
let a21 = A2.Create(1)
type A3(?prop: int) as this =
do if prop.IsSome then this.Prop <- prop.Value
member val Prop: int = 0 with get, set
let a31 = A3(1)
however the A1 version seems the cleanest and there are no apparent reasons why it cannot be valid (it is very similar to the A2 static member)
Can someone explain why the A1 syntax cannot be valid?
The primary constructor of your object should generally take all the parameters required for constructing a valid object. As a general rule I'd make the secondary constructor parameterless and the primary take all the parameters you care about.
If you must have a parameterless primary constructor but still want to assign properties in secondary constructors you can use the then keyword for side-effectful construction.
type A1() =
member val Prop: int = 0 with get, set
new(prop: int) as this =
A1()
then
this.Prop <- prop
I don't know if it cannot be valid if somebody decides the compiler should handle it, but I thought you might be interested in how we normally solve this case.
type A4(prop: int) =
member val Prop = prop with get, set
new() = A4(0)
let a4a = A4() // 0
let a4b = A4(3) // 3
let a4c = A4(Prop=7) // 7
Following this, it's useful to know how to make private constructors.
type A4 private (prop: int) =
member val Prop = prop with get, set
private new () = A4(0)
This example is of course rather useless code, but it shows where to put the private keyword. As you probably already understand, you can use one or more private constructors, typically with many parameters, as helpers for public constructors that have fewer parameters.

f# adding non interface functions to object expressions

Say I have an interface ICache which defines two functions, Function1 and Function2 and I use an object expression to implement it, but I also want to add a helper function:
let WebCache =
{ new ICache with
member __.HelperFunction = //this doesn't work!
member __.Function1 = foo
member __.Function2 = bar
}
F# seems to not allow you to add any methods that are not part of the interface. Is there a workaround? If I want to do this, should I not be using an object expression in the first place?
You can define the helper function as an ordinary (local) function outside of the object expression:
let WebCache =
let helper n =
printfn "Helping %" n
{ new ICache with
member __.Function1 = helper 1
member __.Function2 = helper 2 }

Is it possible for an object to access private field / function of another object of same class?

I know this is possible in C#, which produces simple and efficient code. --- Two objects of the same class can access each other's private parts.
class c1
{
private int A;
public void test(c1 c)
{
c.A = 5;
}
}
But It seems impossible in F#, is it true?
type c1()
let A = 0
member test (c: c1) = c.A
Interesting question. It seems to work with an explicit field but not with a let binding:
// Works
type c1 =
val private A : int
new(a) = { A = a }
member m.test(c : c1) = c.A
let someC1 = new c1(1)
let someMoreC1 = new c1(42);
let theAnswer = someC1.test someMoreC1
// Doesn't work
type c2() =
let mutable A = 42
// Compiler error: The field, constructor or member 'A' is not defined
member m.test(c : c2) = c.A
Yes, but in your example A is not semantically a private member of c1, it is more like a local variable of the constructor.
#afrischke gives an example of how to define c1 with an actual private member A (using val fields).
As section 8.6.1.3 of the F# spec states:
The functions and values defined by instance definitions are lexically scoped (and thus implicitly private) to the object being defined.
This is possible and it is widely used, for example, for checking memberwise equality:
type c1 =
member private this.A = 0
interface IEquatable<c1> with
member this.Equals (that: c1) = this.A = that.A
// of course, it can be done in a regular method as well
member this.Equals (that: c1) = this.A = that.A
You just use a directly in an instance method
type c1()
let A = 0
member x.test = A
For a static method this doesn't work as let bindings are slightly different - then you need a class definition like
type c1()
private member x.A = 0
static member test (A:c1) = A.A

How to create record with some local private functions in F#

type SQLConn =
val mutable private connection : string option
member this.Connection
with get() : string = this.connection.Value
and set(v) = this.connection <- Some v
new (connection : string) = {connection = Some connection;}
new() = SQLConn #"Data Source=D:\Projects\AL\Service\ncFlow\dbase\dbflow.db3; Version=3;Password=432432434324"
I want to use "let x = 5+5" there or something like that, so how can I use private functions in my type (class) (record) , I know that I can use them if I do SQLConn() , but then I can't use val, I want to use both : val and let ...
thank you
As Tim explains, you can only use local let bindings with the implicit constructor syntax. I would definitely follow this approach as it makes F# code more readable.
Do you have any particular reason why you also want to use val in your code? You can still use them with the implicit constructor syntax, but they have to be mutable and initialized using mutation:
type SQLConn(connection:string) as x =
let mutable connection = connection
// Declare field using 'val' declaration (has to be mutable)
[<DefaultValue>]
val mutable a : int
// Initialize the value imperatively in constructor
do x.a <- 10
member this.Connection
with get() = connection and set(v) = connection <- v
new() = SQLConn #"Data Source=.."
As far as I can tell val is only needed to create fields that are not private (which may be required by some code-gen based tools like ASP.NET, but is otherwise not really useful).
The error message explains the problem:
error FS0963: 'let' and 'do' bindings are not permitted in class definitions unless an implicit construction sequence is used. You can use an implicit construction sequence by modifying the type declaration to include arguments, e.g. 'type X(args) = ...'.
The error message is suggesting that you declare your class as type SQLConn(connection) =. If you do this, you probably ought to remove the member this.Connection property, since you'll no longer have a mutable field.
A more likely workaround would be to declare x as val x : int, then put the x = 5 + 5; initializer inside your constructor.
What about the following?
type SQLConn(conn:string) =
// could put some other let bindings here...
// ex: 'let y = 5 + 5' or whatever
let mutable conn = conn
new() = SQLConn(#"some default string")
member __.Connection
with get () = conn and set v = conn <- v

Resources