I'd happy with if val { ... }
and if !val { ... } Instead of comparing val with an explicit zero but don't feel strongly about this. > On Oct 17, 2023, at 9:09 PM, Jon Watte <jwa...@gmail.com> wrote: > > Circling back to this, because it came up today again. > > Here's the generic function I want to write. It comes up in a lot of function > composition, which in turn comes up in a lot of interface adapters and such: > > func maybeAssign[T any](dst *T, src T, name string) { > if *dst != nil { // any can't be compared with nil > panic(fmt.Errorf("too many %s arguments", name)) > } > *dst = src > } > > Using this function in each assignment, instead of inlining the four-line > construct with panic, can save a lot of space and make code a lot more > readable. > The above doesn't work, because not every type can be assigned nil. > The following also doesn't work: > > func maybeAssign[T comparable](dst *T, src T, name string) { > var zero T > if *dst != zero { // interface and other nillable types can't be compared > to zero > panic(fmt.Errorf("too many %s arguments", name)) > } > *dst = src > } > > Because interface values aren't comparable. (As aren't chans, maps, etc, but > THOSE can be jammed into various interface constructs, whereas "any > interface" cannot, because "interface{}" doesn't actually mean "any > interface") > > Let me try to answer: > > > Why is the specific split into (interfaces, pointers, slices, functions, > > maps, channels) and (numbers, booleans, strings, structs, arrays) a > > particularly important one? > > Because, while go tries very hard to make sure every storable type has a > "zero value," it somehow decides that you can't necessarily COMPARE to that > zero value. > But the whole point of zero values is that you can tell them from non-zero > values! > So, the language has introduced a work-around with the concept of "I can > compare to nil" for these reference types that aren't comparable to their > zero value. > But generics don't allow us to sense or make use of this, so generics can't > express what the regular language can express. Even a very simple case like > the above, can't currently be expressed, and this leads to more verbose code > that's harder to read and harder to work with. (Granted, this is my opinion, > but I'm not alone.) > > If the language instead changes such that chans and interfaces and maps > become comparable, then that's fine -- that solves the problem! But that > seems like a much bigger change than a constraint that senses exactly the > "can compare to nil" semantic. > > If the language instead changes so that nil means "the zero value" in > general, and it so happens that these nil-comparable types can be compared to > nil without any particular qualification, that also solves the problem. That > might indeed be a good solution -- but if so, it'd be nice to know what we > can do to make that happen, and what the other opposition to that change > might be, because that change also feels much less narrow than a "nil" type > constraint. > > > Sincerely, > > Jon Watte > > > -- > "I find that the harder I work, the more luck I seem to have." -- Thomas > Jefferson > > > On Tue, Oct 3, 2023 at 10:41 PM Axel Wagner <axel.wagner...@googlemail.com > <mailto:axel.wagner...@googlemail.com>> wrote: >> Oh (sorry, being forgetful) and re "it's less of a new mechanism than >> introducing a zero identifier": #62487 >> <https://github.com/golang/go/issues/62487> introduces even less new >> mechanism, by expanding comparison to (and assignment of) `nil` to all types >> inside a generic function. It's not a new class of constraint, it just >> special-cases `nil` a bit more. So it is still a far more general mechanism, >> that solves more problems than `nilable` constraint, while requiring fewer >> (or at worst the same number of) new concepts. >> >> On Wed, Oct 4, 2023 at 7:36 AM Axel Wagner <axel.wagner...@googlemail.com >> <mailto:axel.wagner...@googlemail.com>> wrote: >>> (correction: It should be Convert[J isinterface, T J]. I changed the name >>> from I to J to be more readable and then missed one occurrence) >>> >>> On Wed, Oct 4, 2023 at 7:33 AM Axel Wagner <axel.wagner...@googlemail.com >>> <mailto:axel.wagner...@googlemail.com>> wrote: >>>> On Wed, Oct 4, 2023 at 6:54 AM Jon Watte <jwa...@gmail.com >>>> <mailto:jwa...@gmail.com>> wrote: >>>>> > where it is important to permit only type arguments that can be >>>>> > compared to nil >>>>> >>>>> I see! As in, if we somehow got a "equalszero" constraint, then that >>>>> constraint would solve the problem I illustrate. >>>>> I believe that assertion is correct, but I also believe that is a >>>>> stronger assertion, and also that it introduces more of a new concept >>>>> than a simple "nil" constraint. (Unless you're looking for some way to >>>>> make "any" work, and introduce a zero keyword or something...) >>>> >>>> Yes, that is what #61372 <https://go.dev/issue/61372> proposes: Introduce >>>> a `zero` predeclared identifier (!) that is assignable to any type and >>>> comparable to any type. With some discussion about whether it should only >>>> apply inside generic code or not. There is no proposal (as far as I know) >>>> for anything like an "equalszero" constraint, as every type can be >>>> assigned a meaningful comparison to its zero value, so it seems we should >>>> just allow it for all types. >>>> >>>> To be clear, the criticism of a `nilable` constraint is >>>> 1. It only solves a subset of the problem we are seeing. You gave examples >>>> from that subset. I gave some examples of problems we are seeing that are >>>> *not* in that subset. >>>> 2. It is not really clear this particular subset is particularly >>>> important. Why is the specific split into (interfaces, pointers, slices, >>>> functions, maps, channels) and (numbers, booleans, strings, structs, >>>> arrays) a particularly important one? >>>> 3. As long as that is not clear, it seems more prudent to focus on >>>> mechanisms that solve more of the problems we are seeing. >>>> >>>> FWIW I could, personally, get more (though still not fully) on board with >>>> an `isinterface` constraint, that would allow only interfaces. It would >>>> still allow assignment and comparison to `nil`. But it seems far clearer >>>> to me, that interfaces can be singled out. While a `nil` interface is >>>> categorically an invalid value, the same is not true for `nil` >>>> pointers/maps/channels/funcs in general. Any of those kinds of types could >>>> still have methods callable on them that work perfectly fine (by doing an >>>> `if receiver == nil` check in the method). You categorically can't call a >>>> method on a `nil` interface. >>>> >>>> And an `isinterface` constraint could still conceivable be useful for many >>>> of the examples you mentioned. Or it would allow >>>> >>>> func Convert[J isinterface, T I](s []T) []J { >>>> out := make([]I, len(T)) >>>> for i, v := range s { >>>> out[i] = J(v) >>>> } >>>> return out >>>> } >>>> >>>> I'd still not be convinced this is really worth it, but at least it seems >>>> clearer why that particular subset of types deserves to be singled out. In >>>> fact, many people have argued that the interface zero value really >>>> shouldn't have been spelled `nil`, because interfaces have so little in >>>> common, conceptually, to other "nilable" types. >>>> >>>>> >>>>> Also, there's the ergonomics of having to make a zero value instance. >>>>> Maybe we can rely on the compiler to optimize it away, but at a minimum >>>>> it adds another required line of code in the implementation. E g: >>>>> >>>>> func MaybeNuke[T nil](b bool, val T) T { >>>>> if b { >>>>> return nil >>>>> } >>>>> return val >>>>> } >>>>> >>>>> func MaybeNuke(T zero](b bool, val T) T { >>>>> if b { >>>>> var nope T // an extra line! >>>>> return nope >>>>> } >>>>> return val >>>>> } >>>>> >>>>> func MaybeNuke(T any](b bool, val T) T { >>>>> if b { >>>>> return zero[T]{} // maybe? seems weird >>>>> } >>>>> return val >>>>> } >>>>> >>>>> This is because not all zero values can be instantiated inline with >>>>> simply T{}. >>>>> >>>>> Sincerely, >>>>> >>>>> Jon Watte >>>>> >>>>> >>>>> -- >>>>> "I find that the harder I work, the more luck I seem to have." -- Thomas >>>>> Jefferson > > > -- > 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 > <mailto:golang-nuts+unsubscr...@googlegroups.com>. > To view this discussion on the web visit > https://groups.google.com/d/msgid/golang-nuts/CAJgyHGPYEqrDTyRE-gMvSpiyUobHWKuL35nAAtDa1MmGd8uqzA%40mail.gmail.com > > <https://groups.google.com/d/msgid/golang-nuts/CAJgyHGPYEqrDTyRE-gMvSpiyUobHWKuL35nAAtDa1MmGd8uqzA%40mail.gmail.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/FADB0BAB-675C-45A1-8B31-70C0EAFCA4F8%40iitbombay.org.