Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I properly override a constrained method

How do I override the method Zero in the following code in such a way that I can return Euro(0) for the definiton in the type Euro

[<AbstractClass>] 
type Currency () =
    abstract member Zero<'T when 'T :> Currency > : unit -> 'T

type Euro (value: int) =
    inherit Currency()
    member this.Value = value
    override this.Zero() = Euro(0) :> _
like image 208
robkuz Avatar asked Feb 15 '17 15:02

robkuz


2 Answers

Have you tried lifting the generic constraint to the class level?

[<AbstractClass>] 
type Currency<'T when 'T :> Currency<'T>>() =
    abstract member Zero : unit -> 'T

type Euro (value: int) =
    inherit Currency<Euro>()
    member this.Value = value
    override this.Zero() = Euro(0)

Though self-referencing generics always seems weird to me, this is how it'd be done in, for example, C#.

like image 83
pblasucci Avatar answered Oct 17 '22 22:10

pblasucci


There is also the 'roll your own typeclass' technique in F#. Basically your abstract type's (instance and static) members become the fields of a 'typeclass' record, and values of that record are typeclass instances. You can have a 'euro' instance, a 'dollar' instance, and so on:

module Currency =
  type t<[<Measure>] 'a> =
    { zero : decimal<'a>; from : decimal -> decimal<'a> }

  /// Helper function to easily create typeclass instances for any
  /// currency.
  let make<[<Measure>] 'a> (curr_unit : decimal<'a>) : t<'a> =
    { zero = curr_unit - curr_unit; from = ((*) curr_unit) }

  [<Measure>] type euro
  let euro : t<euro> = make 1m<euro>

  [<Measure>] type dollar
  let dollar : t<dollar> = make 1m<dollar>

The unique thing about F# is that the type parameter that is passed to each typeclass instance can actually be a measure type, which is appropriate for currencies.

like image 36
Yawar Avatar answered Oct 17 '22 23:10

Yawar