Override method with generic type signature - f#

How can I override an abstract method with a generic type signature, and give it a more specific parameter type in a subclass?
type Rule() =
abstract Core : 'T -> bool
default _.Core _ = false
type Entity = {
Name: string
State: string
}
type Wisconsin() =
inherit Rule()
override _.Core (entity: Entity) =
entity.State = "WI"
SimpleMemberOverload.fsx(256,22): error FS0001: This expression was expected to have type
''a'
but here has type
'Entity'

You can't. After all, saying a rule takes any 'T and then having such a rule taking only entities would violate the contract. What should a caller having a reference of type Rule pointing to an object of type Wisconsin expect if e.g. a string is passed to Core?
You could however define various rules like so:
type Rule<'T> () =
abstract Core : 'T -> bool
default _.Core _ = false
type Entity = {
Name: string
State: string
}
type Wisconsin() =
inherit Rule<Entity>()
override _.Core entity =
entity.State = "WI"
meaning Wisconsin does not narrow the parameter type but now is a rule for/of entities.

Related

F# multiple interface implementations with object expressions

According to docs you can implement multiple interfaces with object expressions. But if you see below code :
// Define two interfaces
type IFirst =
abstract F : unit -> unit
abstract G : unit -> unit
type ISecond =
abstract H : unit -> unit
abstract J : unit -> unit
// This object expression implements both interfaces.
let implementer : IFirst =
{ new ISecond with
member this.H() = ()
member this.J() = ()
interface IFirst with
member this.F() = ()
member this.G() = () }
So casting to IFirst causes a compiler error. Why is that so?
F# does not perform implicit conversions.
When type annotating in a let binding, the type must strictly match the expression.
For example,
let value : obj = new System.Collections.Generic.List<int>()
will fail to compile, even though a List is very obviously an object.
When you write:
let implementer : IFirst = expr
The type of expr must absolutely be IFirst. There's no implicit casting like in C#.
An object expression will have its type as the abstract type implemented, so:
{ new ISecond with ... }
will be inferred to have a type of ISecond. Combine it with no-implicit casts rule, and you have a compile error.
Because IFirst and ISecond are unrelated, you could (runtime) downcast to IFirst:
let firstImplementer = implementer :?> IFirst
Another option is to make a combined interface:
type IBoth = inherit IFirst inherit ISecond
and do:
let implementer =
{
new IBoth with ...
That way you can freely (static) upcast to IFirst or ISecond.
let firstImplementer = implementer :> IFirst
let secndImplementer = implementer :> ISecond

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) :> _
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#.
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.

Why can't F# infer the type in this case?

Consider the following sample code where I have a generic type and 2 static member constructors that create a specialized instance of the said type.
type Cell<'T> = { slot: 'T }
with
static member CreateInt x : IntCell = { slot = x }
static member CreateString x : StringCell = { slot = x}
and IntCell = Cell<int>
and StringCell = Cell<string>
// Warnings on the next 2 lines
let x = Cell.CreateInt 123
let y = Cell.CreateString "testing"
I think I have the necessary type annotations in place and yet F# gives me warnings. E.g:
Warning 2 The instantiation of the generic type 'Cell' is missing and can't be inferred from the arguments or return type of this member. Consider providing a type instantiation when accessing this type, e.g. 'Cell<_>'.
How can I make the warning go away?
As hinted by #ildjarn, Cell is a generic type and the compiler wants to know the type 'T when calling the static member.
// Two ways to fix the compiler warning
let x = Cell<int>.CreateInt 123
let y = StringCell.CreateString "testing"
A way to avoid specifying 'T is to move the create functions into a module.
type Cell<'T> = { slot: 'T }
type IntCell = Cell<int>
type StringCell = Cell<string>
module Cell =
let createInt x : IntCell = { slot = x }
let createString x : StringCell = { slot = x }
let x = Cell.createInt 123
let y = Cell.createString "testing"
However, since you specify the desired type in the function name anyway, the following syntax may be preferred.
type Cell<'T> = { slot: 'T }
with
static member Create (x : 'T) = { slot = x }
type IntCell = Cell<int>
type StringCell = Cell<string>
let x = IntCell.Create 123
let y = StringCell.Create "testing"
// or simply
let z = Cell<float>.Create 1.0
Thanks to #Vandroiy for pointing out the missing type constraint in my Create method and for his answer that shows how the compiler can infer 'T for the generic type Cell when it can be determined by the static method being called.
The compiler cannot determine the generic parameter 'T of the methods CreateInt and CreateFloat because it is unrelated to the methods' return types. In the question, it is valid to write:
Cell<float>.Create 1.0 // useless type annotation to remove warning
However, you can just as well write
Cell<string>.Create 1.0 // Trollolol
To avoid this, you need to make sure the factory can only produce the type it is called on. When declaring a factory on a generic type, use a type annotation to equate the generic argument of its return type with the generic argument of the type it is called on.
In my opinion, the complicated formulation adds to the confusion. You can achieve the desired effect with
type Cell<'T> =
{ slot: 'T }
static member Create (x : 'T) = { slot = x }
let x = Cell.Create 123
let y = Cell.Create "testing"
Note the type annotation for x that equates the factory's input type with the generic parameter of the Cell<> type!
Edited to address the comment:
As is, the types IntCell and StringCell serve no purpose; they are just a less readable form of Cell<int> and Cell<string>. From a comment to this answer, I understand that these types should be exposed instead of Cell. As far as I know, this is not possible if they are defined as in the question, since type abbreviations have at most the accessibility of the type they abbreviate.
This is a reasonable design choice: if a type is generic, it should accept all valid generic type arguments. If IntCell and StringCell add specialized implementation, the usual way is to compose them of the appropriate instantiation of the Cell type and their specialized features. Then, the Cell type is allowed to have a more restricted accessibility than the specialized types.

How can I use Nullable abstract types in F#?

Here is what am I trying to do :
and [<AbstractClass>] Figure() =
let mutable name : string = ""
let mutable color : ColorType = WHITE
abstract member Name : string
member F.Color
with get() = color
and set v = color <- v
abstract member motion : Dashboard -> SPosition -> ColorType -> list<SPosition * CellDashboard * bool>;
override F.ToString() = name
and CellDashboard(addingFigure : Nullable<Figure>) as C =
let mutable attacked : bool = false;
let mutable cleaned : bool = false;
let mutable _CellState : Nullable<Figure> = Nullable<Figure>(addingFigure);
the trouble is :
Error 1 A generic construct requires that the type 'Figure' be non-abstract
why ? And how can I avoid this error ?
The Nullable<T> type can only be used for .NET value types. The error message essentially means that the compiler cannot check whether the constraint holds or not (because the type is abstract).
If you want to represent missing value in F#, it is better to use option<T> instead.
If you're writing code that will be used from C#, then it is better to avoid exposing F#-specific types (like option<T>) and you can mark the type with AllowNullLiteral, which makes it possible to pass null as a value of the type (but null is evil, so this shouldn't be done unless necessary!)

Overriding ToString when creating interface type using object expression

Is there a way to override System.Object's virtual methods, particularly ToString, when creating an interface type using an object expression?
type INamedObject =
abstract Name : string
let makeNamedObject name =
{ new INamedObject with
member x.Name = name
override x.ToString() = x.Name } //would like to do this, but doesn't work
It's possible to supplly multiple types to implement / override in an object expression including concrete types. This allows you to both specify Object and INamedObject in the expression and get the desired effect.
let makeNamedObject name =
{
new System.Object() with
member x.ToString() = name
interface INamedObject with
member x.Name = name }

Resources