Re: [go-nuts] Knowing from documentation whether an interface is holding a pointer or a struct?

2021-06-08 Thread Marvin Renich
* Robert Engels  [210608 18:30]:
> I think the playground code I supplied is essentially a test case -
> and it works in the absence of concurrency or other held references
> (like putting it in a map). 

But it is one simple test case, not an appropriate set of tests.  Saying
that code passes one test says very little about its correctness.  It is
often very easy to intentionally (or inadvertently) write a single test
that passes, even though the code being tested is broken.

> I guess the bottom line for me is that faq says do not mix receiver
> types. There is either a valid reason for this or it should be
> removed. I think it is the former as it makes more usage patterns
> resilient to hard to track bugs. 

I think your MyEventRecorder is good anecdotal evidence that it is
usually better to not mix receiver types.  I don't think anyone is
saying that the FAQ is wrong, just that it is not an absolute.  I don't
think Axel was suggesting that this should be removed, he was just
giving an aside that he sometimes does not follow that advice, but he
knows why he does and accepts the responsibility for any mistakes as a
result.

> I must be very dense but I still don’t see the rationale behind not
> stating : use value receivers for immutable types and pointer
> receivers otherwise. There may be some fringe cases where this doesn’t
> hold - but if you can write the entire stdlib with this pattern it
> seems fairly stable. 

The way I read it, that is the primary advice in the
https://golang.org/doc/faq#methods_on_values_or_pointers section.  It
also gives some other considerations that may mitigate that advice.

...Marvin

-- 
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/YMAjJjDGsZfUpO7x%40basil.wdw.


Re: [go-nuts] Knowing from documentation whether an interface is holding a pointer or a struct?

2021-06-08 Thread Robert Engels
I think the playground code I supplied is essentially a test case - and it 
works in the absence of concurrency or other held references (like putting it 
in a map). 

I guess the bottom line for me is that faq says do not mix receiver types. 
There is either a valid reason for this or it should be removed. I think it is 
the former as it makes more usage patterns resilient to hard to track bugs. 

I must be very dense but I still don’t see the rationale behind not stating : 
use value receivers for immutable types and pointer receivers otherwise. There 
may be some fringe cases where this doesn’t hold - but if you can write the 
entire stdlib with this pattern it seems fairly stable. 

> On Jun 8, 2021, at 5:03 PM, 'Dan Kortschak' via golang-nuts 
>  wrote:
> 
> On Tue, 2021-06-08 at 07:57 -0500, robert engels wrote:
>> The following code is works fine from the developers perspective:
>> 
>> https://play.golang.org/p/gC1XsSLvovM
>> 
>> The developer says, oh cool, I see this great new 3P library that
>> does background logging - I want to use that instead. Hey, I already
>> implement the EventLogger interface, so no problem, I take out my
>> manual logging code, and make a call to recordEvents(EventLogger).
>> 
>> Hmm, my program isn’t logging properly any more. Oh, it says
>> background logging - that likely means concurrency - so maybe I have
>> a race condition, so I run it under —race. Hmmm, says it's fine and
>> it still isn’t working. :(
>> 
>> Eventually the developer figures out that the call to recordEvents()
>> is making a copy, and so needs pointer receiver and to create a
>> pointer based interface reference (and add the atomic calls). It’s
>> not clear to me how the library author would document things to avoid
>> this scenario.
>> 
>> If you don’t see that the above is suboptimal and an AFI I am not
>> sure what else I can say. That a person of your caliber writes code
>> that differs from the recommendation in the FAQ (the mixing of
>> receiver types) is a flag to me that one of the approaches is
>> probably not correct.
>> 
>> ‘go vet’ already has the ability to disable certain checks. Adding a
>> check to ‘go vet’ to detect mixed receiver types (which the FAQ says
>> is not recommended) seems reasonable and will make life easier for
>> many beginner Go programmers - and some seasoned ones as well :)
>> 
>> The duplicitous and transparent nature of pointer/value receivers and
>> interfaces is a source of confusion. I think being explicit would
>> have been a better choice here but that horse has left the barn.
> 
> 
> An error like this would be found in any reasonable set of tests for
> the type. Minimally, if the type is intended to be passed to functions
> in order to be able to be used, a test would involve that and that
> would immediately surface the error.
> 
> What you seem to be asking for is a way for the language to enforce
> contracts on behaviour from the source and you seem to put that at the
> feet of interface handling. However, it is clearly something that
> arises without needing interfaces in the language; a user of the
> MyEventRecorder type would already find problems if they pass the value
> to a function without needing to do that in an interface value. Without
> significant addition of annotations for implementations it is not
> possible for the language to understand the contractual obligations of
> an implementation, and these kinds of annotations are in opposition to
> the design of the language. Other languages do have these kinds of
> marks, but they are not Go (thankfully).
> 
> In terms of documentation of expectations of an interface if that were
> the situation, there are examples in the standard library where it's
> described that implementations must be able to mutate themselves — be a
> pointer receiver (or other reference-like type).
> 
> 
> -- 
> 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/cce7af413d7cb56b4fd653703f1d49d6f5f7e7c6.camel%40kortschak.io.

