Hi Ian,

On Thu, Sep 6, 2018 at 9:45 PM Ian Lance Taylor <i...@golang.org> wrote:

> On Thu, Sep 6, 2018 at 10:29 AM, jimmy frasche <soapboxcic...@gmail.com>
> wrote:
>
> This is clearly a key issue.  I happen to think that contracts are
> fairly clear for the reader: take your type argument and see if the
> contract body works.  I feel that everyone who knows Go will be able
> to do that.  But maybe that's just me.
>

I agree with you on this. But I don't think it's enough. To be type-safe
(from the author perspective), you also need to do the opposite: Take any
*other* type and make sure that it *doesn't* pass the contract. Because
otherwise, you might end up with a program that compiles, but is crashing
or otherwise invalid. And that's what made me turn against contracts,
lately.

I name a couple examples in my blog post (linked upthread), but as it just
came up during a talk at the Zurich Go Meetup: For example, you might have
a contract like `t%1`, to ensure you get an integer type (sorry, that is
ad-hoc the best way I can come up to write that contract). Now, say a
generic function uses that type-parameter for a loop-counter, counting
down: `for i := T(N); i >= 0; i-- { … }`. They check that `int` types pass
their contract and everything goes smoothly. At some point, someone uses
the function with a `uint` argument and you get an endless loop.

Now, this example is constructed. It will probably not occur in practice.
But it illustrates why I believe contracts make it relatively hard to write
type-safe generic code - because the contract does not only has to allow
everything you want to do, it also has to disallow anything you don't.
Expressing that syntactically is much harder.
This gets exacerbated by implied capabilities (though it's not clear yet if
and how much they exist): i.e. the compiler could prove that only integer
types allow `%`, so if you put down that constraint, it also allows `+`,
`*`, conversions to float…
Of course that doesn't *have* to happen - you could just literally only
allow the expressions given in the contract, but then the contract
potentially becomes very verbose, as it has to cover lots of ground. For
example, `a[0]` allows integer-indexing, but it technically only allows to
pass 0. Extending that to arbitrary integers is what's probably going to
happen (and an example of an implicit capability) - but then that code is
less type-safe then it needs to be, as Arrays already provide tight bounds
for constant-indices. You can say that `a[N]` then allows indexing with any
constant <= N (to make those bounds explicit), but at that point I would
criticize that the argument "contracts are just familiar Go syntax" becomes
less and less convincing, because you are introducing all these special
semantical meanings to expressions.

This just walks very roughly through one of these cases - but the more I
talked to people, the more of these we discovered. Personally, I just don't
find contracts a very good format to provide type-constraints - because to
a human, something might be obvious, that isn't to the compiler; causing
things that look like they *should* work not to work or things that don't
look like they work to work (for example, I recently re-discovered that
[]rune allows converting to string too, but has completely different range
and index semantics…).

Sorry for rambling a bit :-/


>
>
> > Scaling back the problem to simply not include operators and fields at
> > all looks like it eliminates so much of the complexity in the
> > implementation and its user interface. Any such limited solution
> > increases the boilerplate of using generics when operators and fields
> > come in to play, certainly, but I think the majority of use-cases for
> > generics are going to be data structures and algorithms more generally
> > expressible without operators anyway (few types have a < operator but
> > any type can have a Less method and without type classes in the
> > haskell/etc. there still isn't a way to handle both without accepting
> > a Less method and requiring a wrapper for types that have a <
> > operator).
> >
> > Is it really *necessary* for generics to support operators and fields?
>
> It's not necessary to support fields but I think it really is
> necessary to support operators.  I claim that, other than type safe
> data structures, the number one generic function that people want to
> write is Min (or Max).  I don't think we can plausible add a generics
> system to Go that doesn't permit writing a Min function.
>
> contract comparable(x T) {
>     x < x
> }
>
> func Min(type T comparable)(a, b T) T {
>     if a < b {
>         return a
>     }
>     return b
> }
>
> Ian
>
> --
> 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.
>

-- 
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