On Tue, Jun 8, 2021 at 3:16 AM Robert Engels <reng...@ix.netcom.com> wrote:

> Now, I have a struct I want to use with as an EventLogger (badly named -
> really EventSource). The code I wrote works fine. Test cases (of Log())
> work fine.
>

This is where the refusal to acknowledge comes in. It does not work fine. I
don't understand how you can look at the code without interfaces
<https://play.golang.org/p/WpIzYYLOKn->, run it, see that it behaves
*exactly* the same as your code with interfaces
<https://play.golang.org/p/-f73t_Pm7ur> and still make a statement that
this code works fine. This isn't a matter of being convincing. I'm not
making an argument here. The code you wrote to show that the method is
broken shows that it's broken if you use interfaces or not. How can you
look at that and deny that the code executes the way it does, when you can
actually run it for yourself?

If you wrote tests for those methods and those tests passed, then clearly
your tests are insufficient. Because you, personally, have posted a test
case in this thread, which shows that the `Log` method does *not* work
fine. Without any interfaces.

That's what baffles me. How you can hold on to the narrative that the code
without interfaces works fine and the code with interfaces breaks, when
that's so easily verifiable and shown to be false, just by clicking "Run"
on the playground.

Even if you would try to make the argument (but, again, you are simply
refusing to even acknowledge, you aren't even making a counter argument)
that the tests without interfaces would use a pointer
<https://play.golang.org/p/k6m6Itv9510> (but that's changing more than just
whether or not you are using interfaces - and if you do the same change
using interfaces you again get the same execution trace), all that's needed
to still see that's broken is to run it using `-race`.

There is no opinion here. These are easily verifiable facts. Just repeating
"the code works fine" doesn't change the fact that people can run it and
see that it's not.

