Cast error (Type constraint missmatch) - f#

I have problem with casting
type IConfig = interface end
type test(num: string) =
interface IConfig
member this.num = num
type init(context:string) =
interface IConfig
member this.context = context
let dict:Dictionary<string, IConfig> = new Dictionary<string, IConfig>()
dict.Add("x1", new test() { num = "1" });
dict.Add("x2", new init() { context = "1" });
for item in dict do
if(item.Key = "x1") then
let x = (item.Value :> init).context
//Here I have an error: Type constraint missmach. The type IConfig is not compatibile with type InitConfig
I've done the same with C#, and it works.
Please, help.

I had to make some changes to your code to get it working, but I think you're looking for the :?> operator instead of the :> operator. The :> only does upcasting (i.e. init -> IConfig), whereas :?> does downcasting (i.e. IConfig -> init), which is what you're trying to do here.
Here's the code I used to get it working:
open System.Collections.Generic
type IConfig = interface end
type test(num: string) =
interface IConfig
member this.num = num
type init(context:string) =
interface IConfig
member this.context = context
let dict:Dictionary<string, IConfig> = new Dictionary<string, IConfig>()
dict.Add("x1", new test(num = "1"))
dict.Add("x2", new init(context = "1"))
for item in dict do
if(item.Key = "x2") then
let x = (item.Value :?> init).context
printfn "%A" x

Related

How can I create a CustomEvent with detail object in Fable?

In Javascript it is possible to create a CustomEvent and include a second argument containing detail data to pass when the event is dispatched. For example:
let evt = new CustomEvent("hello", {
detail: { name: "John" }
});
elem.dispatchEvent(evt);
With Fable I can create a CustomEvent without the detail data as follows:
let evt = CustomEvent.Create "hello"
elem.dispatchEvent evt
The definition in Browser.Events is as follows:
type [<AllowNullLiteral>] CustomEventType =
[<Emit("new $0($1...)")>] abstract Create : typeArg: string * ?eventInitDict: CustomEventInit -> CustomEvent
[<Emit("new $0($1...)")>] abstract Create : typeArg: string * ?eventInitDict: CustomEventInit<'T> -> CustomEvent<'T>
But I can't work out how to create a CustomEventInit as I think this is an interface.
let details:CustomEventInit = { detail = {name = "John"}} //ERROR: This type is not a record type
let evt = CustomEvent.Create ("hello", details)
elem.dispatchEvent evt
Any help on how to achieve this would be greatly appreciated!
CustomEventInit is a class type, so you can instantiate it using an object expression:
let details =
let mutable bubbles = true
let mutable cancelable = true
let mutable composed = true
let mutable detail : obj = "John"
{
new CustomEventInit with
member _.bubbles
with set(value) = bubbles <- value
and get() = bubbles
member _.cancelable
with set(value) = cancelable <- value
and get() = cancelable
member _.composed
with set(value) = bubbles <- value
and get() = bubbles
member _.detail
with set(value) = detail <- value
and get() = detail
}
Or you could create a named subclass if you prefer.

F# Error compiling

