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 ren...@ix.netcom.com 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 < > golan...@googlegroups.com> wrote: > > > > > On Thu, Aug 27, 2020 at 11:39 AM targe...@gmail.com <targe...@gmail.com> > 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 >> axel.wa...@googlemail.com wrote: >> >>> On Thu, Aug 27, 2020 at 11:10 AM targe...@gmail.com <targe...@gmail.com> >>> 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 >>>> axel.wa...@googlemail.com wrote: >>>> >>>>> On Thu, Aug 27, 2020 at 10:06 AM targe...@gmail.com < >>>>> targe...@gmail.com> 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 alex.be...@gmail.com >>>>>> 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 >>>>>>>> <denis.c...@gmail.com> 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 >>>>>>>> ren...@ix.netcom.com 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 < >>>>>>>> golan...@googlegroups.com> wrote: >>>>>>>> >>> >>>>>>>> >>> On Fri, Apr 10, 2020 at 7:17 PM <cpu...@gmail.com> 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 golang-nuts...@googlegroups.com. >>>>>>>> >>>> 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 golang-nuts...@googlegroups.com. >>>>>>>> >>> >>>>>>>> >>> 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 golan...@googlegroups.com. >>>>>>>> >>>>>>> > 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 golang-nuts...@googlegroups.com. >>>>>> >>>>> 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 golang-nuts...@googlegroups.com. >>>> >>> 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 golang-nuts...@googlegroups.com. >> 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 golang-nuts...@googlegroups.com. > > 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 golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/7ae1ace1-1980-4e2f-86e7-27d8b92735f6n%40googlegroups.com.