-
Notifications
You must be signed in to change notification settings - Fork 301
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[JS] casting a .NET Dictionary to ICollection JS should not use .push #3914
Comments
It seems like this is not has easy to fix as I though. JS Map doesn't seem to have a I think the issue comes from the fact that Because of that, when calling: open System.Collections.Generic
let dic = Dictionary<int,string>()
dic.Add(2, "b") Then Fable is able to replace the import { addToDict } from "fable-library-js/MapUtil.js";
export const dic = new Map([]);
addToDict(dic, 2, "b"); But when doing the cast to class ExtendedMap extends Map {
constructor() {
super();
}
add(key, value) { // This will replace the call to `addToDict`
// ...
}
} In theory, it means that the new Map class will keep fulfilling the following statement from Fable If people compare the constructor there will be issues, but the existing API should keep working. |
@MangelMaxime I am confused about how Interfaces are used in Fable. |
My theory, is when doing: let iD = (b :> IDictionary<string, int>)
iD.Add("B",2) Fable only see the type of This can be visible when doing: type MyDict<'K,'V when 'K:equality > () =
// ..
interface IDictionary<'K,'V> with
member _.Add(k, v) =
printfn "add IDictionary"
failwith "dwdwdw" // I am on purpose not using `dic.Add(k, v)`
// ..
let iD = (b :> IDictionary<string, int>)
iD.Add("B",2) generates export class MyDict$2 {
// ..
"System.Collections.Generic.IDictionary`2.Add5BDDA1"(k, v) {
toConsole(printf("add IDictionary"));
throw new Error("dwdwdw");
}
// ..
}
export const iD = b;
addToDict(iD, "B", 2); I don't think there is a way to implements to implements your own |
Yes, I was trying to work around the original issue. Do you know why correct code is generated for the interface but not used? |
This is because Fable replacement is the mechanism that's allow Fable to support native API, you cannot say I don't want replacement to happen. To work around the issue, you can use dynamic typing temporary to create a helper function. |
I am looking at how to fix The problem is that let dic = Dictionary<int,string>()
let dicCollection = dic :> ICollection<_>
let kv = KeyValuePair(1,"a")
printfn "Dic collection count: %d" dicCollection.Count
let intArray : int array = [|1;2;3|]
let intCollection = intArray :> ICollection<int>
intCollection.Add(4)
printfn "Int collection count: %d" intCollection.Count
let stringArray : string array = [|"a";"b";"c"|]
let stringCollection = stringArray :> ICollection<string>
stringCollection.Add("d")
printfn "String collection count: %d" stringCollection.Count With the example above, we already have 3 different types at runtime (with different APIs)
@ncave Do you have any ideas? I can implement it with some guidance, I just don't know how we can ensure that |
@MangelMaxime In theory we need different wrappers for each internal type that is supposed to implement ICollection, and return those on casting. |
That was my supposition. So the idea is for: open System.Collections.Generic
let stringArray : string array = [|"a";"b";"c"|]
let stringCollection = stringArray :> ICollection<string>
stringCollection.Add("d") export const stringArray = ["a", "b", "c"];
export const stringCollection = stringArray;
void (stringCollection.push("d")); to becomes something like that? export const stringArray = ["a", "b", "c"];
export const stringCollection = castArrayToIColletion(stringArray);
void (stringCollection.push("d")); I suppose this also means we will need to support the other direction too going from |
@MangelMaxime We could, technically the wrapper can just return the wrapped collection. But I'm sure I'm glossing over some details. |
Thanks for looking into this. |
To clarify, although #3949 fixes the current issue using runtime checks, arguably a better way forward would be to eventually provide proper F# wrappers for all native JS collections, so that all their other interfaces can be easily implemented. Something like this which does it for JS |
@goswinr I'm not sure, each new version of .NET adds quite a few new interfaces. For now I've also added the mappings and tests for |
Casting a .NET
Dictionary
to anICollection
emits.push
for.Add
, but a JS Map has no.push
member.REPL
fable 4.21
The text was updated successfully, but these errors were encountered: