One other advantage of Eric's proposal that has just occurred to me is that 
folks who dislike operator overloading wouldn't have to use it at all - 
they could just use the named methods.

The only people who would need to use it would be those writing unified 
generic functions/methods who would probably be a minority of users in any 
case.

Of course, all users would need some familiarity with the concept as they 
might need to read code written by others which did use it.

Alan

On Tuesday, October 16, 2018 at 11:33:26 AM UTC+1, alanfo wrote:
>
> Well, whatever you may think of it, there's no doubt that a lot of the 
> problems we currently have with generic constraints would go away if 
> operator overloading were introduced into Go 2.
>
> Personally, I wouldn't be dismayed if this were to happen. A lot of my 
> stuff is mathematical in nature and this is an area where operator 
> overloading works best - and indeed is expected - by programmers working in 
> these disciplines.
>
> However, I think it's important to learn the lessons of the past and not 
> follow languages such as C++ or Scala where you can overload virtually 
> anything or even make up your own operators which can result in confusing 
> or even write-only code.
>
> It is far better, in my view, just to permit the overloading of a limited 
> subset of operators and for their signature, priority etc. to mirror those 
> of the built-in ones.
>
> In particular, I agree with Ian that there would be very little value in 
> overloading the logical operators (&&, || and !) and that this should be 
> disallowed.
>
> I would also disallow overloading of the =, :=, <-, ..., [], {}, () and 
> yes - equality operators - as well because I believe to do otherwise would 
> be very confusing. 
>
> The equality operators (== and !=) have a well defined meaning in Go 1 
> which spans both built-in and user defined types and, to maintain backwards 
> compatibility, I don't think this should be changed. When you want to use 
> these operators purely for ordering purposes, they can always be reproduced 
> by a combination of the other ordering operators as I said in another 
> recent thread.
>
> If you can't overload == and != then 'comparable' (or whatever you want to 
> call it) would need to be a built-in interface.
>
> Another possibility would be to introduce two new ordering operators, 
> perhaps >< (for ==) and <> (for !=), which *could* be overloaded though 
> the first of these would take some getting used to!
>
> As for Eric's proposal - using an 'implements' keyword - I like it for the 
> following reasons:
>
> 1. It avoids the need to make up a long list of names for the operators 
> which folks either have to remember or look up in the spec.
>
> 2. It makes it easier to retrofit operator overloading to existing types 
> for which suitable methods have already been defined.
>
> 3. As 'implements' would only be used in contexts which don't exist at 
> present, it needn't be a 'full' keyword and would therefore be backwards 
> compatible.
>
> One area that hasn't been addressed so far is conversions. To convert to 
> say, int64, I'd suggest 'implements int64()' and to convert from int64 
> perhaps 'implements T(int64)' where T is the method's receiver type. TBH, I 
> don't particularly like the idea of user-defined conversions at all but 
> they're probably inevitable if you want to have unified generic constraints 
> and at least they'd always be explicit.
>
> Subject to all this, I think it might well be possible to get rid of 
> contracts and just use interfaces for generic constraints.
>
> Incidentally, I'm not a fan of wrapping types so that they can support the 
> built-in operators. Although this is easy enough for scalar types, when you 
> have slices, maps etc. of such types it's a different kettle of fish as 
> wrapping/unwrapping requires a lot more code.
>
> Alan
>
> On Tuesday, October 16, 2018 at 3:24:50 AM UTC+1, Eric Raymond wrote:
>>
>> Recent discussion of possible generics designs has forced me to a 
>> conclusion I'm not happy with, because it requires a feature-cluster that I 
>> thought I was glad  to be leaving behind in Python.  That is this:
>>
>> The simplest and most effective way to solve the generics problem is to 
>> embrace operator overloading and the kind of magic method designations that 
>> go with it.
>>
>> I'm still not a big fan of operator overloading as a surface feature of 
>> the language.  I think the arguments that it encourages overly clever 
>> one-liners are sound. My argument is not in favor of that. Rather, after 
>> reviewing all the design strawmen I have seen, I see no way to declare 
>> contracts for generics that is (a) as simple, and (this is a really 
>> important point brought out in a recent post) maintains unification with 
>> primitive types.
>>
>> In fact, more and more as I look at the proposals that have failed to 
>> catch fire I see them as clever but doomed attempts to evade operator 
>> overloading because most people did not want that camel's nose in the 
>> tent.  As a matter of cold fact I don't either, but I am forced to the 
>> conclusion that in the portion of design space we can easily reach from Go 
>> 1, operator overloading and contracts are more joined at the hip than 
>> anyone - including me - has been willing to face up to now.  I therefore 
>> propose that we embrace the suck and limit the complexity load on the rest 
>> of the language as much as possible. 
>>
>> Here's a stupid-simple system for describing generic contracts with just 
>> one new keyword: "implements", having  a single argument which is a token 
>> that may occur as an operator in expressions.   Here is what it would look 
>> like:
>>
>> type Sortable interface { 
>>         implements <
>> }
>>
>> type MySortable struct {
>>         name string
>>         sortkey id
>> }
>>
>> func (r MySortable) LessThan (s MySortable) bool implements < {
>>         return r.sortkey < s.sortkey
>> }
>>
>> Because MySortable has a method that "imnplements <", it satisfies the 
>> Sortable interface.
>>
>> Each eligible operator has an implied generic signature.  For example is 
>> we use s and t as generic argument placeholders, that of < is 
>> s.(T).func(t T) bool.   That of + would be s.(T).func(t T) T.  It would 
>> be a compile-time error for an "implements"  method not to match the 
>> signature template of its operator as it applies to basic types.
>>
>> The general insight this leverages is that every primitive-type operator 
>> implies a description of a contract *without adding any additional 
>> complexity to the language*.
>>
>> Notice that we have evaded the methods themselves needing to have magic 
>> names.  The only declaration of contract and overloading is the 
>> "implements" clause.
>>
>> This passes Ian's smoke test. That is, it is easy to see how to implement 
>> min() and max() on generics under this system.
>>
>> By being able to define relationals  and + or * as a composition operator 
>> for algebras on user-defined types I think we solve a huge part of the 
>> generic contracts problem.  At the cost of adding only one new construct to 
>> the language, and one that is easy to describe and understand.  (Because 
>> the heavy lifting is done by well-established expectations about the 
>> behavior of primitive types.)
>>
>> Perhaps I risk overreaching, for I am relatively new to the language, but 
>> it seems to me that the simplicity and orthogonality of this proposal are 
>> very much in the spirit of Go. Enough to that the side effect of 
>> overloading as a surface syntactic feature is - if grudgingly - forgivable.
>>
>> Can it even possibly be simpler than this? What, if anything, am I 
>> missing?
>>
>>
>>  
>>
>>
>>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to