> I'm mostly form C++ land from of course :) On Thursday, August 27, 2020 at 2:01:33 PM UTC+3 [email protected] wrote:
> I know this. I'm mostly form C++ land, so you may imagine how many warts > are there "on the top of the index finger" :) > I'm merely speaking against opinion that Shroedingerface is not a problem > at all. > On Thursday, August 27, 2020 at 1:55:54 PM UTC+3 [email protected] > wrote: > >> This will be a Go wart that will never go away. All languages have warts. >> This one just happens to be on the top of the index finger There is so >> little utility in a nil interface but it’s there. >> >> On Aug 27, 2020, at 5:14 AM, 'Axel Wagner' via golang-nuts < >> [email protected]> wrote: >> >> >> >> >> On Thu, Aug 27, 2020 at 11:39 AM [email protected] <[email protected]> >> wrote: >> >>> > I'm saying the current situation is less confusing than what you >>> describe, yes. >>> > AIUI, with what you describe, if I have a variable `x` of type `*T` >>> and an interface variable `y`, then `y = x` and `y = (*T)(x)` have >>> different semantics. I think it is strange to have a conversion of `x` *to >>> its own type* have any sort of semantic implication. It should be a no-op. >>> >>> It may be expressed in some different way. To me, if `x == nil` and then >>> `y != nil` after `y = x` is much more confusing. >>> >> >> And obviously you are not alone. Even though I really don't understand >> why this isn't just one of those "you learn about it, you know about it, >> you never run into any problems again" type of things. It does seem to come >> up sufficiently often to be a problem. And there are solutions that I think >> are fine. For example, using a different identifier (say `none`) to denote >> the zero-value of interfaces would be fine by me. >> >> But solutions that try to give special treatment to nil-values when they >> are put into interfaces just seem wrong to me. They single out nil-values >> as somehow special or less valid than other values. They single out >> pointer/slice/map/chan types as somehow special over int/bool/string/… >> types. It just seems undeniable to me, that they make the language *less* >> consistent. >> >> If you ask my opinion, I would make interfaces compare to nil on just >>> data pointer. If one wanted interface which doesn't require data, he >>> could've easily created one with static stub variable. No additional >>> checks, no "semi-nil" fat pointers, everything simple and consistent. >>> >> >> The rule is very simple: A nil-interface is one that has no dynamic >> value. All values are treated the same for this purpose. All types are >> treated the same. I don't understand how that is anything but simple and >> consistent. It might be less understandable for some other reason, but I >> don't think it's simplicity or consistency. >> >> >>> On Thursday, August 27, 2020 at 12:20:59 PM UTC+3 >>> [email protected] wrote: >>> >>>> On Thu, Aug 27, 2020 at 11:10 AM [email protected] <[email protected]> >>>> wrote: >>>> >>>>> it would definitely. Though price for consistency looks very much >>>>> acceptable. >>>> >>>> >>>> I don't think "consistency" is at all the right word here. If anything, >>>> things would get *less* consistent, not more. >>>> >>>> > Personally, I would also find it very confusing, if converting a T to >>>>> a T changed program behavior >>>>> Sorry, didn't get it. Are you saying that nil pointer -> nil interface >>>>> is more confusing? >>>>> >>>> >>>> I'm saying the current situation is less confusing than what you >>>> describe, yes. >>>> >>>> AIUI, with what you describe, if I have a variable `x` of type `*T` and >>>> an interface variable `y`, then `y = x` and `y = (*T)(x)` have different >>>> semantics. I think it is strange to have a conversion of `x` *to its own >>>> type* have any sort of semantic implication. It should be a no-op. >>>> >>>> >>>>> On Thursday, August 27, 2020 at 11:49:16 AM UTC+3 >>>>> [email protected] wrote: >>>>> >>>>>> On Thu, Aug 27, 2020 at 10:06 AM [email protected] < >>>>>> [email protected]> wrote: >>>>>> >>>>>>> Not sure if it was mentioned here, but IMO the main issues isn't nil >>>>>>> data itself, but how easy it's created. It'd be much less of a surprise >>>>>>> if >>>>>>> creating nil-data required explicit cast from nil struct pointer to >>>>>>> interface pointer and resulted in just nil interface pointer in case of >>>>>>> implicit cast. Though such change is almost certainly breaking one. >>>>>>> >>>>>> >>>>>> This would require to insert extra nil-checks when assigning a >>>>>> pointer-value to an interface, as the compiler can't know if a pointer >>>>>> is >>>>>> nil or not. Personally, I would also find it very confusing, if >>>>>> converting >>>>>> a T to a T changed program behavior (though arguably, there is one such >>>>>> case currently with `uintptr(uintptr(unsafe.Pointer))`. But usage of >>>>>> `unsafe` seems sufficiently advanced). >>>>>> >>>>>> >>>>>>> >>>>>>> On Monday, August 24, 2020 at 7:08:17 AM UTC+3 [email protected] >>>>>>> wrote: >>>>>>> >>>>>>>> Can we at least move with the >>>>>>>> https://github.com/golang/go/issues/22729 , please? Anything will >>>>>>>> help with the current mess. >>>>>>>> >>>>>>>> >>>>>>>> On Sunday, August 23, 2020 at 8:52:30 PM UTC-7, Ian Lance Taylor >>>>>>>> wrote: >>>>>>>> >>>>>>>>> On Sun, Aug 23, 2020 at 1:16 PM Denis Cheremisov >>>>>>>>> <[email protected]> wrote: >>>>>>>>> > >>>>>>>>> > You may use something like this >>>>>>>>> > >>>>>>>>> > value2 := >>>>>>>>> *(*uint64)(unsafe.Pointer(uintptr(unsafe.Pointer(&value)) + 8)) >>>>>>>>> > if value2 == 0 { >>>>>>>>> > return true >>>>>>>>> > } >>>>>>>>> > >>>>>>>>> > on AMD64, should work also for any 64 bit architecture (at least >>>>>>>>> I believe so). Remember though this is hacky and may stop working >>>>>>>>> once. >>>>>>>>> >>>>>>>>> You could do that, but please don't. >>>>>>>>> >>>>>>>>> Ian >>>>>>>>> >>>>>>>>> >>>>>>>>> > воскресенье, 23 августа 2020 г. в 22:58:51 UTC+3, Aviv Eyal: >>>>>>>>> >> >>>>>>>>> >> I was trying to show that the current behavior is confusing and >>>>>>>>> that fmt.Print() needing to resort to panic-and-recover is kinda code >>>>>>>>> smell, but I sorts-of convinced myself that the current behavior is >>>>>>>>> right, >>>>>>>>> or at least consistent. >>>>>>>>> >> >>>>>>>>> >> In my code, I got bit because I sometimes use v *Type to denote >>>>>>>>> "I may or may not have a value here" (where Type is a value-type). >>>>>>>>> >> This is probably a bad practice on my behalf, because I break >>>>>>>>> the Liskov substitution principle: there is a value of `*Type` that >>>>>>>>> is not >>>>>>>>> a valid value of `Type`, and I let this value slip by. >>>>>>>>> >> >>>>>>>>> >> In this case, `v Type` implements Stringer (i.e. valid callee >>>>>>>>> for `v.String()`, but `v *Type`, in the strictest sense, does not. >>>>>>>>> >> The only reason we can write: >>>>>>>>> >> >>>>>>>>> >> func (Type) String() string {...} >>>>>>>>> >> v *Type = &Type{...} >>>>>>>>> >> _ = v.String() >>>>>>>>> >> >>>>>>>>> >> and have it compile, is syntactic sugar: `v` gets implicitly >>>>>>>>> de-referenced, and there's an implicit assumption that it's not nil. >>>>>>>>> >> And there's a matching syntactic sugar for converting `Type` to >>>>>>>>> a `*Type`. >>>>>>>>> >> >>>>>>>>> >> So, In the code: >>>>>>>>> >> >>>>>>>>> >> func (Type) String() string {...} >>>>>>>>> >> >>>>>>>>> >> v *Type = nil >>>>>>>>> >> r interface{} = v >>>>>>>>> >> _, ok = r.(Stringer) >>>>>>>>> >> >>>>>>>>> >> What I really want to ask is "Can I, at runtime, call >>>>>>>>> r.String()?", whereas the question Go answers is "Is any of `r`, >>>>>>>>> `*r`, or >>>>>>>>> `&r` defines .String()?" - which matches the static semantics of >>>>>>>>> `r.String()`. >>>>>>>>> >> >>>>>>>>> >> So, while I should probably not use *Type as a replacement for >>>>>>>>> Optional<Type>, I think it might make sense to have some operator >>>>>>>>> that can >>>>>>>>> determine, at run-time, if a call `r.String()` is valid (including a >>>>>>>>> nil-check). >>>>>>>>> >> >>>>>>>>> >> >>>>>>>>> >> -- Aviv >>>>>>>>> >> >>>>>>>>> >> On Saturday, April 11, 2020 at 4:48:28 PM UTC+3 >>>>>>>>> [email protected] wrote: >>>>>>>>> >>> >>>>>>>>> >>> I agree with the OP. The usefulness of nil interfaces is >>>>>>>>> pretty limited. Show me a useful case that cant easily be implemented >>>>>>>>> with >>>>>>>>> non-nil interfaces. >>>>>>>>> >>> >>>>>>>>> >>> I would argue that allowing nil interfaces causes more subtle >>>>>>>>> latent bugs and makes it harder to reason about the correctness of >>>>>>>>> code >>>>>>>>> when reviewing it. >>>>>>>>> >>> >>>>>>>>> >>> It just feels wrong. I realize I’m probably in the minority >>>>>>>>> here but the OP is not alone. >>>>>>>>> >>> >>>>>>>>> >>> On Apr 11, 2020, at 8:20 AM, 'Axel Wagner' via golang-nuts < >>>>>>>>> [email protected]> wrote: >>>>>>>>> >>> >>>>>>>>> >>> On Fri, Apr 10, 2020 at 7:17 PM <[email protected]> wrote: >>>>>>>>> >>>> >>>>>>>>> >>>> I realize I'm reviving an age-old discussion here and >>>>>>>>> apologize for bringing up the undead. I happend to run into this when >>>>>>>>> my >>>>>>>>> application panicked when some interfaces where initialized with nil >>>>>>>>> mock >>>>>>>>> objects instead of being left uninitialized as in production mode. >>>>>>>>> >>> >>>>>>>>> >>> >>>>>>>>> >>> Let's imagine a world in which `foo == nil` also is true if >>>>>>>>> `foo` is an interface-value containing a nil-pointer. Let's say in >>>>>>>>> this >>>>>>>>> world, someone sends a message to golang-nuts. They wrote a mock for >>>>>>>>> the >>>>>>>>> same code. And since it's just a mock, they just returned static >>>>>>>>> value from >>>>>>>>> its methods and didn't need to care if the pointer was nil or not. >>>>>>>>> They are >>>>>>>>> confused, because the passed in this mock, but the code just assumed >>>>>>>>> the >>>>>>>>> field was uninitialized and never called into their mock. What would >>>>>>>>> you >>>>>>>>> tell them? Why is their confusion less valid? >>>>>>>>> >>> >>>>>>>>> >>>> This would be an example where a nil implementing fooer is >>>>>>>>> never caught: >>>>>>>>> >>>> >>>>>>>>> >>>> type fooer interface { >>>>>>>>> >>>> foo() >>>>>>>>> >>>> } >>>>>>>>> >>>> >>>>>>>>> >>>> type other struct{} >>>>>>>>> >>>> >>>>>>>>> >>>> func (o *other) foo() {} // implement fooer >>>>>>>>> >>>> >>>>>>>>> >>>> func main() { >>>>>>>>> >>>> var f fooer >>>>>>>>> >>>> >>>>>>>>> >>>> var p *other // nil >>>>>>>>> >>>> f = p // it is a fooer so I can assign it >>>>>>>>> >>>> >>>>>>>>> >>>> if f == nil { >>>>>>>>> >>>> // will not get here >>>>>>>>> >>>> } >>>>>>>>> >>>> } >>>>>>>>> >>>> >>>>>>>>> >>>> >>>>>>>>> >>>> My confusion comes from the point that the nil interface is >>>>>>>>> apparently not "a nil-pointer with the correct method set" while >>>>>>>>> *other is >>>>>>>>> even if nil. >>>>>>>>> >>> >>>>>>>>> >>> >>>>>>>>> >>> In the code you posted, even a nil *other is a perfectly fine >>>>>>>>> implementation of fooer. You can call `(*other)(nil).foo()` without >>>>>>>>> any >>>>>>>>> problems. >>>>>>>>> >>> So, as you illustrated, calling methods on a nil-pointer can >>>>>>>>> be totally fine. A nil-interface, OTOH, doesn't have any methods to >>>>>>>>> call, >>>>>>>>> as it doesn't contain a dynamic value. If you write >>>>>>>>> `(*other)(nil).foo()`, >>>>>>>>> it is completely clear what code gets called - even if that code >>>>>>>>> *might* >>>>>>>>> panic. If you write `fooer(nil).foo()`, what code should be called in >>>>>>>>> your >>>>>>>>> opinion? >>>>>>>>> >>> >>>>>>>>> >>> I think it's easy to see that a nil-interface and a >>>>>>>>> nil-pointer stored in an interface are very different things. Even >>>>>>>>> from >>>>>>>>> first principles, without deep knowledge of the language. And if they >>>>>>>>> are >>>>>>>>> obviously different, I don't understand why you'd find it confusing >>>>>>>>> that >>>>>>>>> they are not the same in this particular manner. >>>>>>>>> >>> >>>>>>>>> >>>> The above is a case where that might happen. In can be worked >>>>>>>>> around but it is unexpected unless the programmer is deeply rooted in >>>>>>>>> the >>>>>>>>> language definition. >>>>>>>>> >>> >>>>>>>>> >>> >>>>>>>>> >>> I fully agree with that. What I *don't* agree with, is where >>>>>>>>> you attribute the problem here. You say, the problem is that the >>>>>>>>> nil-check >>>>>>>>> is ill-behaved. I say that - if anything - the original >>>>>>>>> nil-assignment is >>>>>>>>> ill-behaved. Having `(fooer)((*other)(nil)) == nil` be true is >>>>>>>>> semantically >>>>>>>>> wrong, because by checking against `nil`, you are checking if you >>>>>>>>> have a >>>>>>>>> correct implementation - and you might well have a correct >>>>>>>>> implementation, >>>>>>>>> even if it's using a nil-pointer. >>>>>>>>> >>> >>>>>>>>> >>> Note, that the contained pointer being nil isn't the *only* >>>>>>>>> case in which calling the method might panic. For example, what about >>>>>>>>> this >>>>>>>>> code? >>>>>>>>> >>> https://play.golang.org/p/lNq0qphez7v >>>>>>>>> >>> Shouldn't the `nil`-check also catch that? After all, calling >>>>>>>>> the method panics, so it's clearly not a valid implementation - even >>>>>>>>> if x >>>>>>>>> itself is not nil. Why is a nil-pointer more special than any other >>>>>>>>> value >>>>>>>>> that causes a method to panic? >>>>>>>>> >>> >>>>>>>>> >>>> Seems as of today that there is no tooling to support that >>>>>>>>> check. Maybe it's not a widespread issue. >>>>>>>>> >>> >>>>>>>>> >>> >>>>>>>>> >>> As of today, the language also isn't changed :) Maybe someone >>>>>>>>> who think this is important enough to change the language, could also >>>>>>>>> feel >>>>>>>>> it's important enough to write this tooling. >>>>>>>>> >>> >>>>>>>>> >>>> >>>>>>>>> >>>> -- >>>>>>>>> >>>> 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 [email protected]. >>>>>>>>> >>>> To view this discussion on the web visit >>>>>>>>> https://groups.google.com/d/msgid/golang-nuts/e0dbcd38-510e-43b9-b363-2af1c636250b%40googlegroups.com. >>>>>>>>> >>>>>>>>> >>>>>>>>> >>> >>>>>>>>> >>> -- >>>>>>>>> >>> 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 [email protected]. >>>>>>>>> >>> >>>>>>>>> >>> To view this discussion on the web visit >>>>>>>>> https://groups.google.com/d/msgid/golang-nuts/CAEkBMfEPjcsZ3enqXyt%2BUphFJ1cNQ81cFCcjfwwkQZKHMrjSzA%40mail.gmail.com. >>>>>>>>> >>>>>>>>> >>>>>>>>> > >>>>>>>>> > -- >>>>>>>>> > 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 [email protected]. >>>>>>>>> >>>>>>>> > To view this discussion on the web visit >>>>>>>>> https://groups.google.com/d/msgid/golang-nuts/c1ed2e38-6215-4ed2-8357-f8b5d83bf1a7n%40googlegroups.com. >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>> -- >>>>>>> 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 [email protected]. >>>>>>> >>>>>> To view this discussion on the web visit >>>>>>> https://groups.google.com/d/msgid/golang-nuts/84244528-84e6-4c2e-89bf-7fbf0590e132n%40googlegroups.com >>>>>>> >>>>>>> <https://groups.google.com/d/msgid/golang-nuts/84244528-84e6-4c2e-89bf-7fbf0590e132n%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 [email protected]. >>>>> >>>> To view this discussion on the web visit >>>>> https://groups.google.com/d/msgid/golang-nuts/46d92421-a3a8-4b8a-b557-aa14d79e55b6n%40googlegroups.com >>>>> >>>>> <https://groups.google.com/d/msgid/golang-nuts/46d92421-a3a8-4b8a-b557-aa14d79e55b6n%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 [email protected]. >>> To view this discussion on the web visit >>> https://groups.google.com/d/msgid/golang-nuts/31df134b-7e55-4f32-9e1f-6d974817891en%40googlegroups.com >>> >>> <https://groups.google.com/d/msgid/golang-nuts/31df134b-7e55-4f32-9e1f-6d974817891en%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 [email protected]. >> >> To view this discussion on the web visit >> https://groups.google.com/d/msgid/golang-nuts/CAEkBMfGhDrbJRMr%3DtxPu_XNDTzyT7PV61Oo7kOLP5QBqg-Zaiw%40mail.gmail.com >> >> <https://groups.google.com/d/msgid/golang-nuts/CAEkBMfGhDrbJRMr%3DtxPu_XNDTzyT7PV61Oo7kOLP5QBqg-Zaiw%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 [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/f3081a9b-bf99-41f9-81e6-62147cbb6a12n%40googlegroups.com.
