Declare private static members in F #?
I decided to port the C # class below to F # as an exercise.
It was complicated. I only noticed three problems.
1) The greeting is visible 2) I can't get v to be a static class variable 3) I don't know how to set the greeting in the constructor.
How to fix it? The code should be similar enough so that I don't have to change any C # source. Only for ATM Test1.v = 21; does not work
FROM#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CsFsTest
{
class Program
{
static void Main(string[] args)
{
Test1.hi("stu");
new Test1().hi();
Test1.v = 21;
var a = new Test1("Stan");
a.hi();
a.a = 9;
Console.WriteLine("v = {0} {1} {2}", a.a, a.b, a.NotSTATIC());
}
}
class Test1
{
public int a;
public int b { get { return a * 2; } }
string greet = "User";
public static int v;
public Test1() {}
public Test1(string name) { greet = name; }
public static void hi(string greet) { Console.WriteLine("Hi {0}", greet); }
public void hi() { Console.WriteLine("Hi {0} #{1}", greet, v); }
public int NotSTATIC() { return v; }
}
}
F #
namespace CsFsTest
type Test1 =
(*
public int a;
public int b { get { return a * 2; } }
string greet = "User";
public static int v;
*)
[<DefaultValue>]
val mutable a : int
member x.b = x.a * 2
member x.greet = "User" (*!! Needs to be private *)
[<DefaultValue>]
val mutable v : int (*!! Needs to be static *)
(*
public Test1() {}
public Test1(string name) { greet = name; }
*)
new () = {}
new (name) = { }
(*
public static void hi(string greet) { Console.WriteLine("Hi {0}", greet); }
public void hi() { Console.WriteLine("Hi {0} #{1}", greet, v); }
public int NotSTATIC() { return v; }
*)
static member hi(greet) =
printfn "hi %s" greet
member x.hi() =
printfn "hi %s #%i" x.greet x.v
member x.NotSTATIC() =
x.v
Below are a few F # that compile against the C # client.
In .NET, public fields are rarely exposed; I would recommend against this. The F # syntax for expanding fields is somewhat cumbersome.
namespace CsFsTest
open System
type Test1 =
val mutable private greet : string
[<DefaultValue>]
val mutable public a : int
[<DefaultValue>]
static val mutable private vv : int
static member v with get() = Test1.vv
and set(x) = Test1.vv <- x
member this.b = this.a*2
static member hi(greet:string) = Console.WriteLine("Hi {0}", greet)
member this.hi() = Console.WriteLine("Hi {0} #{1}", this.greet, Test1.v)
new() = { greet = "User" }
new(name : string) = { greet = name }
member this.NotSTATIC() = Test1.v
source to share
The F # language has some constructs that have no C # equivalent, but it has almost everything that you can use in C #. This means that if you just translate code from C # to F #, you end up using only a subset of F #. As a result, it is sometimes better to look for some specific F # constructs.
I think this also applies to static members. In addition to classes, you can also organize your F # code using modules and modules, which provide a natural way to declare static data and functions. Here's an example of a module for greeting:
// modules are automatically 'static' (from the C# point of viedw)
module Greetings =
// public mutable field inside a module
let mutable how = "Hello "
// global function that uses the field
let greet name =
Console.WriteLine(how + name)
// modify the global field and invoke global function
Greetings.how <- "Ahoj "
Greetings.greet("Tomas")
If you want static functionality and the functionality of some instances, it is usually easy to split functionality between a module and a standard class. The obvious advantage is that it gives you an easier syntax, but it can also help you structure your code:
type Person(name) =
member GreetMe() =
Greetings.greet(name)
Members within a module can be declared as private
or internal
if you want to keep them hidden from the user. For example, if you want to make a field how
available only to your assembly, you can write:
let mutable internal how = "Hello "
I think this gives you more idiomatic F # code, so I would prefer this programming style when writing F # code. If you plan to use this from C # then the modules will appear as static classes which are easy to use as well.
As a side note, it is generally recommended to avoid using too many mutable elements. However, if you are using them for some kind of configuration, then I suppose everything is fine.
source to share
You define the greeting as a property. He doesn't have to be alone.
// these are the same
member x.greet = "User"
member x.greet with get() = "User"
It can just be a variable.
val mutable private greet : string
new () = { greet = "User" }
new (name) = { greet = name }
F # does not allow you to have public variables of a static class. You must use a getter / setter.
source to share