-- 
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/578FCA64-1551-4902-B09F-2269A286C32D%40ix.netcom.com.


Re: [go-nuts] Knowing from documentation whether an interface is holding a pointer or a struct?

2021-06-08 Thread 'Dan Kortschak' via golang-nuts
On Tue, 2021-06-08 at 07:57 -0500, robert engels wrote:
> The following code is works fine from the developers perspective:
>
> https://play.golang.org/p/gC1XsSLvovM
>
> The developer says, oh cool, I see this great new 3P library that
> does background logging - I want to use that instead. Hey, I already
> implement the EventLogger interface, so no problem, I take out my
> manual logging code, and make a call to recordEvents(EventLogger).
>
> Hmm, my program isn’t logging properly any more. Oh, it says
> background logging - that likely means concurrency - so maybe I have
> a race condition, so I run it under —race. Hmmm, says it's fine and
> it still isn’t working. :(
>
> Eventually the developer figures out that the call to recordEvents()
> is making a copy, and so needs pointer receiver and to create a
> pointer based interface reference (and add the atomic calls). It’s
> not clear to me how the library author would document things to avoid
> this scenario.
>
> If you don’t see that the above is suboptimal and an AFI I am not
> sure what else I can say. That a person of your caliber writes code
> that differs from the recommendation in the FAQ (the mixing of
> receiver types) is a flag to me that one of the approaches is
> probably not correct.
>
> ‘go vet’ already has the ability to disable certain checks. Adding a
> check to ‘go vet’ to detect mixed receiver types (which the FAQ says
> is not recommended) seems reasonable and will make life easier for
> many beginner Go programmers - and some seasoned ones as well :)
>
> The duplicitous and transparent nature of pointer/value receivers and
> interfaces is a source of confusion. I think being explicit would
> have been a better choice here but that horse has left the barn.


An error like this would be found in any reasonable set of tests for
the type. Minimally, if the type is intended to be passed to functions
in order to be able to be used, a test would involve that and that
would immediately surface the error.

What you seem to be asking for is a way for the language to enforce
contracts on behaviour from the source and you seem to put that at the
feet of interface handling. However, it is clearly something that
arises without needing interfaces in the language; a user of the
MyEventRecorder type would already find problems if they pass the value
to a function without needing to do that in an interface value. Without
significant addition of annotations for implementations it is not
possible for the language to understand the contractual obligations of
an implementation, and these kinds of annotations are in opposition to
the design of the language. Other languages do have these kinds of
marks, but they are not Go (thankfully).

In terms of documentation of expectations of an interface if that were
the situation, there are examples in the standard library where it's
described that implementations must be able to mutate themselves — be a
pointer receiver (or other reference-like type).


-- 
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/cce7af413d7cb56b4fd653703f1d49d6f5f7e7c6.camel%40kortschak.io.


[go-nuts] Re: Table-driven benchmarks defeat inlining

2021-06-08 Thread 'drc...@google.com' via golang-nuts

