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

      

+2


source to share


3 answers


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

      

+5


source


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.

+10


source


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.

+2


source







All Articles