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

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.

Related

user generic function to determine the instance type in swift

I have three classes that conforms to same object type (protocol).
class Bicycle: Vehicle {}
class Car : Vehicle {}
class Truck: Vehicle {}
class Bus : Vehicle {}
I have an array that holds objects of the above classes like
let vehicle1 = Car()
let vehicle2 = Bicycle()
let vehicle3 = Truck()
let vehicle4 = Car()
let vehicle5 = Bus()
let listOfVehicles = [vehicle1, vehicle2, vehicle3, vehicle4, vehicle5]
Now I need an array which will tell me the index of the parameter that passed.
func getFirstIndex<T: Vehicle>(for targetObject: T) -> Int {
guard let index = listOfVehicles.firstIndex(where: { $0 is targetObject.Type })
else {
return -1
}
return index
}
If I call getFirstIndex(for: vehicle3), I need to get 2 and
If I call getFirstIndex(for: vehicle4), I need to get 0,
because vehicle4's type and vehicle1's type is same which is Car.
But I am getting compile-error "Type of expression is ambiguous without more context".
Does anyone have any clue.
Just replace targetObject.Type with T

DRY self-replicating type

Is there a succint way to express self-replicating types in F#? — That is, without repeating oneself.
// Manual self-replication
type Foo (par1 : Type1, par2 : Type2, par3 : Type3, par4 : Type4) =
let unique = new UniqueState() // unique for every instance of Foo
member this.SelfReplicate =
new Foo(par1, par2, par3, par4) // repeating myself
let a = new Foo(x, y, z, w)
let b = a.SelfReplicate
Attempt with manually injected self-replicator:
// Semi-automagic self-replication
type Foo' (par1 : Type1, par2 : Type2, par3 : Type3, par4 : Type4, replicate : unit -> Foo') =
let unique = new UniqueState() // unique for every instance of Foo'
member this.SelfReplicate = replicate() // not repeating myself
let rec foo' () = new Foo'(x, y, z, w, foo')
let a = foo'()
let b = a.SelfReplicate
I'm not sure how this can be any more succint without compiler magic. It just seems like there should be a way to capture the current arguments and type without repeating them syntactically.
You could define a type WithUnique<'T> which is a wrapper over a value of type 'T and adds a unique value to this. You may need to think about how you want the equality testing on those types to work - if you use record (as I do below), then two instances with different unique value will not be equal:
let rnd = System.Random()
let uniqueState() = rnd.Next()
type WithUnique<'T> =
{ Value : 'T; Unique : int }
static member Create(v) : WithUnique<'T> =
{ Value = v; Unique = uniqueState() }
member x.Replicate() =
{ Value = x.Value; Unique = uniqueState() }
The value of 'T is just one type, but this can be a tuple (or a record) if you need to wrap multiple things:
let wu1 = WithUnique.Create( (10, "hi") )
let wu2 = wu1.Replicate()
Given the above, wu1=wu2 will be false.

Cast error (Type constraint missmatch)

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

Is it possible to set sub-properties on initialization in F#? [duplicate]

This question already has answers here:
C# object initialization syntax in F#
(3 answers)
Closed 6 years ago.
I recently found (see near the end of this page) that it's possible to set properties on initialization, as in the last line of the following. This is very concise:
type Account() =
let mutable balance = 0.0
member this.Balance
with get() = balance
and set(value) = balance <- value
let account1 = new Account(Balance = 1543.33)
Is there a way to set sub-properties (i.e. properties of properties) in a similarly concise way, without overwriting them completely?
For example, I would like to write something along these lines:
type Person() =
let mutable name = ""
let mutable someProperty = ""
member this.Name
with get() = name
and set(value) = name <- value
member this.SomeProperty
with get() = someProperty
and set(value) = someProperty <- value
type Account() =
let mutable balance = 0.0
let mutable person = new Person(SomeProperty = "created by an account")
member this.Person
with get() = person
and set(value) = person <- value
member this.Balance
with get() = balance
and set(value) = balance <- value
let account1 = new Account(Balance = 1543.33, Person.Name = "John Smith")
However, the last line produces a compile error which doesn't make complete sense: Named arguments must appear after all other arguments.
Please note this is actually for interop with a C# library, so I can't necessarily construct a new object for the property. I wouldn't use mutable properties like this in F# if at all possible.
Yes, you can do this.
Try the following:
let account1 = new Account(Balance = 1543.33, Person = Person(Name = "John Smith"))
Edits following change to posters question:
I'm still not 100% sure if I follow correctly, but a solution could be the following. It doesn't feel particularly functional, but given this is meant to interact with C# classes I don't see that as an issue:
type Account() =
let mutable balance = 0.0
static let mutable person = new Person(SomeProperty = "created by an account")
member this.Person
with get() = person
and set(value) = person <- value
member this.Balance
with get() = balance
and set(value) = balance <- value
static member GetPerson = person
let account2 = new Account(Balance = 1543.33, Person = Person (Name = "John Smith", SomeProperty = Account.GetPerson.SomeProperty))

The F# equivalent of C#'s 'out'

I am rewriting a C# library to F# and I need to translate the following code
bool success;
instance.GetValue(0x10, out success);
what is the equivalent of the out keyword in F#?
Neither wasatz's answer nor Max Malook's is complete. There are three ways of calling methods with out parameters. The second and third ways also work with ref parameters.
For the examples, assume the following type:
open System.Runtime.InteropServices //for OutAttribute
type SomeType() =
member this.GetValue (key, [<Out>] success : bool byref) =
if key = 10 then
success <- true
"Ten"
else
success <- false
null
Assume also that we have an instance of that type:
let o = SomeType()
Option 1
You can let the F# compiler handle the out parameter by tupling it with the return value:
let result1, success1 = o.GetValue 10
let result2, success2 = o.GetValue 11
Running the above lines in F# interactive yields
val success1 : bool = true
val result1 : string = "Ten"
val success2 : bool = false
val result2 : string = null
Option 2
You can use a mutable value, passing its address with the & operator:
let mutable success3 = false
let result3 = o.GetValue (10, &success3)
let mutable success4 = false
let result4 = o.GetValue (11, &success4)
In F# interactive, the result is
val mutable success3 : bool = true
val result3 : string = "Ten"
val mutable success4 : bool = false
val result4 : string = null
This option is best when you are delegating to another method, since you can pass the calling method's out parameter directly to the called method. For example, if you are implementing a wrapper around IDictionary<_,_>, you can code the TryGetValue method as
//...
interface IDictionary<'TKey, 'TValue> with
member this.TryGetValue (key, value) = inner.TryGetValue (key, &value)
//...
Option 3
You can use a reference cell:
let success5 = ref false
let result5 = o.GetValue (10, success5)
let success6 = ref false
let result6 = o.GetValue (11, success6)
The output:
val success5 : bool ref = {contents = true;}
val result5 : string = "Ten"
val success6 : bool ref = {contents = false;}
val result6 : string = null
Warning!
Be careful not to use the ref keyword as you would in C# for an in/out parameter. For example, the following does not yield the desired result:
let success7 = false
let result7 = o.GetValue (10, ref success7)
The output:
val success7 : bool = false
val result7 : string = "Ten"
Why does success7 hold the value false? Because success7 is an immutable variable.
In C#, ref calls attention to the fact that you are passing a reference to a variable as the argument for a ref parameter. It simply serves as insurance that the programmer of the caller is aware that the variable may be modified by the called method. In F# however, ref creates a new reference cell holding a copy of the value of the following expression.
In this case, we are making a reference cell that holds the value copied from the success7 variable, but not assigning that new reference cell to any variable. We then pass that reference cell to the GetValue method, which modifies the content of the reference cell. Because the calling method has no variable pointing to the modified cell, it has no way of reading the new value of the reference cell.
You should probably return an option or a tuple instead. Because F# has pattern matching you really don't need out parameters since there are better ways to return more than one value from a function.
So, something like this would be more idiomatic
let (value, success) = instance.GetValue(0x10)
where instance.GetValue is a
unit -> ('a, bool)
Or you could return an option and do something like
match instance.GetValue(0x10) with
| Some value -> doStuff value
| None -> failwith "Oops!"
You have to use a reference cell.
let success = ref false
instance.GetValue(0x10, success)
// access the value
!success
I think it's also worth mentioning here that the value of the out parameter doesn't have to be initialized.
It is possible to do the following:
let mutable success3 = Unchecked.defaultof<bool>
let result3 = o.GetValue (10, &success3)
This might be usefull in scenarios where you are calling a .NET library function with arrays as output parameters, i.e:
let mutable currFeatures = Unchecked.defaultof<PointF[]>
let mutable status = Unchecked.defaultof<byte[]>
let mutable trackError = Unchecked.defaultof<float32[]>
CvInvoke.CalcOpticalFlowPyrLK(
previousFrame,
nextFrame,
previousPoints,
Size(15,15),
2,
MCvTermCriteria(10, 0.03),
//Out params
&currFeatures,
&status,
&trackError,
//---------
LKFlowFlag.UserInitialFlow)

Resources