It fails when used as a source to RecordEvents() (and similar held
> reference patterns).
>
> How do you protect against this? What is the mechanism as a library author?
>
> Clearly this is a trivial example but similar patterns are everywhere.
>
> Compare the Go interface handling with Java’s everything is a reference -
> much simpler - and then adding value types that are explicit. Or a similar
> implementation in Rust. In both cases knowing you wrote a correct
> implementation is much easier. Java has since added annotations for aspects
> like “thread safe” that cover the atomic aspects.
>
> I like Go. A lot. I’ve designed and built systems with millions of LOC.
> Pointing out aspects that might benefit from changes should be encouraged -
> if not it’s a religion not a programming language.
>
> On Jun 7, 2021, at 7:40 PM, Axel Wagner <axel.wagner...@googlemail.com>
> wrote:
>
> 
>
>
> On Tue, Jun 8, 2021 at 2:05 AM Robert Engels <reng...@ix.netcom.com>
> wrote:
>
>>
>> We agree. It needs a pointer receiver to work. The atomic is also needed
>> in this case for background logging.
>>
>> The problem in this case is that recordEvents() has to document that the
>>  EventLogger passed to recordEvents() must have a pointer receiver for the
>> Log() method. There is nothing in the language that allows me to declare it
>> nor the compiler to enforce it.
>>
>
> It is possible to write a working implementation of that interface without
> a pointer receiver - it just needs to *contain* a pointer:
> https://play.golang.org/p/Xm6ASGcCyhR
> You could also have a slice type, which also can do modifications without
> a pointer receiver. Or a map-type. Or a channel.
>
> If you would restrict an interface to require pointer-receiver, you would
> wrongly restrict the implementer from all these possibilities.
>
> As is the common wisdom, the user of an interface should not care what the
> concrete type implementing an interface is (except if it needs to do a
> type-assertions). It's the same wisdom that applies to people wanting to
> check if an interface contains a nil-pointer: That check relies on the
> assumption that the interface contains a pointer, which shouldn't be nil
> and that's not something that should concern the user of an interface.
>
> Again, to be abundantly clear (you still seem unwilling to acknowledge
> this): The problem with your code is not the definition or usage of the
> interface. It's the definition of the method that is wrong. The
> interface-definition is fine and works fine.
>
> If you don’t see this as suboptimal and an area for improvement I am not
>> sure what else I can say.
>>
>
> I just want to state again, clearly, that all I objected to was you
> calling this "the most inconsistent and obtuse aspect of the Go language",
> which I perceived (and still do) to be an overstatement. "It is suboptimal"
> or "it is an area of improvement" are both significantly weaker statements,
> which I find less objectionable.
>
> Personally, I still don't think it is a huge problem. And the fact that
> you where having a lot of trouble coming up with an example showing it to
> be one (the one you posted doesn't - again, it doesn't, in any way, change
> behavior when using or not using interfaces) is, in my view, a testament to
> that.
>
> And by the way, linters often flag correct code - that is why they have
>> disable options. They try to enforce the most common cases - and by the
>> recommendation in the faq to only use receivers of the same type - it seems
>> appropriate to me to have the linter flag this.
>>
>
> I'm opposed to a linter flag, because it would flag correct code I
> regularly write. In general, linters should not be ignored - they either
> shouldn't be run, or they should be followed. Note that golint has no
> option to selectively disable a particular instance of a warning - the only
> way to silence a warning is to change the code. But I don't want to use a
> pointer receiver, if a value receiver is more appropriate.
>
> If golint or go vet would start flagging this, I would likely follow the
> advice it's giving. Because that's how linters and static checks are
> supposed to be used - to enforce consistency. But I'd be sad doing it.
> Which is why I don't want them to flag it.
>
> I'm less opposed to the FAQ entry. Simpy because an FAQ entry can be more
> easily ignored where it makes sense. If you will, it is one step in
> stringency below a linter. I'm fine defending my choice in a code review,
> but I don't want to defend it to a linter.
>
>
>> As to this being in my opinion the most inconsistent and obtuse aspect of
>> Go - that is my opinion. Curious, what do you think would take the top spot?
>>
>
> I'm not sure. I don't like putting things in absolute order or claiming
> something is "the most X" for exactly that reason - it almost always turns
> out to be an overstatement.
>
> Empirically, the issue of nil-pointers in interfaces not being nil seems
> to take one of the top spots, even though I don't fully understand why.
> To me, concurrency in Go is extremely subtle and I would generally advice
> novices to stay away from it at first (or stay with extremely simple
> constructs), because they are likely to get it wrong.
> Details of how Go handles constants and type-identity/assignabiity is what
> is probably most often tripping me, personally, up in questions/quizzes
> about Go. But it rarely comes up in practice.
> The lack of co/contravariance is probably one of the things I miss the
> most from the language.
>
> It really depends on what you're asking. And I'm very likely forgetting
> things while being put on the spot.
> It's just a lot easier to make relative judgments, than absolute ones.
>
>
>>
>> On Jun 7, 2021, at 6:34 PM, Axel Wagner <axel.wagner...@googlemail.com>
>> wrote:
>>
>> 
>> On Tue, Jun 8, 2021 at 1:26 AM Robert Engels <reng...@ix.netcom.com>
>> wrote:
>>
>>> The pattern of a background stats collector is a common one. The atomic
>>> is required not optional.
>>>
>>
>> It might be a common pattern, but it uses a pointer-receiver in that
>> case. The atomic operation is not required, it operates on a local
>> variable. Again, I don't understand how you can make statements that are so
>> clearly wrong.
>>
>> Feel free to try running it in the race detector without an atomic
>> operation. Feel free trying to get the race detector to trigger without the
>> atomic access, but keeping it silent when you add it. You'll find that this
>> needs a pointer receiver. Because otherwise the function is operating on a
>> local variable.
>>
>>
>>>
>>> On Jun 7, 2021, at 6:16 PM, 'Axel Wagner' via golang-nuts <
>>> golang-nuts@googlegroups.com> wrote:
>>>
>>> 
>>> BTW, just to nail down the point of that code being wrong without
>>> interfaces: Your usage of `atomic` in `Log` is superfluous. You are
>>> operating on a local variable, so there is no possibility of concurrent
>>> modification. Your code is equivalent to this:
>>> https://play.golang.org/p/zYG0zTsk-2a
>>> The only reason to use `atomic` here (and why you used it) is if that
>>> memory could be shared between goroutines. For that to happen, you need a
>>> pointer receiver though.
>>>
>>> I refuse to believe that interfaces have anything to do with this
>>> obfuscation here. There is more than enough indication of it being wrong in
>>> any case.
>>>
>>> On Tue, Jun 8, 2021 at 1:05 AM Axel Wagner <
>>> axel.wagner...@googlemail.com> wrote:
>>>
>>>> On Mon, Jun 7, 2021 at 11:42 PM Robert Engels <reng...@ix.netcom.com>
>>>> wrote:
>>>>
>>>>> I don’t think that represents the problem fairly. In the non interface
>>>>> case I know I can’t accept a copy so I would declare the method as taking 
>>>>> a
>>>>> pointer to the struct.
>>>>>
>>>>
>>>> How methods are declared should, in general, not be a matter of whether
>>>> or not they are assigned to an interface, but to whether or not they need a
>>>> pointer. Again: Your code is incorrect without interfaces
>>>> <https://play.golang.org/p/WpIzYYLOKn->. The problem doesn't happen
>>>> when you put that value into an interface - it happens when you pass a copy
>>>> of it and expect it to refer to the original. Interfaces are just one way
>>>> to create such a copy, but they do not matter for the correctness of this
>>>> code and for whether or not that method needs a pointer receiver (it does).
>>>>
>>>> But again, to be clear: I'm not saying problems like this *never*
>>>> happen and I'm not even saying that interfaces may obscure it in some
>>>> cases. Just that a) the root cause here is that your method really needs to
>>>> take a pointer-receiver, interfaces or not and b) that it seems very much
>>>> an overstatement to me to call this "the most inconsistent and obtuse
>>>> aspect of the Go language".
>>>>
>>>> With interfaces this is lost - as the interface is implicitly a pointer
>>>>>
>>>>
>>>> Well, it seems a bad idea to say that interfaces are implicitly
>>>> pointers then. That seems to indicate that Rob's original phrasing is
>>>> indeed an important clarification - the language behaves as if the value
>>>> contained in them is copied when the interface value is copied.
>>>>
>>>> It seems the confusion here is, that you assume it's not. And that
>>>> interfaces act as a pointers, when they don't.
>>>>
>>> --
>>> 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/CAEkBMfGVyvYYpQhCp_JkxN9EvgZ4FXJ8_WpxseJOB1OR7qt6ww%40mail.gmail.com
>>> <https://groups.google.com/d/msgid/golang-nuts/CAEkBMfGVyvYYpQhCp_JkxN9EvgZ4FXJ8_WpxseJOB1OR7qt6ww%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/CAEkBMfHibUpDHQU9m8%3DrLYtnDj%3DFY01nkuP4k0Giow-hCbhNgQ%40mail.gmail.com
>> <https://groups.google.com/d/msgid/golang-nuts/CAEkBMfHibUpDHQU9m8%3DrLYtnDj%3DFY01nkuP4k0Giow-hCbhNgQ%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/CAEkBMfGRsVZi9L_quB_fJhxTUHY0XYYhADmKLLEP0Ly2B6k4qA%40mail.gmail.com.

Reply via email to