I would like to extend DateTime in the following fashion:
[<AutoOpen>]
type System.DateTime with
member this.floor (interval: TimeSpan) =
this.AddTicks(-(this.Ticks % interval.Ticks))
member this.ceiling (interval: TimeSpan) =
let overflow = this.Ticks % interval.Ticks
if overflow = 0 then this else this.AddTicks(interval.Ticks - overflow)
member this.round (interval: TimeSpan) =
let halfIntervalTicks = (interval.Ticks + 1) >>> 1
this.AddTicks(halfIntervalTicks - ((this.Ticks + halfIntervalTicks) % interval.Ticks))
based on aj.toulan's C# answer at: DateTime Round Up and Down
but this won't work; apparently I should be using a module, but then how do I get the 'this' part? what would be the right syntax?
I get this error:
[FS0644] Namespaces cannot contain extension members except in the
same file and namespace declaration group where the type is defined.
Consider using a module to hold declarations of extension members.
Judging by the error message, I'm assuming you have that declaration inside a namespace, like this:
namespace N
type System.DateTime with
...
If so, then my first question is: why do you need a namespace in the first place? Use modules instead! Modules are more idiomatic in F# and let you do more stuff:
module N
type System.DateTime with
...
But if you must have a namespace for some reason, you can still make this work by using the advice that is given to you in the error message itself: put the extensions inside a module!
namespace N
module M =
type System.DateTime with
...
Of course, now you would also have to open that module at use sites:
open N
open M // <-- extra open
... DateTime.Now.floor ...
But you can avoid that as well by giving that module an [<AutoOpen>] attribute:
namespace N
[<AutoOpen>]
module M =
type System.DateTime with
...
Now the use site can open just the namespace:
open N
... DateTime.Now.floor ...
Also, note that [<AutoOpen>] on the type extension is non-sensical. Type extensions are always open, that's their very point, you don't need to open them explicitly or have an AutoOpen attribute.
Related
Given the following code int the implementation file:
namespace Lib
module Test =
type ITest =
abstract member IsTest: bool
type T = Test with
interface ITest with
member this.IsTest = true
let create () = Test
And the following signature file:
namespace Lib
module Test =
[<Interface>]
type ITest =
abstract member IsTest: bool
type T
val create: unit -> T
The following warning occurs:
Warning 2. The type implements the interface 'Test.ITest' but this is not revealed by the signature. You should list the interface in the signature, as the interface will be discoverable via dynamic type casts and/or reflection.
How should the signature of type T be changed in the signature file to conform to the implementation?
You should list the interfaces in the type definition inside the module signature (fsi) file, for example:
namespace Lib
module Test =
[<Interface>]
type ITest =
abstract member IsTest: bool
type T =
interface ITest
//you can list other interfaces here
val create: unit -> T
Note, there is no member listing when you specify the interfaces in the fsi files (we omitted the IsTest member when defining type T), the member listing should be part of the module implementation (fs) file.
Update
The above example is valid for F# 4.0. Since the OP tagged the question with the F#-3.0 tag, then the syntax for the older F# should be a little different -- in the fsi file instead of
type T = ...
use
type T with ...
this has to be changed as in the original example if you plan on upgrading to F# 4+. The compiler will display the relevant warnings for this change
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'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
Hi would like to know how to make the f# compiler to auto open a namespace automatically.
I have
namespace XXX
I have to add something here do(AutoOpen("XXX.YYY")) or something like that to make the XXX.YYY module to be opened when referencing the library from external projects.
[<AutoOpen>]
module YYY =
....
Thanks
In order to open a namespace/module without opening its parent first, you have to add the attribute on assembly level.
You can do this by adding an AssemblyInfo.fs file to your project:
In the case of the following code:
namespace Framework
module GlobalFunctions =
let Test () =
10.
You would for instance add the following code to AssemblyInfo.fs:
namespace Framework
[<assembly:AutoOpen("Framework.GlobalFunctions")>]
do()
And then you can call the code from a script (.fsx) file with:
#r #"C:\PathToAssembly\Assembly.dll"
let result = Test ()
Resulting in:
--> Referenced 'C:\PathToAssembly\Assembly.dll'
val result : float = 10.0
The AutoOpen attribute can be applied only to F# module, so you won't be able to add it to an entire namespace. However, since you can place all F# declarations inside a module, that may be enough for what you need. The syntax is:
[<AutoOpen>]
module MyGlobals =
// Declarations in the module
type Foo() =
member x.Bar = 10
When you reference the assembly, you should see Foo immediately. If the declaration is placed inside another namespace (i.e. MyLibrary), then you'll need to add open MyLibrary, but MyGlobals will be accessible automatically.
I'm aware of other questions about modules and namespaces in F#, but they're not helping me right now.
I've got a project with
Utilities.fs
namespace Company.Project.Namespace
module Utilities =
//stuff here
Functions.fs
namespace Company.Project.Namespace
open Utilities
module Functions =
//stuff here
And I'm trying to test them in an fsx:
#load "Utilities.fs"
#load "Functions.fs"
which gives me error FS0039: The namespace or module 'Utilities' is not defined when I try to send it to FSI with Alt-Enter.
I've tried adding same namespace at the top of the script file, but it doesn't like that.
What's weird is that the background compiler doesn't shout at me.
This seems to work, but is it the right approch?
#load "Utilities.fs"
open Company.Project.Namespace
#load "Functions.fs"
Is there a 'reference' FSharp project somewhere, which contains examples of how to integrate all this stuff: namespaces, modules, classes, script files, tests etc.?
I'm not an expert with FSI, but some experimentation suggests that namespaces are only supported by #load declarations (not via typical interactions - sending a namespace declaration group to VFSI via Alt-Enter does not work), and that different interactions contribute different 'instances'. For example, with the code file
namespace Foo
type Bar() =
member this.Qux() = printfn "hi"
namespace Other
type Whatever() = class end
namespace Foo
module M =
let bar = new Bar()
bar.Qux()
if I #load it more than once I get e.g.
> [Loading C:\Program.fs]
hi
namespace FSI_0002.Foo
type Bar =
class
new : unit -> Bar
member Qux : unit -> unit
end
namespace FSI_0002.Other
type Whatever =
class
new : unit -> Whatever
end
namespace FSI_0002.Foo
val bar : Bar
> #load #"C:\Program.fs";;
> [Loading C:\Program.fs]
hi
namespace FSI_0003.Foo
type Bar =
class
new : unit -> Bar
member Qux : unit -> unit
end
namespace FSI_0003.Other
type Whatever =
class
new : unit -> Whatever
end
namespace FSI_0003.Foo
val bar : Bar
> new Foo.Bar();;
> val it : Foo.Bar = FSI_0003.Foo.Bar
Note that it seems the FSI_0003.Foo.Bar shadowed the FSI_0002 version.
So I'm thinking the part of the F# spec that says
Within a namespace declaration group,
the namespace itself is implicitly
opened if any preceding namespace
declaration groups or referenced
assemblies contribute to this
namespace, e.g.
namespace MyCompany.MyLibrary
module Values1 =
let x = 1
namespace MyCompany.MyLibrary
// Implicit open of MyCompany.MyLibrary bringing Values1 into scope
module Values2 =
let x = Values1.x
However this only opens the namespace
as constituted by preceding namespace
declaration groups.
Does not interact with FSI, given FSI's limited understanding of namespaces. Specifically, I expect that the 'second #load' from your example opens e.g. FSI_000N+1's version of the namespace, whereas the prior code was in FSI_000N. Which maybe-explains why the explicit open interaction fixes it; you bring the existing, unshadowed FSI_000N stuff up to the top level before trying to (implicitly) reference it later.
I'm relatively new at this too, but this is what works for me when I'm testing in an fsx file:
#if INTERACTIVE
#r #"C:\Program Files\FSharpPowerPack-2.0.0.0\bin\FParsec.dll"
#r #"C:\Program Files\FSharpPowerPack-2.0.0.0\bin\FParsecCS.dll"
#endif
open FParsec.Primitives
open FParsec.CharParsers
followed by my code that uses these libraries.