On Fri, Jan 1, 2021 at 2:16 PM Axel Wagner <axel.wagner...@googlemail.com> wrote:
> Hi, > > On Fri, Jan 1, 2021 at 1:41 PM Markus Heukelom <markus.heuke...@gain.pro> > wrote: > >> One thing that comes to mind that is not supported by the current >> proposal is the ability to express that T must be (any) struct. >> > […] >> > Another example is where you write a library that creates an RPC service >> from any function that you provide: >> > > Personally, given that in both of these cases you still need to use > `reflect` and there's still a lot of type-errors that can happen, I feel > the wins here are relatively minor. There definitely are some and if they > could be added more or less "for free", I'd definitely support that. But I > don't see, personally, how that could be done. > > As an example, a similar case is expressing that an argument must be a > pointer - for example, for json.Unmarshal. It has a similar level of > benefit (json.Unmarshal also still needs to use reflect to actually set > fields or values) - but in that case, there is already a "free" way to > achieve it with the design (that is, use `func Unmarshal[type T any](b > []byte, p *T) error`). > > >> On the other hand, I don't see a lot of cases myself where I would want >> to call some method on T in a generic function, mainly because there's >> already interfaces and helper function for this in Go if you need it. For >> example, you could say that a generic priority queue must call a method >> Priority() on T, but that could be done in an equally type-safe way by >> asking for a helper function to be provided with T (ie. func (T) int) with >> the container. There's the graph example in the generics proposal but I >> think that that can have a likewise type-safe solution that doesn't need >> the ability to call a method on T. >> > > You could argue, that you don't actually *need* methods or interfaces at > all. Instead of passing an `io.Reader`, you could pass a `func(p []byte) > (int, error)`. And instead of passing an `io.ReadCloser` you could pass > that func and a `func() error`. At the end of the day, an interface is just > a table of functions. > That's true (although an interface is more than a table of functions: it also a value and type pointer tuple at runtime - ie. you can use it as a variant etc.). My argument is that for generics it is -possibly- not that inconvenient to go without methods (i.e. most of the benefit lies elsewhere). Yes, it can be convenient or elegant in some cases but it comes with quite high cost (in my view) wrt complicating the interface concept with little benefit to type-safety (as opposed to generics in itself). It is more complicated because now you also need to understand sum-types and that methods are not allowed if you have a type list etc etc. This in addition to understanding the mechanics when interfaces can be nil (think of the pointer pit fall etc) and how to use type assertions in switch etc. Another benefit of not allowing method calls on T is that you don't have to choose whether to use io.Reader as a type parameter or as a runtime interface when you design a function. That lack of not having to make that choice is in my view beneficial because it simplifies the programming effort (less choices to make) and avoids discussions and opinion camps. The drawback is that you lose some expressiveness / conciseness in writing some generic containers (or algorithms). > > On the other hand I agree that an "interface" in its meaning of a >> "declaration of a method set" applies equally well to compile time and >> runtime. So the current argument is (I think) that generics is just the >> application of interfaces at compile time instead of runtime. >> > > I think the argument is rather "we want a way to constrain types and > interfaces already provide a familiar way to express such constraints". > It's just about re-using a familiar mechanic, instead of introducing a new > one (in fact, the previous incarnation of contracts *would* have introduced > a new mechanic and that was one of the main criticisms of it). > > The issue I have with this is that it complicates (at least) the language >> around the concept of "interface" at lot (just think about all the >> documentation around interface that needs to be rewritten, and if someone >> asks a question on a interface you first need to address if it's used >> runtime or compile time, etc). >> > > I do think interfaces change, but only to accommodate type-lists. I'm not > a huge fan of that aspect of the design myself. > If no methods calls on T are allowed, then interfaces and generics can be decoupled and just type lists could suffice (with "comparable" being the only built-in special type list for comparable types): // sketch type Ordered generic {float64,int,string,...} type Any generic {} func Max[T Ordered](a, b T) T {} type Bimap[K, V comparable] struct { forward map[K][V] reverse map[V][K] } etc. Btw, you lose "sum-types" here of course. > I don't think the documentation around interfaces need to change at all > apart from that. Their usage to express constraints is quite orthogonal to > their usage as types and personally, I don't predict much confusion > happening around that. > > > A second issue is that, in my opinion, it does not agree very well with >> the idea of "one way of doing things" / orthogonality in Go (as explained >> above). >> >> >> The third use-case I see for generics is to catch bugs by being able >> to express more complicated type-invariants in code. An example of that >> would be type-safety for context.Value >> <https://blog.merovius.de/2020/07/20/parametric-context.html> (or, >> similarly but subtly different, optional i >> >> The context.Value example is maybe an example of something that to me >> feels (at least initially) as a suspicious application of generics. If >> context.Context is made generic (if this is what is meant) then all >> functions that use it, such as in the sql package, are forced to be generic >> too: >> >> func (c *Conn) QueryContext[T any](ctx context.Context[T], query >> string, args ...interface{}) (*Rows, error) >> <https://golang.org/pkg/database/sql/#Conn.QueryContext> >> >> Before you know it everything is generic.... On the other hand, maybe >> this is something that you just need to get used to and be very happy with >> after. My initial reaction would be that the right choice here would be to >> make context not generic as Value is only a "extra" customer user value >> that is not part of its main functionality/purpose. However, it would >> possibly be tempting to factor interface{} into a T if you don't think too >> much about it. >> > > I definitely agree that, especially as I presented it, Context.Value is > not a good use of generics. I was really just interested in exploring the > possibility, to come to that conclusion. Context.Value is widely criticized > as not being type-safe and generics are widely advertised as solving > type-safety issues - so I thought it would be useful, to look at the costs > involved in using generics to solve a type-safety issue (that isn't just > limited to containers). > > My general feeling, right now, is that there aren't a lot of type-safety > issues generics (or at least this generics design) *can* solve, that aren't > containers or generic algorithms (as in "things you'd find in an algorithms > text book"). But I'd be interested to be proven wrong :) > > >> >> -Markus >> >> >> -- >> 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. >> To view this discussion on the web visit >> https://groups.google.com/d/msgid/golang-nuts/28dfab48-9413-4658-9272-bcc79f73153fn%40googlegroups.com >> <https://groups.google.com/d/msgid/golang-nuts/28dfab48-9413-4658-9272-bcc79f73153fn%40googlegroups.com?utm_medium=email&utm_source=footer> >> . >> > -- 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. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CAMoB8rVJoZfUntn%2Bi5T9w9ft5LnQ01Bp0nSJdpMHj-NOWYMTNw%40mail.gmail.com.