tags:

views:

249

answers:

3

I decided to port the class in C# below to F# as an exercise.

It was difficult. I only notice three problems

1) Greet is visible 2) I can not get v to be a static class variable 3) I do not know how to set the greet member in the constructor.

How do i fix these? The code should be similar enough that i do not need to change any C# source. ATM only Test1.v = 21; does not work

C#

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
A: 

You're defining greet as a property. It doesn't need to be one.

// 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# doesn't allow you to have public static class variables. You have to use a getter/setter.

gradbot
You can hide F# module members using a .fsi file, making them functionally identical to private static functions.
Juliet
+2  A: 

Below is some F# that compiles against the C# client.

In .NET, one very rarely exposes public fields; I would recommend against it. The F# syntax for exposing 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
Brian
+2  A: 

The F# language has some constructs that don't have any equivalent in C#, but it has almost everything that you can use in C#. This means that if you simply translate code from C# to F#, you'll 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 is also the case of static members. In addition to classes, you can also organize F# code using modules and modules provide a natural way for declaring static data and functions. Here is an example of 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 need some static functionality and some instance functionality, it is usually easy to split the functionality between a module and a standard class. The obvious benefit is that it gives you easier syntax, but it may also help structuring the code:

type Person(name) =
  member GreetMe() = 
    Greetings.greet(name)

Members inside module can be declared as private or internal if you want to keep them hidden from the user. For example if you wanted to make the how field accessible only to your assembly, you could write:

let mutable internal how = "Hello "  

I think this gives you more idiomatic F# code, so I would probably prefer this style of programming when writing F# code. If you plan to use this from C#, then modules will appear as static classes, which are also easy to use.

As a side-note, it is generally recomended to avoid using too many mutable members. However, if you're using them for some kind of configuration then I suppose it is OK.

Tomas Petricek
Right now i am only using them to so i know i can use them if i need to. As you can tell the class is mostly useless doing different things just so it can mess me up with gotchas. I almost quit before i got as far as i did.
acidzombie24
Yes, I understand that your class is just an example to understand how to write some C# construct in F#. I wanted to give a broader answer to emphasize idiomatic F# programming style (perhaps just for the case when someone finds this question later). Anyway, you really don't need to worry about this kind of gotchas when learning F# (C# objects are just terribly complex!!)
Tomas Petricek