F# cast invalid - f#

I have a method :
member this.Get<'IAMSOMETHING when 'IAMSOMETHING : not struct>([<ParamArray>] parameters:obj[]) : 'IAMSOMETHING=
if typeof<'IAMSOMETHING> = typeof<IProvideAbilities> then
this._issues :?> 'IAMSOMETHING
else
raise(System.NotImplementedException())
this.Issues is a member. I have an error:
The member 'Get<'IAMSOMETHING when 'IAMSOMETHING : not struct and
'IAMSOMETHING :> Issues> : obj [] -> 'IAMSOMETHING when 'IAMSOMETHING
: not struct and 'IAMSOMETHING :> Issues' does not have the correct
type to override the corresponding abstract method. The required
signature is 'Get<'IAMSOMETHING when 'IAMSOMETHING : not struct> : obj
[] -> 'IAMSOMETHING when 'IAMSOMETHING : not struct'.
How can I cast this.Issues to IAMSOMETHING ?
Thanks a lot.

I think you need to declare your "parameters" parameter as obj[] instead of obj. The attribute must be on the last parameter and must be an array.
See documentation MSDN

Related

Extend F# Arrays with lookup for bigint

I would like to extend F# Arrays such that I can use arrays without converting to the finite int. Instead I want to work with bigint directly.
I was able to add a second length method to the array type as follows:
type 'T ``[]`` with
member this.LengthI: bigint =
bigint this.Length
member this.Item(index: bigint): 'T =
this.[int index]
However the Item method cannot be called with the .[ ] syntax.
Any ideas how this could be achieved? I this possible at all?
I strongly suspect this isn't possible for native arrays. You can verify yourself that you can overload indexed access just fine for other collections.
If you compile the following code:
let myArray = [| "a" |]
let myList = [ "a" ]
let arrayElement = myArray.[11111]
let listElement = myList.[22222]
and inspect the resulting IL, you'll see that while accessing the list element compiles to a regular virtual call, there is a special CIL instruction for accessing a native array element, ldelem.
//000004: let arrayElement = myArray.[11111]
IL_002c: call string[] Fuduoqv1565::get_myArray()
IL_0031: ldc.i4 0x2b67
IL_0036: ldelem [mscorlib]System.String
IL_003b: stsfld string '<StartupCode$51dff40d-e00b-40e4-b9cc-15309089d437>'.$Fuduoqv1565::arrayElement#4
.line 5,5 : 1,33 ''
//000005: let listElement = myList.[22222]
IL_0040: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<string> Fuduoqv1565::get_myList()
IL_0045: ldc.i4 0x56ce
IL_004a: callvirt instance !0 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<string>::get_Item(int32)
IL_004f: stsfld string '<StartupCode$51dff40d-e00b-40e4-b9cc-15309089d437>'.$Fuduoqv1565::listElement#5
IL_0054: ret
I would guess that the same compiler logic that special-case array access to that single instruction also bypass any overload resolution involving extension methods and the like.
One way to circumvent this is to wrap the array in a custom type, where overloaded indexers will work as you expect. Making the wrapper type a struct should reduce the performance loss in most cases:
type [<Struct>] BigArray<'T>(array : 'T[]) =
member this.LengthI: bigint =
bigint array.Length
member this.Item
with get(index : int) = array.[index]
and set (index : int) value = array.[index] <- value
member this.Item
with get(index : bigint) = array.[int index]
and set (index : bigint) value = array.[int index] <- value
let bigArray = BigArray myArray
let bigArrayElement = bigArray.[0]
let bigArrayElement2 = bigArray.[bigint 0]
Another one is to upcast the array to the base System.Array class, on which you can then define the same overloaded operator. This removes the need to create a wrapper type and duplicate all members of 'T[], as you can just upcast/downcast the same array object as necessary. However, since the base class is untyped, you will lose type safety and have to box/unbox the elements when using the indexed access, which is quite ugly:
type System.Array with
member this.Item
with get (index : int) = (this :?> 'T[]).[index]
and set (index : int) (value : 'T) = (this :?> 'T[]).[index] <- value
member this.Item
with get(index : bigint) : 'T = (this :?> 'T[]).[int index]
and set(index : bigint) (value : 'T) = (this :?> 'T[]).[int index] <- value
let untypedArray = myArray :> System.Array
let untypedArrayElement = box untypedArray.[0] :?> string
let untypedArrayElement2 = box untypedArray.[bigint 0] :?> string

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.

Is it possible to use explicit member constraints on static fields?

Using F#, I had the following (simplified), which works fine:
type MyInt =
struct
val Value: int
new v = { Value = v }
end
static member inline name() = "my_int" // relevant line
let inline getName (tp: ^a): string = (^a: (static member name : unit -> string) ())
It seems to me that the statically resolved member signature from the explicit member constraint requires a function. I was wondering if it can also be used with a field instead. I tried a few things:
The following will compile, but won't work and will fail with the error
error FS0001: The type 'MyInt' does not support the operator 'get_name'
type MyInt =
//...
static member inline name = "my_int"
let inline getName (tp: ^a): string = (^a: (static member name : string) ())
Removing the () to prevent it from trying to call the gettor is a syntax error. If I change it to actually implement the gettor, it works (but that's essentially the same as the original code).
type MyInt =
// ...
static member inline name with get() = "my_int"
let inline getName (tp: ^a): string = (^a: (static member name : string) ())
Is there a way to get, using explicit member constraints or similar means, the compiler to find the static field? Or is this simply a limitation of the syntax of constraints?
Update:
Surprisingly, it does work with instance fields, or as in this case, struct fields: using (^a: (member Value: 'b) ()), which will call the member Value.

f#: Signature file causing Intellisense to complain?

Given the following code...
type IMyInterface =
abstract BoolA : bool
abstract BoolB : bool
let myFn _boolVal (_i: IMyInterface) = if _boolVal then _i.BoolA else _i.BoolB
let myFnTrue = myFn true
let myFnFalse = myFn false
... Intellisense complains, and the compiler fails, if I create a signature file with this in it:
type IMyInterface =
abstract BoolA : bool
abstract BoolB : bool
val myFnTrue : (IMyInterface -> bool)
val myFnFalse : (IMyInterface -> bool)
The error is Error 10 Module 'MyModule' contains val myFnTrue : ('_a -> bool) when '_a :> MyModule.IMyInterface but its signature specifies val myFnTrue : (MyModule.IMyInterface -> bool) The types differ. (A similar error is reported for myFnFalse.)
I feel like an idiot, not being able to figure this out. What am I doing wrong? (Bracing for the "duh" answer...)
In your signature file, myFnTrue and myFnFalse have the signature IMyInterface -> bool but in your implementation 'a -> bool with the constraint 'a :> IMyInterface (due to automatic generalization), that is, the implementation is generic and the signature is not.
The simplest solution is changing your implementation to this:
let myFnTrue i = myFn true i
let myFnFalse i = myFn false i

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!)

Resources