Reputation: 4302
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
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
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