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

Reply via email to