Jamie Dixon
Jamie Dixon

Reputation: 4302

F# Referencing Types

I am working on a project where the F# code will be consumed by other .NET projects - so I am using classes. I created a code file like this:

namespace StockApplication

open System


type Stock = 
    {Symbol: String;
     DayOpen: Decimal;
     Price: Decimal;
     }

    member x.GetChange () =
        x.Price - x.DayOpen

    member x.GetPercentChange() =
        Math.Round(x.GetChange()/x.DayOpen,4)

This works fine when I consume it from some unit tests written in C#. For example:

[TestMethod]
public void CreateStock_ReturnsValidInstance()
{
    Stock stock = new Stock("TEST", 10, 10.25M);
    Assert.IsNotNull(stock);
}

I then went to create another file with another class. This class uses the 1st class so I made sure it was below the original class in VS2012. When I created the next class, I can see it available via intellisense.

namespace StockApplication


open System

type StockTicker() = 
    member x.GetStock () =
        StockApplication.Stock

However, every attept to either new it or refer it gives me the same error:

Error 1 The value, constructor, namespace or type 'Stock' is not defined

Does anyone have any insight on why I can just simply new up a class that I created in F# in another F# file?

Thanks in advance.

Upvotes: 1

Views: 200

Answers (2)

Gene Belitski
Gene Belitski

Reputation: 10350

Your C# test having Stock stock = new Stock("TEST", 10, 10.25M); that was compiled without a problem prompts to believe that F# constructor for the Stock should look the same. But this is not true and, perhaps, was the source of your confusion.

Your original

type Stock = 
    {Symbol: String;
     DayOpen: Decimal;
     Price: Decimal; }

is of F# type Record indeed, not an ordinary class. The following excerpt from MSDN applies:

Record construction also differs from class construction. In a record type, you cannot define a constructor.

Meaning that

let stock = Stock("ABC"; 10M; 10M)

will produce error FS0039: The value or constructor 'Stock' is not defined while

let stock = { Symbol = "ABC"; DayOpen = 10M; Price = 10M; }

will successfully create a record instance.

In order to build an instance of type Stock in your second F# type StockTicker you should use record construction syntax, something like

member x.GetStock () = { Symbol = "MSFT"; DayOpen = 32M; Price = 32.5M; }

which compiles without any problems.

When it comes to interop use of F# record from C# the latter follows the syntax that you applied in your test method.

Upvotes: 3

Jamie Dixon
Jamie Dixon

Reputation: 4302

OK, after digging into this reference (MSDN was 0 help) here, I found the answer.

Here is the syntax for the Stock class:

namespace StockApplication

open System


type Stock = class
    val Symbol: String
    val DayOpen: Decimal
    val Price: Decimal

    new (symbol, dayOpen, price) =
        {
            Symbol = symbol;
            DayOpen = dayOpen;
            Price = price
        }

    member x.GetChange () =
        x.Price - x.DayOpen

    member x.GetPercentChange() =
        Math.Round(x.GetChange()/x.DayOpen,4)


end

And here is the syntax for the consuming class:

namespace StockApplication

type StockTicker() = 
    member x.GetStock () =
        let y = new Stock("AET",1m,1m)
        y.DayOpen

Upvotes: 2

Related Questions