Mikioo / sharpkit

Automatically exported from code.google.com/p/sharpkit
0 stars 0 forks source link

Support Dictionary directly based on object's GetHashCode #289

Open GoogleCodeExporter opened 8 years ago

GoogleCodeExporter commented 8 years ago
If you provide a GetHashCode override on an object then that should be used 
with any dictionaries.

The below example seems to perform a reference based hashing.

    [JsType(JsMode.Clr, Filename = "res/Example.js")]
    public class Pair
    {
        public readonly int X;
        public readonly int Y;

        public Pair(int x, int y)
        {
            X = x;
            Y = y;
        }

        public override int GetHashCode()
        {
            var hc = X;
            return ((hc << 5 | hc >> 27) + Y);
        }
    }

    [JsType(JsMode.Global, Filename = "res/Default.js")]
    public class DefaultClient
    {
        private static void DefaultClient_Load()
        {
            new jQuery(HtmlContext.document.body).append("Ready<br/>");
        }

        private static void btnTest_click(DOMEvent e)
        {
            var a = new Pair(x: 1, y: 2);
            var b = new Pair(x: 1, y: 2);
            var c = new Pair(x: 4, y: 2);

            var dic = new Dictionary<Pair, string>();

            dic[a] = "one";
            dic[b] = "two";
            dic[c] = "three";

            new jQuery(HtmlContext.document.body).append(string.Format("Hashcodes a={0}, b={1}, c={2}<br/>",
                                                                       a.GetHashCode(), b.GetHashCode(), c.GetHashCode()));

            new jQuery(HtmlContext.document.body).append("dic[a]: " + dic[a] + "<br/>");
            new jQuery(HtmlContext.document.body).append("dic[b]: " + dic[b] + "<br/>");
            new jQuery(HtmlContext.document.body).append("dic[c]: " + dic[c] + "<br/>");

        }
    }

This results in

Hashcodes a=34, b=34, c=130
dic[a]: one
dic[b]: two
dic[c]: three

where it should give

Hashcodes a=34, b=34, c=130
dic[a]: two
dic[b]: two
dic[c]: three

The hashing could probe for the predefined GetHashCode method.

/*Generated by SharpKit 5 v5.01.0000*/

Original issue reported on code.google.com by co...@gravill.com on 19 Apr 2013 at 3:15

GoogleCodeExporter commented 8 years ago
As a follow-up I tried using IEqualityComparer to pass in a custom comparer. 
There seem to be two problems. First issue is that the generated javascript 
doesn't appear to get a $1 suffix i.e. just:

IEqualityComparer

Then when it looks for IEqualityComparer$1, it's not found.

The bigger issue is that the generated dictionary, calls against the Comparer 
with $$T rather than the type the dictionary has been instantiated with:

return this.Comparer.GetHashCode$$T(key);

Am I missing something about how to use this functionality?

Original comment by co...@gravill.com on 19 Apr 2013 at 4:33

GoogleCodeExporter commented 8 years ago
Currently, Dictionary is implemented using JavaScript standard Object, with a 
generated string key as the key using the global $GetHashKey() function. This 
means that GetHashCode is currently ignored. It is possible to add 
functionality to allow objects to implement their own GetHashKey command and 
allow you to control this behavior.
Do not confuse HashKey with HashCode, since HashKey should be a unique string, 
where HashCode is a number and doesn't have to be unique.

Regarding the second issue, can you add a code sample (maybe in a new issue)?

Thanks

Original comment by DanelK...@gmail.com on 21 Apr 2013 at 10:44

GoogleCodeExporter commented 8 years ago
I over-simplified my example and missed the equals for bucket chaining

    [JsType(JsMode.Clr, Filename = "res/Example.js")]
    public class Pair
    {
        public readonly int X;
        public readonly int Y;

        public Pair(int x, int y)
        {
            X = x;
            Y = y;
        }

        public override int GetHashCode()
        {
            var hc = X;
            return ((hc << 5 | hc >> 27) + Y);
        }

        public override bool Equals(object obj)
        {
            var other = (Pair) obj;
            return X == other.X && Y == other.Y;
        }
    }

If you use that code in an equivalent console application you get:

    public class Pair
    {
        public readonly int X;
        public readonly int Y;

        public Pair(int x, int y)
        {
            X = x;
            Y = y;
        }

        public override int GetHashCode()
        {
            var hc = X;
            return ((hc << 5 | hc >> 27) + Y);
        }

        public override bool Equals(object obj)
        {
            var other = (Pair)obj;
            return X == other.X && Y == other.Y;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var a = new Pair(x: 1, y: 2);
            var b = new Pair(x: 1, y: 2);
            var c = new Pair(x: 4, y: 2);

            var dic = new Dictionary<Pair, string>();

            dic[a] = "one";
            dic[b] = "two";
            dic[c] = "three";

            Console.WriteLine(string.Format("Hashcodes a={0}, b={1}, c={2}<br/>",
                                                                       a.GetHashCode(), b.GetHashCode(), c.GetHashCode()));

            Console.WriteLine("dic[a]: " + dic[a] + "<br/>");
            Console.WriteLine("dic[b]: " + dic[b] + "<br/>");
            Console.WriteLine("dic[c]: " + dic[c] + "<br/>");
        }
    }

then gives:

Hashcodes a=34, b=34, c=130<br/>
dic[a]: two<br/>
dic[b]: two<br/>
dic[c]: three<br/>

It would nice to support such types directly with the existing .net mechanism 
but I'm happy to look at the GetHashKey. Are there any examples you can point 
me towards for that as I haven't been able to find anything useful yet only -

http://sharpkit.net/help/SharpKit.JsClr/SharpKit.JavaScript.Compilation/JsCompil
er/GetHashKey(Object).htm

I'll add an issue for my problem with IEqualityComparer

Original comment by co...@gravill.com on 22 Apr 2013 at 1:44