Hi Sandro, Thanks for the comments
On 27 Mar 2010, at 02:44, Sandro Magi wrote: > Looks interesting, but if I'm understanding correctly, this OO type > class pattern is already widely used in Java/C# class libraries [1, > 2]. > The main thrust of the paper is then pointing out the connections of > this pattern to type classes, and how to extend this pattern with > implicit instantiation to encompass Haskell's implicit type class > resolution. It took me a couple of reads to understand these two > points. > I have seen things like IComparer before. From the documentation links that you sent me, I could not see the exact definition. Am I correct that it is defined as: interface IComparer<T> { Bool compare(T x); } class MyClass extends IComparer<MyClass> {... } Like the example that I discuss in page 6 under Limitations and alternatives? I noticed that the example in [3] is indeed an instance of the pattern. In any case it is great to see that the pattern (or similar uses) are in use. It means that the pattern is useful :). If we follow the design patterns Gang-of-four premise, patterns are not invented, they really grow out from experience and proven design. As we mention in the paper, type-class like patterns are quite frequent among Scala programmers. One goal of the paper is to more precisely document this practice and to say why this is useful. I suspect though, that among Java and C# programmers the pattern is much less used than it could be, because without support for implicits it can quickly get quite unwieldy, or if something like IComparer above, you run into some limitations. My guess is that it is only used for very simple use cases similar to Comparison and Equality, > C# suffers from a similar problem as Haskell here, re: numerous > sort/sortBy and equals overloads for > IComparable<T>/delegate/IComparer<T> instances. They've tried to > mitigate this to some extent in recent releases by providing standard > factory methods which perform runtime type tests on the type > parameters > and cache the resulting instances in static fields [3]. Ok; I'll have a closer look. > > They then provide two overloads, one with an explicit > IEqualityComparer<T> param, and one without that uses the implicit > equality comparer obtained via EqualityComparer<T>.Default. This is > obviously just a pattern to overcome the absence of implicits. > Ah, yes. As you say, a bit like Haskell, where the pattern is to have multiple functions like sort/sortBy > However, while reading this paper I remembered that C# 4.0 is getting > named and optional parameters with default values. Assuming default > values could be specified using general static terms, ie. access > static > fields/properties or invoke static methods, we get some of the power > of > implicits. Only one overload would then be needed, with the default > value being the term: EqualityComparer<T>.Default > How does Default work? Does it use reflection to try an get an appropriate comparison operation for the particular type T in use? > Unfortunately, default parameters are currently limited to constants > [4], since they are embedded as attribute metadata. Named params with > default values could generalize explicit type class instances by > making > all instances explicit, and specifying a standard path-dependent > type as > a default. There is quite a bit of hand-waving going on here of > course, > so take with a grain of salt. I think in general default parameters are quite useful to have (Scala will have them too in 2.8). (Not sure if I follow the idea you propose, maybe a concrete example would help?) But they have different use-cases from implicits: Default arguments are very handy for handling constant default values at *definition* site. Using some pseudo-syntax: Int func(List<Int> l)(Monoid<Int> m = sumMonoid) String pretty<T>(List<T> l)(Int breakLine = 80) In this case, by default you would use the sumMonoid, if no arguments are provided to "func". Similarly, in the second case, you could have a pretty printing function that, by default, breaks lines after 80 columns. Now, for the first use case, I don't think default arguments are the most appropriate thing. I think it is obvious that you'd like to generalise the first case to something like (well, depending on what func does :)): T func<T>(List<T> l)(Monoid<T> m = ???) With implicits this is easy: T func<T>(List<T> l)(implicit Monoid<T> m) because, if you wish, the "default" is only picked at *use* site. You could also mimic the second use-case with implicits: implicit val breakLine : Int = 80 String pretty<T>(List<T> l)(implicit Int break) But I think, in this case, default arguments would be more appropriate. Bruno > > Sandro > > [1] IEqualityComparer<T>, > http://msdn.microsoft.com/en-us/library/system.collections.iequalitycomparer.aspx > [2] IComparer<T>, > http://msdn.microsoft.com/en-us/library/system.collections.icomparer.aspx > [3] http://msdn.microsoft.com/en-us/library/ms132123.aspx > [4] http://msdn.microsoft.com/en-us/library/dd264739%28VS.100%29.aspx > > On 26/03/2010 4:33 AM, Bruno Oliveira wrote: >> Hi, >> >> Adriaan Moors, Martin Odersky and I finally managed to submit the >> paper >> that we have been working on. I think this is of interest to the >> discussion, so here is a link to it: >> >> http://ropas.snu.ac.kr/%7Ebruno/papers/TypeClasses.pdf >> >> A quick comment below, but I am still not entirelly freed from the >> paper. >> Still have a couple of hours to try to spot typos :). >> > > _______________________________________________ > bitc-dev mailing list > bitc-dev@coyotos.org > http://www.coyotos.org/mailman/listinfo/bitc-dev _______________________________________________ bitc-dev mailing list bitc-dev@coyotos.org http://www.coyotos.org/mailman/listinfo/bitc-dev