On Sunday, June 6, 2021 at 8:35:02 AM UTC-4 Paul S. R. Chisholm wrote:

> For example, could this code:
>
> func BenchmarkPopCountAlive(b *testing.B) {
> sum = 0
> for i := 0; i < b.N; i++ {
> sum += PopCount(0x1234567890abcdef)
> }
> }
>
> hypothetically be optimized to:
>
> func BenchmarkPopCountAlive(b *testing.B) {
> sum = PopCount(0x1234567890abcdef) * b.N
> }
>
> since PopCount() always returns the same value for the same argument? It 
> probably wouldn't, since that would break many existing benchmarks.
>

We're talking about adding that very optimization, and I estimate the 
chance of it appearing in the next 2 years is above 50%.
Preserving benchmark performance is an anti-goal for people working on 
general-purpose (*) compilers and runtimes.
(*) crypto and real-time are special-purpose.

As to "why", I know of at least three reasons:
- hoisting invariant expressions out of loops is one of those mechanical 
things that computers do pretty well, and Go's package layering makes it 
easy to gather "pure function" information.
- we're getting more and more Go programmers, doing more and more diverse 
things, they won't all be interested in learning hand-optimization tricks.
- when we turn on generics, and as more things are written generically, 
generic-expansion will remove opportunities to hand-optimize code in the 
usual way

So we are *definitely* thinking about this.

As to what to do for your benchmarks, I am not sure.  One obvious answer is 
"write them more carefully", but this does somewhat subvert the idea that 
it's easy to write benchmarks in Go.  We might also provide more guidance, 
as in "a benchmark must do useful work that is consumed or checked" and 
then provide examples of the same.  It's not just the Go compiler, either 
-- if a loop-invariant input causes code to take exactly the same paths 
over and over again, hardware branch predictors will do a better-than-usual 
job.
 

-- 
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/35975862-cfee-4fe5-ad99-70eb83154c1en%40googlegroups.com.


Re: [go-nuts] Are receiver copies atomic?

2021-06-08 Thread 'Axel Wagner' via golang-nuts
Not using gc. You can verify that by running this under the race detector
(`go run -race main.go`):

package main

type A int

func (A) M() {}

func main() {
var a A
go func() { a.M() }()
a = 1
}

Notably, the function doesn't even have to use the receiver (in fact, the
receiver is ignored in this example) for a race to trigger.

I think the only way to get atomic copies would be with something like STM
 or by
guarding ~every access using a mutex transparently. i.e. you need a way to
copy arbitrarily large chunks of memory atomically.

On Tue, Jun 8, 2021 at 12:08 PM Ian Davis  wrote:

> This question came to me while reading the recent thread titled "Knowing
> from documentation whether an interface is holding a pointer or a struct?"
>
> When a method with a non-pointer receiver is called, is the copy made
> atomically? My intuition says it must be but perhaps someone else can
> confirm it?
>
> If so, how does it work?
>
> Ian
>
> --
> 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/cb79c482-42ed-4213-9fc3-381f179e3fa6%40www.fastmail.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+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CAEkBMfESaz8LsJ2afs5yEGZK2JMbZo8%2B%2BTLq2tTx%3DXnvZKhCnA%40mail.gmail.com.


[go-nuts] Re: Are receiver copies atomic?

2021-06-08 Thread jake...@gmail.com
I'm not 100% sure what you mean by "copy made atomically" means in this 
context. But if you mean is calling a value receiver method safe for 
concurrently, then the answer is no. 

