2

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.

Thomas
  • 10,933
  • 14
  • 65
  • 136
  • When you say "this won't work", what does that mean exactly? – Fyodor Soikin Oct 24 '20 at 14:50
  • @FyodorSoikin, sorry I should have precised; I get this message: [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. – Thomas Oct 24 '20 at 15:11

1 Answers1

2

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.

Fyodor Soikin
  • 78,590
  • 9
  • 125
  • 172