I have the following F# Code that is causing a compile error:
persistence.fs(32,21): error FS0072: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved.
The error is at the line "serializer.write...."
Any help would be appreciated.
namespace persisitence
open System.Collections.Generic
open System
open System.IO
type LocalData<'T> =
struct
val mutable elements_ : 'T list
val mutable lock_ : obj
new(e: 'T list) = { elements_ = e ; lock_ = new obj() }
end
type BinaryPersistenceOut<'T, ^W when ^W: (member write : ('T * BinaryWriter) -> unit)>(fn: string, serializer: ^W) as this =
let writer_ = new BinaryWriter(File.Open(fn, FileMode.Append))
let mutable localdata_ = new LocalData<'T>([])
let serializer_ = serializer
let NUM_SECS_IN_MIN = 60
let NUM_MSECS_IN_SEC = 1000
let NUM_MIN_BETWEEN_COMMITS = 2
let TIME_TO_WAIT = 15
let closed_ = false
let freq_ = NUM_MIN_BETWEEN_COMMITS * NUM_SECS_IN_MIN * NUM_MSECS_IN_SEC
let path_ = fn
let timer_ = new System.Timers.Timer((float) (NUM_MIN_BETWEEN_COMMITS * NUM_MSECS_IN_SEC) )
let writetofile =
fun (arg: Timers.ElapsedEventArgs ) ->
lock localdata_.lock_ ( fun () ->
if closed_ = false then
for elem in localdata_.elements_ do
serializer.write(elem, writer_)
)
do
timer_.Elapsed.Add(writetofile)
Although it'd be nice if you could invoke the write function like serializer.write(elem, writer_), you can't. You have to invoke it like this instead:
(^W: (member write : ('T * BinaryWriter) -> unit) (serializer, (elem, writer_)))
Full code block:
type BinaryPersistenceOut<'T, ^W when ^W: (member write : ('T * BinaryWriter) -> unit)> (fn: string, serializer: ^W) as this =
let writer_ = new BinaryWriter(File.Open(fn, FileMode.Append))
let mutable localdata_ = new LocalData<'T>([])
let serializer_ = serializer
let NUM_SECS_IN_MIN = 60
let NUM_MSECS_IN_SEC = 1000
let NUM_MIN_BETWEEN_COMMITS = 2
let TIME_TO_WAIT = 15
let closed_ = false
let freq_ = NUM_MIN_BETWEEN_COMMITS * NUM_SECS_IN_MIN * NUM_MSECS_IN_SEC
let path_ = fn
let timer_ = new System.Timers.Timer((float) (NUM_MIN_BETWEEN_COMMITS * NUM_MSECS_IN_SEC) )
let writetofile =
fun (arg: Timers.ElapsedEventArgs ) ->
lock localdata_.lock_ ( fun () ->
if closed_ = false then
for elem in localdata_.elements_ do
(^W: (member write : ('T * BinaryWriter) -> unit) (serializer, (elem, writer_)))
)
do
timer_.Elapsed.Add(writetofile)
Caveat: this compiles, but I have no idea if it does what you want it to do.

Creating an F# record or union type (not instance thereof) at runtime

What is the best way to create an instance of System.Type representing an F# record or union at runtime? That is, I am looking for an equivalent of FSharpType.MakeTupleType for records and unions.
Just to clarify, I am not interested in creating an instance (i.e. FSharpValue.MakeRecord or FSharpValue.MakeUnion).
I am not aware of an equivalent to FSharpType.MakeTupleType for records and unions in the F# library.
One way to create record or union type like structures at runtime is to use Reflection.Emit. A record type is analogous to a sealed class and a union type is an abstract base class with sealed classes for each case.
For example the following function generates a minimal F# record type:
open System
open System.Reflection
open System.Reflection.Emit
let MakeRecord(typeName:string, fields:(string * Type)[]) =
let name = "GeneratedAssembly"
let domain = AppDomain.CurrentDomain
let assembly = domain.DefineDynamicAssembly(AssemblyName(name), AssemblyBuilderAccess.RunAndSave)
let name = "GeneratedModule"
let dm = assembly.DefineDynamicModule(name, name+".dll")
let attributes = TypeAttributes.Public ||| TypeAttributes.Class ||| TypeAttributes.Sealed
let typeBuilder = dm.DefineType(typeName, attributes)
let con = typeof<CompilationMappingAttribute>.GetConstructor([|typeof<SourceConstructFlags>|])
let customBuilder = CustomAttributeBuilder(con, [|SourceConstructFlags.RecordType|])
typeBuilder.SetCustomAttribute(customBuilder)
let makeField name t =
let attributes = FieldAttributes.Assembly
let fieldBuilder = typeBuilder.DefineField(name+"#", t, attributes)
let attributes = PropertyAttributes.None
let propertyBuilder = typeBuilder.DefineProperty(name, attributes, t, [||])
let customBuilder = CustomAttributeBuilder(con, [|SourceConstructFlags.Field|])
propertyBuilder.SetCustomAttribute(customBuilder)
let attributes = MethodAttributes.Public ||| MethodAttributes.HideBySig ||| MethodAttributes.SpecialName
let methodBuilder = typeBuilder.DefineMethod("get_"+name, attributes, t, [||])
let il = methodBuilder.GetILGenerator()
il.Emit(OpCodes.Ldarg_0)
il.Emit(OpCodes.Ldfld, fieldBuilder)
il.Emit(OpCodes.Ret)
propertyBuilder.SetGetMethod(methodBuilder)
fieldBuilder
let types = fields |> Array.map snd
let cb = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, types)
let il = cb.GetILGenerator()
il.Emit(OpCodes.Ldarg_0)
il.Emit(OpCodes.Call, typeof<obj>.GetConstructor(Type.EmptyTypes))
fields |> Array.iteri (fun i (name, t) ->
let paramName = name.Substring(0,1).ToLower()+name.Substring(1)
let param = cb.DefineParameter(i+1, ParameterAttributes.In, paramName)
let fieldBuilder = makeField name t
il.Emit(OpCodes.Ldarg_0)
il.Emit(OpCodes.Ldarg, param.Position)
il.Emit(OpCodes.Stfld, fieldBuilder)
)
il.Emit(OpCodes.Ret)
let t = typeBuilder.CreateType()
assembly.Save("GeneratedModule.dll")
t
let r = MakeRecord("MyRecord", [|"Alpha",typeof<int>;"Beta",typeof<string>|])
Note the expected interfaces for a Record type may also need to be generated, i.e. implementations of IEquatable, IStructuralEquatable, IComparable and IStructuralComparable are missing.
Update
Extension methods MakeTupleType and MakeUnionType based on the code sample above are now available in the open source Fil (F# to IL Compiler) project (alpha).

Extension methods for F# tuples

Is it possible to write extension methods for F# tuples? For example, to add instance methods .Item1 and .Item2 (like System.Tuple) which are equivalent to calling fst and snd for 2-tuples?
The System.Tuple<'T1, 'T2> type that internally represents (2-element) tuples in F# actually already has properties Item1 and Item2, but these are hidden by the F# compiler. An obvious method to add extension members to a tuple does not do the trick, so I would not expect this to work (but there may be some workaround I'm not aware of).
Generally, I think pattern matching is preferable to members such as Item1, Item2 etc. (and C# 3.0 programmers often ask for pattern matching support when working with tuples :-)).
The reason is that pattern matching forces you to name things. Compare these two code snippets:
let (width, height) = tuple
width * height
and a version using properties:
tuple.Item1 * tuple.Item2
The second is a bit shorter, but definitely less readable.
Not perfect but I'm using this. (I borrowed original code from http://www.fssnip.net/6V and added small modification.)
[<AutoOpen>]
module TupleExtensions =
type System.Tuple with
static member Item1(t) = let (x,_) = t in x
static member Item1(t) = let (x,_,_) = t in x
static member Item1(t) = let (x,_,_,_) = t in x
static member Item1(t) = let (x,_,_,_,_) = t in x
static member Item1(t) = let (x,_,_,_,_,_) = t in x
static member Item1(t) = let (x,_,_,_,_,_,_) = t in x
static member Item2(t) = let (_,x) = t in x
static member Item2(t) = let (_,x,_) = t in x
static member Item2(t) = let (_,x,_,_) = t in x
static member Item2(t) = let (_,x,_,_,_) = t in x
static member Item2(t) = let (_,x,_,_,_,_) = t in x
static member Item2(t) = let (_,x,_,_,_,_,_) = t in x
static member Item3(t) = let (_,_,x) = t in x
static member Item3(t) = let (_,_,x,_) = t in x
static member Item3(t) = let (_,_,x,_,_) = t in x
static member Item3(t) = let (_,_,x,_,_,_) = t in x
static member Item3(t) = let (_,_,x,_,_,_,_) = t in x
static member Item4(t) = let (_,_,_,x) = t in x
static member Item4(t) = let (_,_,_,x,_) = t in x
static member Item4(t) = let (_,_,_,x,_,_) = t in x
static member Item4(t) = let (_,_,_,x,_,_,_) = t in x
static member Item5(t) = let (_,_,_,_,x) = t in x
static member Item5(t) = let (_,_,_,_,x,_) = t in x
static member Item5(t) = let (_,_,_,_,x,_,_) = t in x
static member Item6(t) = let (_,_,_,_,_,x) = t in x
static member Item6(t) = let (_,_,_,_,_,x,_) = t in x
static member Item7(t) = let (_,_,_,_,_,_,x) = t in x
How to use it:
let t = (1, 2, 3)
let item1 = Tuple.Item1(t)
Tuple.Item1 defined here has advantage over fst: It is polymorphic for number of items. Once we write function which uses n tuple using these extension methods, we can extend it for n+1 tuple without modifying function body. Instead we have to modify argument type declaration. It is more effortless.
I think, what you're asking is not very functional way. You can make your own type with instance methods, but at the same time you are losing many aspects of functional programming, e.g. pattern matching.
Other than that, a DU seems to be the way to go:
type MyTuple<'T, 'U> =
| MyTuple of 'T * 'U
with
member this.MyItem1 = match this with | MyTuple(x,y) -> x
member this.MyItem2 = match this with | MyTuple(x,y) -> y
let x = MyTuple(42, "foo")
let y1 = x.MyItem1 // 42
let y2 = x.MyItem2 // "foo"
As #Tomas Petricek noted, you can't name the properties Item1 and Item2 since they already exist in System.Tuple<'T1, 'T2>. Attempting to do that will cause an error:
error FS2014: A problem occurred writing the binary [filename]: Error in pass2 for type [...], error: Error in pass2 for type MyTuple`2, error: duplicate entry 'Item1' in property table
You could also use the fst and snd functions to get the values you want (and obviously write your own for third, fourth, etc. if you really wanted to).
The workaround is to use C# style extension definitions.
This will work just fine:
open System.Runtime.CompilerServices
[<Extension>]
type TupleExtensions () =
[<Extension>] static member First((a,b)) = a
[<Extension>] static member First((a,b,c)) = a
let x = (1,2).First()
let y = (1,2,3).First()
But I agree in that it's not a good idea to access the elements of a tuple through methods, pattern matching is the best way.

f# overwrite array access operator .[]

in F#, I want to make a type of indexed array, so I can access the element by either .[i] or .[index_names] and by slice notation with index .. Is it possible to overwrite .[] like this? thanks.
define overloaded indexer in your type:
type MyIndexedArray<'T>() =
member this.Item(i : int) : 'T = Unchecked.defaultof<_>
member this.Item(name : string) : 'T = Unchecked.defaultof<_>
member this.GetSlice(a : int option, b : int option) : 'T = Unchecked.defaultof<_>
let arr = new MyIndexedArray<int>()
let a = arr.[1]
let b = arr.["name"]
let c = arr.[1..2]
let d = arr.[1..]
let e = arr.[..3]
let f = arr.[*]

Resources