In fact it can be the source of subtle races. Take for example this simple 
program (https://play.golang.org/p/Wk5LHxEJ8dQ): 

package main
import "fmt"

type Split struct {
MutValue  uint64
CostValue uint64
}

func (s Split) GetConstValue() uint64 {
return s.CostValue
}

var Sum uint64

func main() {
theOne := Split{7, 3}
fmt.Print("Start ")

go func() {
for {
theOne.MutValue += 1
}
}()

for {
Sum += theOne.GetConstValue()
}
}

If you run this with the race detector on, you will see that there is a 
race between " theOne.MutValue += 1" and "Sum += theOne.GetConstValue()". 
At first glance it might seem like this should be ok, since the body of 
GetConstValue() only reads a non-changing variable, and does not touch MutValue 
. But in fact calling the function does a copy, and so also reads "MutValue", 
which is being concurrently modified, hence the race.  

If GetConstValue() is changed to take a pointer receiver, then the race 
goes away.   

On Tuesday, June 8, 2021 at 6:08:56 AM UTC-4 Ian Davis wrote:

> This question came to me while reading the recent thread titled "Knowing 
> from documentation whether an interface is holding a pointer or a struct?"
>
> When a method with a non-pointer receiver is called, is the copy made 
> atomically? My intuition says it must be but perhaps someone else can 
> confirm it?
>
> If so, how does it work? 
>
> Ian
>

-- 
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/a2ebc1d7-0a3e-4a70-a4a0-ab88fd675d34n%40googlegroups.com.


Re: [go-nuts] Re: what type of grammar GO programming language?

2021-06-08 Thread shuang cui
wonderful!

在2011年10月23日星期日 UTC+8 下午3:11:53<⚛> 写道:

> On Sat, Oct 22, 2011 at 8:05 PM, Tom (NiftyHat) Mitchell
>  wrote:
> >
> > On Sat, Oct 22, 2011 at 1:38 AM, ⚛ <0xe2.0x...@gmail.com> wrote:
> > > On Oct 22, 12:14 am, "Tom (NiftyHat) Mitchell" 
> > > wrote
> > :.
> > >> ...snip...
> > >>  in the parser (see Bison
> > >>
> > >> > file "src/cmd/gc/go.y" in Go implementation).
> > >>
> > >> One answer for a student
> > ...
> >
> > And you remarked to me.
> >
> > > I do not understand what you are talking about.
> >
> > My take on the question from the original poster
> > was this was a take-home quiz question.
> >
> > Knowing the answer is often not the goal in a class.
> > Knowing how to discover the answer is.
> >
> > Sort of like:  Answer = 42
> >
> > Without knowing the question and without
> > showing "your work" the answer is not
> > a real answer.
>
> If you take a look into the file "src/cmd/gc/go.y" and compare it to
> the grammar in the Go specification, you may be able to see some
> examples of the grammar in the specification *not* being parseable by
> Yacc/Bison because the Bison grammar uses different grammar rules in
> several places and postpones the recognition to a later stage of
> compilation.
>
> I believe what I wrote in my 1st post in this forum thread has some
> real value. If you have actual arguments (other than "42") that render
> my post invalid, I would like you to present them to me. If your
> argument is "examining the file src/cmd/gc/go.y" is pointless in
> relation to the OP, it is a wrong argument.
>

-- 
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/04d47714-b143-4e05-a696-577aff001136n%40googlegroups.com.


Re: [go-nuts] Knowing from documentation whether an interface is holding a pointer or a struct?

2021-06-08 Thread Marvin Renich
* 'Axel Wagner' via golang-nuts  [210608 02:54]:
> On Tue, Jun 8, 2021 at 6:36 AM Marvin Renich  wrote:
> 
> > You say that test cases of Log work fine, but they are only fine in a
> > non-concurrent environment.  The instant you test Log (without
> > interfaces) in a concurrent program it fails in an obvious manner.
> >
> 
> nit: I don't think concurrency has anything to do with it either. The
> failure mode is making a copy and expecting the copy and the original to
> share memory.

I agree.

> FWIW I agree with Robert that it's relatively easy to write a test for this
> that never copies the value (though even then, if you think about using
> atomics you definitely should think about writing a concurrent test and
> running it with `-race` enabled, which should show the problem).

Sure.

> I disagree with him, however, that interfaces make it more likely to run
> into the problem when *using* the code. Any even remotely realistic usage
> of that code is broken. Even if you failed to write tests which surface
> that breakage.

Right.  This is just one of many aspects of programming that require
careful consideration to get right.  As you keep saying, "this is
suboptimal" applies, but "the most inconsistent and obtuse aspect of the
Go language" is way too extreme of an assertion.

...Marvin

-- 
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/20210608151806.ebqigtzmdopb5qdq%40basil.wdw.


Re: [go-nuts] Knowing from documentation whether an interface is holding a pointer or a struct?

2021-06-08 Thread robert engels
OK, I will try one more time.

The following code is works fine from the developers perspective:

https://play.golang.org/p/gC1XsSLvovM 

The developer says, oh cool, I see this great new 3P library that does 
background logging - I want to use that instead. Hey, I already implement the 
EventLogger interface, so no problem, I take out my manual logging code, and 
make a call to recordEvents(EventLogger).

Hmm, my program isn’t logging properly any more. Oh, it says background logging 
- that likely means concurrency - so maybe I have a race condition, so I run it 
under —race. Hmmm, says it's fine and it still isn’t working. :(

Eventually the developer figures out that the call to recordEvents() is making 
a copy, and so needs pointer receiver and to create a pointer based interface 
reference (and add the atomic calls). It’s not clear to me how the library 
author would document things to avoid this scenario.

If you don’t see that the above is suboptimal and an AFI I am not sure what 
else I can say. That a person of your caliber writes code that differs from the 
recommendation in the FAQ (the mixing of receiver types) is a flag to me that 
one of the approaches is probably not correct.

‘go vet’ already has the ability to disable certain checks. Adding a check to 
‘go vet’ to detect mixed receiver types (which the FAQ 
 says is not 
recommended) seems reasonable and will make life easier for many beginner Go 
programmers - and some seasoned ones as well :)

