I'm running into an error when creating a signature file for an F# script file which I can't quite work out.
To replicate, create a new F# class library and add a file, Test.fs:
namespace Signatures
open System
type Test (id : Guid, name : string) =
member this.Id = id
member this.Name = name
This will build fine. Then create a new signature file above it, Test.fsi:
namespace Signatures
open System
type Test =
new : (Guid * String) -> Test
member Id : Guid
member Name : String
This will now not build with the error Module 'Signatures' requires a value 'new : (Guid * String) -> Test (this is different to the error you get if the constructor signature is different in the two files). The only real documentation I can find on defining constructors in the signature file is MSDN and that deals with parameterless constructors.
If you hover over Test in the .fs file the constructor's signature matches the one in the .fsi file. I've also tried changing the constructor so that it is not implicit with no joy.
I'm using the VS2012 RC, and have tried .Net 4 and 4.5.
It's too long for a comment, so I post it as an answer.
Test's constructor receives two arguments as its parameters, not one argument which is a tuple. I admit that * between arguments looks confusing. But the signature Guid -> string -> Test is even worse than that. Constructors should get some inputs and produce a new type instance. Curried form and partial application don't make sense in the context of constructors.
I think the brackets help clarify here.
type Test (id : System.Guid, name : string) =
member this.Id = id
member this.Name = name
produces new : id:Guid * name:string -> Test while
type Test (tuple: System.Guid * string) =
let id, name = tuple
member this.Id = id
member this.Name = name
gives me new : tuple:(Guid * string) -> Test in an FSI session. I use F# 2.0/MonoDevelop 3.0 for the record.
Regarding creating type signatures, I usually send code into F# Interactive and copy produced signatures to fsi files to avoid mistakes. If the tooltips and F# Interactive show type signatures wrongly on VS2012 RC, you should report at fsbugs (at) microsoft (dot) com.
An extra pair of parens can be significant. Consider the following:
type T =
static member Add(x, y) = x + y
static member AddTuple((x, y)) = x + y
which, in C#, appear as
int Add(int x, int y)
int AddTuple(Tuple<int, int> arg)
Tangentially, you can't do something similar in a constructor:
type Test((id, name)) = class end //DOESN'T COMPILE
Since constructors already take arguments in tupled form you would expect 'a * 'b and ('a * 'b) to be different things. This is consistent with method syntax.
If anyone wants to explain why this works, I'd love to know but I just started fiddling with the syntax to see if I could get anything more revealing out of the compiler.
If I remove the brackets are the tuple, it compiles, i.e. change this:
new : (Guid * String) -> Test
To:
new : Guid * String -> Test
Related
I'm writing an integration test for a third party C# library in an F# code base. There are some constraints to this integration test.
For regulatory reasons I must test with MsTest
The library only works with a valid license
We cannot commit the license into our repository
I don't want to hardcode the location of the valid license into the test
I've got the failing test passing, but can't figure out how to write the test with a valid license. The function Initialize is just a wrapper for the third party library to initialize the library with the license and returns the Result.
[<TestClass>]
type ``Test Local Initialize`` () =
[<TestMethod>]
member this.``When loading an invalid INI file`` () =
let actual =
$#"{AppDomain.CurrentDomain.BaseDirectory}Resources\DummyLicense.INI"
|> Initialize
match actual with
| Ok _ -> Assert.Fail("Should not initialize with an invalid configuration.")
| Error e -> Assert.IsNotNull(e, "Should error with an invalid configuration")
The test I want to write is "given a valid license file, initializing the library should return a Result of OK."
In C#, I would use the .runsettings to point to a license folder, but I'm pretty new to F# and I'm not really sure how I would add the TestContext to the test. Since the tests are defined as a type, I'm guessing they don't hold state or fields.
So my questions are:
Is there a way to load the TextContext in F#?
Is there a more idiomatic way to achieve this in F#?
It works much the same as in C#. In your test class, mark a static member with the ClassInitialize or AssemblyInitialize attribute and specify a context parameter:
[<TestClass>]
type TestClass () =
static let mutable myValue = ""
[<ClassInitialize>]
static member Setup(context : TestContext) =
myValue <- string context.Properties.["MyValue"]
[<TestMethod>]
member this.TestMyValue() =
Assert.AreEqual("xyzzy", myValue)
I'm attempting to implement the interface IDispatchMessageInspector (of WCF fame) in F#:
open System.ServiceModel.Dispatcher
open System.ServiceModel.Channels
type ServiceInterceptor() as interceptor =
abstract member PreInvoke : byref<Message> -> obj
abstract member PostInvoke : byref<Message> -> obj -> unit
default x.PreInvoke m = null
default x.PostInvoke m s = ()
interface IDispatchMessageInspector with
member x.AfterReceiveRequest(request, channel, instanceContext) = interceptor.PreInvoke(&request)
member x.BeforeSendReply(reply : byref<Message>, correlationState) = interceptor.PostInvoke &reply correlationState
This fails to compile with the following error:
However, if I modify my code to the following (note the change of signature in PostInvoke) everything works:
open System.ServiceModel.Dispatcher
open System.ServiceModel.Channels
type ServiceInterceptor() as interceptor =
abstract member PreInvoke : byref<Message> -> obj
abstract member PostInvoke : byref<Message> * obj -> unit
default x.PreInvoke m = null
default x.PostInvoke (m, s) = ()
interface IDispatchMessageInspector with
member x.AfterReceiveRequest(request, channel, instanceContext) = interceptor.PreInvoke(&request)
member x.BeforeSendReply(reply : byref<Message>, correlationState) = interceptor.PostInvoke(&reply, correlationState)
Is this behaviour expected? And if so could someone explain the reasoning behind it....
The reason is that byref<'T> is not a real type in .NET. F# uses this for representing values that are passed via ref and out parameters, but it is not a normal type that could appear anywhere in your program.
F# restricts the scope in which they can be used - you can only use them for local variables (basically passing around a reference or a pointer) and you can use them as method parameters (where the compiler can then compile it as a method parameter).
With curried methods, the compiler is producing a property that returns a function value and so (under the cover), you get something like a property PostInvoke of type FSharpFunc<T1, FSharpFunc<T2, T3>>. And here, T1 or T2 cannot be byref<T> types, because byref is not a real .NET type. So that's why curried methods cannot have byref parameters.
Another case where you can see this is if you, for example, try to create a list of byref values:
let foo () =
let a : list<byref<int>> = []
a
Here you get:
error FS0412: A type instantiation involves a byref type. This is not permitted by the rules of Common IL.
So I have been doing research on interfaces on F#. I have found these 2 articles on it. The MSDN and F# for fun and profit But unfortunately they are only skin deep.
UPDATED
here is my module with my interfaces
//open statements omitted for brevity
module DrawingInterfaces =
///gets a string representation of the SVG code representation of the object
type IRepresentable_SVG =
abstract member getSVGRepresenation : unit -> string
//other interfaces omitted for brevity
Now within the same namespace and physical folder also I have this:
type lineSet (x1off,x2off,y1off,y2off,x1,x2,y1,y2,rot,rotOff,count) =
//tons of member vals omitted for brevity
member val x1Start = x1 with get, set
interface DrawingInterfaces.IRepresentable_SVG with
member __.getSVGRepresenation() =
let mutable svg = ""
let mutable currentx1 = x1Start
svg
This used to give me 2 errors, before I was using the __. notation for the member. The first error was on the interface line. And a second on the member line.
The errors were respectively:
The type 'IRepresentable_SVG' is not defined
This instance member needs a parameter to represent the object being invoked.
I was able to fix the first one by changing the file order. Thanks to John Palmer.
The second one is nearly fixed./
After using the __ . notation I was able to get rid of the second error. However, now a new error pops up when I try to use type members in my interface implementation.
let mutable currentx1 = x1Start
x1Start shows as not being defined. I need to be able to use values stored in my other members within my implementation.
Let's first make it work and then point to your problems. I define below 2 separate modules in 2 separate .fs files within the same namespace Example for interface definition in module Example.DrawingInterfacesand interface implementation in module Example.UseInterface and also a console app that will use the interface from third (implicit) module Program. In my project correspondent code files are in the following order: DefInterface.fs, UseInterface,fs, Program.fs (I also made few idiomatic styling changes and more brevity omissions)
File: DefInterface.fs
namespace Example
module DrawingInterfaces =
type IRepresentable_SVG =
abstract member GetSVGRepresenation : unit -> string
File: UseInterface.fs
namespace Example
module UseInterface =
type LineSet (x1) =
member val X1Start = x1 with get, set
interface DrawingInterfaces.IRepresentable_SVG with
member __.GetSVGRepresenation() = "test" + " " + __.X1Start.ToString()
File: Program.fs
open Example
open System
[<EntryPoint>]
let main argv =
let lineSet = UseInterface.LineSet(5)
let example : DrawingInterfaces.IRepresentable_SVG = lineSet :> _
example.GetSVGRepresenation() |> printfn "%A"
lineSet.X1Start <- 10
example.GetSVGRepresenation() |> printfn "%A"
0
Compile, run and make sure it works.
Now to problems in your code:
first error message stems from the need to refer to the full implemented interface name in UseInterface.fs, which is Example.DrawingInterfaces.IRepresentable_SVG although as both modules belong to the same namespace the Example prefix may be omitted
second error message points to the need of using instance method in implementation class UseInterface.LineSet, which is achieved by prepending self-identifier __. to the method signature
Finally, notice the usage of your interface in Program.fs that imports namespace, provides module names for definition and implementation respectively, and also explicitly casts implementation LineSet to IRepresentable_SVG.
EDIT: I've added X1Start property to the original LineSet to show how it can be used from interface implementation per question author's request. Now self-id __. is more involved and probably using self. or even this. instead would make more sense.
I want to implement IEnumerable<KeyValuePair<DateTime, 'T>> in my own class and add math operators to that class so that the operators could work like inline function on any numeric types of 'T - automatically add constraints.
I just cannot make the following piece of code work. It doesn't work neither with nor without 'inline' keyword at the member declaration.
Also, if I define a function
let inline add l r = l + r
before the type and use it instead of addition l.Value + r.Value, it also doesn't work.
Could someone please show me what I am doing wrong?
Probably the whole approach is wrong and there is a way to achieve the same goal the other way?
namespace Test
open System
open System.Linq
open System.Collections.Generic
[<SerializableAttribute>]
type TimeSeries<'T>(dictionary : IDictionary<DateTime, 'T>) =
let internalList = new SortedList<DateTime, 'T>(dictionary)
interface IEnumerable<KeyValuePair<DateTime, 'T>> with
member this.GetEnumerator() = internalList.GetEnumerator()
member this.GetEnumerator() : Collections.IEnumerator
= internalList.GetEnumerator() :> Collections.IEnumerator
member private this.sl = internalList
static member inline (+) (left : TimeSeries<'T>, right : TimeSeries<'T>) =
let res =
query {
for l in left do
join r in right on
(l.Key = r.Key)
select (l.Key, l.Value + r.Value)
}
new TimeSeries<'T>(res |> dict)
Your approach seems correct to me.
The reason why your code doesn't compile is because F# type inference is inferring a static constraint (compile-time) for the type variable 'T which is the same used for the type definition.
A generic parameter of a type definition can't be statically resolved (no "hat" types) but nothing stops you from defining a function or a member which uses these compile-time constraints.
Just change your type variable 'T to 'U in the static member (+) definition and it will be fine.
Still you'll be allowed to create a TimeSeries instance of a type which does not support (+) (ie: TimeSeries<obj>) but you will not be able to use (+) for those instances, anyway if you do it you'll get a nice error message at compile-time.
Updated below...
I recently started experimenting with ServiceStack in F#, so naturally I started with porting the Hello World sample:
open ServiceStack.ServiceHost
open ServiceStack.ServiceInterface
open ServiceStack.WebHost.Endpoints
[<CLIMutable; Route("/hello"); Route("/hello/{Name}")>]
type Hello = { Name : string }
[<CLIMutable>]
type HelloResponse = { Result : string }
type HelloService() =
inherit Service()
member x.Any(req:Hello) =
box { Result = sprintf "Hello, %s!" req.Name }
type HelloAppHost() =
inherit AppHostBase("Hello Web Services", typeof<HelloService>.Assembly)
override x.Configure container = ()
type Global() =
inherit System.Web.HttpApplication()
member x.Application_Start() =
let appHost = new HelloAppHost()
appHost.Init()
That works great. It's very concise, easy to work with, I love it. However, I noticed that the routes defined in the sample allow for the Name parameter to not be included. Of course, Hello, ! looks kind of lame as output. I could use String.IsNullOrEmpty, but it is idiomatic in F# to be explicit about things that are optional by using the Option type. So I modified my Hello type accordingly to see what would happen:
[<CLIMutable; Route("/hello"); Route("/hello/{Name}")>]
type Hello = { Name : string option }
As soon as I did this, the F# type system forced me to deal with the fact that Name might not have a value, so I changed HelloService to this to get everything to compile:
type HelloService() =
inherit Service()
member x.Any(req:Hello) =
box { Result =
match req.Name with
| Some name -> sprintf "Hello, %s!" name
| None -> "Hello!" }
This compiles, and runs perfectly when I don't supply a Name parameter. However, when I do supply a name...
KeyValueDataContractDeserializer: Error converting to type: Type
definitions should start with a '{', expecting serialized type
'FSharpOption`1', got string starting with: World
This wasn't a complete surprise of course, but it brings me to my question:
It would be trivial for me to write a function that can wrap an instance of type T into an instance of type FSharpOption<T>. Are there any hooks in ServiceStack that would let me provide such a function for use during deserialization? I looked, but I couldn't find any, and I'm hoping I was just looking in the wrong place.
This is more important for F# use than it might seem at first, because classes defined in F# are by default not allowed to be null. So the only (satisfying, non-hacky) way of having one class as an optional property of another class is with, you guessed it, the Option type.
Update:
I was able to sort-of get this working by making the following changes:
In the ServiceStack source, I made this type public:
ServiceStack.Text.Common.ParseFactoryDelegate
...and I also made this field public:
ServiceStack.Text.Jsv.JsvReader.ParseFnCache
With those two things public, I was able to write this code in F# to modify the ParseFnCache dictionary. I had to run this code prior to creating an instance of my AppHost - it didn't work if I ran it inside the AppHost's Configure method.
JsvReader.ParseFnCache.[typeof<Option<string>>] <-
ParseFactoryDelegate(fun () ->
ParseStringDelegate(fun s -> (if String.IsNullOrEmpty s then None else Some s) |> box))
This works for my original test case, but aside from the fact that I had to make brittle changes to the internals of ServiceStack, it sucks because I have to do it once for each type I want to be able to wrap in an Option<T>.
What would be better is if I could do this in a generic way. In C# terms, it would be awesome if I could provide to ServiceStack a Func<T, Option<T>> and ServiceStack would, when deserializing a property whose generic type definition matches that of the return type of my function, deserialize T and then pass the result into my function.
Something like that would be amazingly convenient, but I could live with the once-per-wrapped-type approach if it were actually part of ServiceStack and not my ugly hack that probably breaks something somewhere else.
So there are a couple of extensibility points in ServiceStack, on the framework level you can add your own Custom Request Binder this allows you to provide your own model binder that's used, e.g:
base.RequestBinders.Add(typeof(Hello), httpReq => {
var requestDto = ...;
return requestDto;
});
But then you would need to handle the model binding for the different Content-Types yourself, see CreateContentTypeRequest for how ServiceStack does it.
Then there are hooks at the JSON Serializer level, e.g:
JsConfig<Hello>.OnDeserializedFn = dto => newDto;
This lets you modify the instance of the type returned, but it still needs to be the same type but it looks like the F# option modifier changes the structural definition of the type?
But I'm open to adding any hooks that would make ServiceStack more palatable for F#.
What does the code look like to generically convert a normal Hello type to an F# Hello type with option?
The only thing I can think of is to replace the option type with your own type, one that has an implicit conversion from string to myOption, and anything else you need.
Not all that nice, but workable. Your type would probably also need to be serializable.
type myOption =
| None
| Some of string
static member public op_Implicit (s:string) = if s <> null then Some s else None
member public this.Value = match this with
| Some s -> s
| _ -> null
member this.Opt = match this with
| Some s -> Option.Some s
| None -> Option.None
Your record type would then be
[<CLIMutable>]
type Hello =
{ Name : myOption }
On the other hand, ServiceStack is open source, so maybe something could be done there.