The duplicitous and transparent nature of pointer/value receivers and 
interfaces is a source of confusion. I think being explicit would have been a 
better choice here but that horse has left the barn.

> On Jun 8, 2021, at 1:54 AM, 'Axel Wagner' via golang-nuts 
>  wrote:
> 
> On Tue, Jun 8, 2021 at 6:36 AM Marvin Renich  > wrote:
> You say that test cases of Log work fine, but they are only fine in a
> non-concurrent environment.  The instant you test Log (without
> interfaces) in a concurrent program it fails in an obvious manner.
> 
> nit: I don't think concurrency has anything to do with it either. The failure 
> mode is making a copy and expecting the copy and the original to share 
> memory. If anything, concurrency (in a test) would make it more likely to get 
> hidden, by increasing the likelihood that a closure is used, which implicitly 
> shares a pointer: https://play.golang.org/p/Gwj9GScjQBJ 
> 
> 
> Of course, concurrency then also makes the failure easy to see, as long as 
> you remember to run your tests with `-race`.
>  
> FWIW I agree with Robert that it's relatively easy to write a test for this 
> that never copies the value (though even then, if you think about using 
> atomics you definitely should think about writing a concurrent test and 
> running it with `-race` enabled, which should show the problem).
> I disagree with him, however, that interfaces make it more likely to run into 
> the problem when *using* the code. Any even remotely realistic usage of that 
> code is broken. Even if you failed to write tests which surface that breakage.
> 
> 
> Interfaces, and their ability to potentially be satisfied by either a
> non-pointer type or a pointer type, depending on the type, is not the
> problem here.
> 
> ...Marvin
> 
> -- 
> 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/20210608043609.gguu3t3hqbsziema%40basil.wdw
>  
> .
> 
> -- 
> 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/CAEkBMfGa5B99OO8oTxJOWFSuJPinPF3b1QJWEuqMD4ZPAiCi%3DQ%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 golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/A2CBA1A9-5342-4AAF-8393-A0DD96EC832A%40ix.netcom.com.


Re: [go-nuts] Are receiver copies atomic?

2021-06-08 Thread Jan Mercl
On Tue, Jun 8, 2021 at 12:08 PM Ian Davis  wrote:

> When a method with a non-pointer receiver is called, is the copy made 
> atomically? My intuition says it must be but perhaps someone else can confirm 
> it?

I don't think the specs require that and I don't think well known
implementations try to enforce it. Also, above machine words it gets
complicated.

> If so, how does it work?

The receiver of a method is just the first parameter of an otherwise
ordinary function. I believe it's passed as any other argument,
currently by pushing it to the stack by the caller in case of gc, for
example. gccgo may already use registers, but that I'm only guessing.
(C ABI usually uses registers, but Go with gccgo may differ.)

FTR: AFAICT, from the perspective of the method, its receiver is
passed always by value, regardless if the method is declared on a
pointer receiver or not because a pointer is also a quite normal
value.

-- 
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/CAA40n-U3q%2BjJDjrq7DuKKn2mjCWjnH4bNo7CYxQ39nbDtVx%2BGw%40mail.gmail.com.


[go-nuts] Are receiver copies atomic?

2021-06-08 Thread Ian Davis
This question came to me while reading the recent thread titled "Knowing from 
documentation whether an interface is holding a pointer or a struct?"

When a method with a non-pointer receiver is called, is the copy made 
atomically? My intuition says it must be but perhaps someone else can confirm 
it?

If so, how does it work? 

Ian

-- 
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/cb79c482-42ed-4213-9fc3-381f179e3fa6%40www.fastmail.com.


Re: [go-nuts] Knowing from documentation whether an interface is holding a pointer or a struct?

2021-06-08 Thread 'Axel Wagner' via golang-nuts
On Tue, Jun 8, 2021 at 6:36 AM Marvin Renich  wrote:

> You say that test cases of Log work fine, but they are only fine in a
> non-concurrent environment.  The instant you test Log (without
> interfaces) in a concurrent program it fails in an obvious manner.
>

nit: I don't think concurrency has anything to do with it either. The
failure mode is making a copy and expecting the copy and the original to
share memory. If anything, concurrency (in a test) would make it more
likely to get hidden, by increasing the likelihood that a closure is used,
which implicitly shares a pointer: https://play.golang.org/p/Gwj9GScjQBJ

Of course, concurrency then also makes the failure easy to see, as long as
you remember to run your tests with `-race`.

FWIW I agree with Robert that it's relatively easy to write a test for this
that never copies the value (though even then, if you think about using
atomics you definitely should think about writing a concurrent test and
running it with `-race` enabled, which should show the problem).
I disagree with him, however, that interfaces make it more likely to run
into the problem when *using* the code. Any even remotely realistic usage
of that code is broken. Even if you failed to write tests which surface
that breakage.


> Interfaces, and their ability to potentially be satisfied by either a
> non-pointer type or a pointer type, depending on the type, is not the
> problem here.
>
> ...Marvin
>
> --
> 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/20210608043609.gguu3t3hqbsziema%40basil.wdw
> .
>

-- 
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/CAEkBMfGa5B99OO8oTxJOWFSuJPinPF3b1QJWEuqMD4ZPAiCi%3DQ%40mail.gmail.com.


Re: [go-nuts] Knowing from documentation whether an interface is holding a pointer or a struct?

2021-06-08 Thread 'Axel Wagner' via golang-nuts
On Tue, Jun 8, 2021 at 3:16 AM Robert Engels  wrote:

> 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.
>

FTR, this is the second time you are making that twist and I already called
out the first and I don't appreciate that you are repeating it.

"This aspect might benefit from a change" is a significantly weaker
statement that using a superlative like "the most inconsistent and obtuse
aspect of the Go language".


>
> On Jun 7, 2021, at 7:40 PM, Axel Wagner 
> wrote:
>
> 
>
>
> On Tue, Jun 8, 2021 at 2:05 AM Robert Engels 
> 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 

Re: [go-nuts] Knowing from documentation whether an interface is holding a pointer or a struct?

2021-06-08 Thread 'Axel Wagner' via golang-nuts
On Tue, Jun 8, 2021 at 3:16 AM Robert Engels  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
, run it, see that it behaves
*exactly* the same as your code with interfaces
 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
 (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 
> wrote:
>
> 
>
>
> On Tue, Jun 8, 2021 at 2:05 AM Robert Engels 
> 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