Re: [go-nuts] Casting int to bool and the reverse for bit hacking ?

2020-11-23 Thread Aleksey Tulinov
Yeah, it's not the first time this question appears and it's not
immediately obvious that Go compiler can do this optimization.

IIRC someone asked for this optimization on Github and it's there, but
Go doesn't allow bool to int conversion therefore it can't do this
optimization implicitly, which is quite unfortunate because some
people might take branching in bitwise operations for granted even
though there is no branching when integers are used. You might also
want to check what GCC is doing, maybe it can optimize code better.

https://godbolt.org/z/Eod5Ye

Assembly looks smaller and when xor is removed it appears like the
entire function is being optimized away perhaps because it's a
constant expression that can be evaluated at compile time. But i'm not
sure how good this assembly is without measuring actual performance.

Hope this helps.

вс, 22 нояб. 2020 г. в 11:54, christoph...@gmail.com
:
>
> Thank you Aleksey. That is indeed a working solution, and it works well.
>  Here are the two functions I wrote as suggested:
>
> func bool2int(b bool) int {
> if b {
> return 1
> }
> return 0
> }
>
> func testBitHack(v int) bool {
> return (bool2int(v==10) & bool2int(v==5) & bool2int(v==15)) == 0
> }
>
> Here is the Go assembly code of testBitHack
>
> "".testBitHack STEXT nosplit size=47 args=0x10 locals=0x0
> 0x 0 (main.go:12)   TEXT"".testBitHack(SB), 
> NOSPLIT|ABIInternal, $0-16
> 0x 0 (main.go:12)   FUNCDATA$0, 
> gclocals·33cdeebe80329f1fdbee7f5874cb(SB)
> 0x 0 (main.go:12)   FUNCDATA$1, 
> gclocals·33cdeebe80329f1fdbee7f5874cb(SB)
> 0x 0 (main.go:13)   MOVQ"".v+8(SP), AX
> 0x0005 5 (main.go:13)   CMPQAX, $10
> 0x0009 9 (main.go:13)   SETEQ   CL
> 0x000c 00012 (main.go:13)   CMPQAX, $5
> 0x0010 00016 (main.go:13)   SETEQ   DL
> 0x0013 00019 (main.go:13)   CMPQAX, $15
> 0x0017 00023 (main.go:13)   SETEQ   AL
> 0x001a 00026 (main.go:13)   MOVBLZX DL, DX
> 0x001d 00029 (main.go:13)   MOVBLZX CL, CX
> 0x0020 00032 (main.go:13)   ANDQDX, CX
> 0x0023 00035 (main.go:13)   MOVBLZX AL, AX
> 0x0026 00038 (main.go:13)   TESTQ   AX, CX
> 0x0029 00041 (main.go:13)   SETEQ   "".~r1+16(SP)
> 0x002e 00046 (main.go:13)   RET
>
> The function bool2int and its condition were effectively optimized away by 
> the Go compiler.  That’s awesome. Good job. It’s a nice trick.
>
>
>
>
> Le samedi 21 novembre 2020 à 11:41:03 UTC+1, aleksey...@gmail.com a écrit :
>>
>> To me your example appears somewhat confusing, int(bool(int())) is the
>> fishiest part IMO. I assume bool(int()) is just (v^v1 != 0) in
>> disguise and this is essentially
>>
>> (v^v1 != 0) & (v^v2 != 0) & (v^v3 != 0)
>>
>> Am i right?
>>
>> Go can't & bools, so
>>
>> func bool2int(b bool) int { // This is what Go compiler can optimize well
>> if b {
>> return 1
>> }
>> return 0
>> }
>>
>> And this leaves us with
>>
>> bool2int(v^v1 != 0) & bool2int(v^v2 != 0) & bool2int(v^v3 != 0)
>>
>> Is that correct?
>>
>> https://godbolt.org/z/jq368G
>>
>> I don't see branching in relevant parts. v == v1 || v == v2 will of
>> course branch because || is a condition.
>>
>> Does that answer your question or maybe I am missing something?
>>
>> пт, 20 нояб. 2020 г. в 11:27, christoph...@gmail.com
>> :
>> >
>> > Go has a strict type separation between int and bool. For a normal usage 
>> > this is OK. I guess it also ease assembly portability because there is not 
>> > always a machine instruction to do so.
>> >
>> > For bit hacking, this is an unfortunate limitation. A handy feature of 
>> > bool <-> int conversion is that true is converted to 1 and any integer 
>> > different of zero to true. As a consequence, when we write int(bool(x)) we 
>> > get 0 when x is 0, and 1 when x is not 0. I checked the math/bits package 
>> > and there is not an equivalent function.
>> >
>> > Is there a way around this that avoids the conditional branching ?
>> >
>> > The use case I have to test if an integer is in a quite small constant set 
>> > of integers. With bool <-> int conversion, we can use binary operation 
>> > like this for instance which would be valid in C
>> >
>> > r := int(bool(v^v1))(bool(v^v2))(bool(v^v3))
>> >
>> > This is to be compared with
>> >
>> > r := v==v1 || v==v2 || v==v3
>> >
>> > The second form is of course more readable, but will also have a 
>> > conditional branch at each ||. If most tested integers are different from 
>> > v1, v2 and v3, the first form seam to me more efficient due to pipelining. 
>> > Though branching prediction can mitigate the penalty.
>> >
>> > The best I could do as valid Go alternative is this
>> >
>> > r := (v^v1)*(v^v2)*(v^v3)
>> >
>> > but the multiplication is obviously not efficient.
>> >
>> > Did I 

Re: [go-nuts] Carting int to bool and the reverse for bit hacking ?

2020-11-21 Thread Aleksey Tulinov
To me your example appears somewhat confusing, int(bool(int())) is the
fishiest part IMO. I assume bool(int()) is just (v^v1 != 0) in
disguise and this is essentially

(v^v1 != 0) & (v^v2 != 0) & (v^v3 != 0)

Am i right?

Go can't & bools, so

func bool2int(b bool) int { // This is what Go compiler can optimize well
  if b {
return 1
  }
  return 0
}

And this leaves us with

bool2int(v^v1 != 0) & bool2int(v^v2 != 0) & bool2int(v^v3 != 0)

Is that correct?

https://godbolt.org/z/jq368G

I don't see branching in relevant parts. v == v1 || v == v2 will of
course branch because || is a condition.

Does that answer your question or maybe I am missing something?

пт, 20 нояб. 2020 г. в 11:27, christoph...@gmail.com
:
>
> Go has a strict type separation between int and bool. For a normal usage this 
> is OK. I guess it also ease assembly portability because there is not always 
> a machine instruction to do so.
>
> For bit hacking, this is an unfortunate limitation. A handy feature of bool 
> <-> int conversion is that true is converted to 1 and any integer different 
> of zero to true. As a consequence, when we write int(bool(x)) we get 0 when x 
> is 0, and 1 when x is not 0. I checked the math/bits package and there is not 
> an equivalent function.
>
> Is there a way around this that avoids the conditional branching ?
>
> The use case I have to test if an integer is in a quite small constant set of 
> integers. With bool <-> int conversion, we can use binary operation like this 
> for instance which would be valid in C
>
> r := int(bool(v^v1))(bool(v^v2))(bool(v^v3))
>
> This is to be compared with
>
> r := v==v1 || v==v2 || v==v3
>
> The second form is of course more readable, but will also have a conditional 
> branch at each ||. If most tested integers are different from v1, v2 and v3, 
> the first form seam to me more efficient due to pipelining. Though branching 
> prediction can mitigate the penalty.
>
> The best I could do as valid Go alternative is this
>
> r := (v^v1)*(v^v2)*(v^v3)
>
> but the multiplication is obviously not efficient.
>
> Did I miss something ?
>
> --
> 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/a2b743d7-011d-481f-9a0f-3f00f4507328n%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+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CAMteYTZDFWgzy6ONxRaUTLJrJo1H0dqeQiqx%2BeKdXcHdQoHEDA%40mail.gmail.com.


Re: [go-nuts] How to drop old value in a channel salety

2020-11-15 Thread Aleksey Tulinov
If you're looking for efficiency, try to sync on a single mutex. The
best kind of syncing is the one that didn't happen, depending on your
circumstances, pthreads mutex can beat channels even taking into
account context switching because syncing on channel isn't free
either.

Implementing thread-safe pops() and pushes() to a channel with
optional blocking and all that stuff is kind of tricky business and
might require extra syncing here and there. If you could decay your
problem to sort of single producer single consumer then one mutex per
consumer might be enough to sync this and the rest of syncing can be
potentially bypassed completely.

Of course this depends on specific implementation under the Go
channels and may change over time, so this is just guessing and actual
performance has to be measured to make any reasonable conclusion.

пн, 16 нояб. 2020 г. в 01:44, 陶青云 :
>
>
> 在2020年11月15日星期日 UTC+8 下午12:19:07 写道:
>>
>> On Sat, Nov 14, 2020 at 7:54 PM Robert Engels  wrote:
>>>
>>> I don’t think a ring buffer works. At least in a traditional ring buffer 
>>> the producer cannot pass the consumer - if the buffer is full the producer 
>>> blocks or drops. Trying to ensure the consumer always reads the most recent 
>>> available item is better (and more simply) served with a shared hand off 
>>> queue.
>>
>>
>> It is trivial to create a ring buffer type that drops the oldest queued item 
>> when appending a new item if the ring is full. Which would seem to be the 
>> behavior the O.P. wants. The important question in this scenario is whether 
>> such an object must be useful in a `select` statement. If not the 
>> implementation is borderline trivial.
>>
> The ring buffer should work, but it seems to need the consumer to test and 
> sleep when the ring is empty, which is not as efficient as a channel.
>
> --
> 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/486267f7-c3fc-4563-814a-1fff54bb2d73n%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+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CAMteYTbJG1_pdHFdHAYnXhvNM4U0kYVcJVE_8o4fH9xghLcuvA%40mail.gmail.com.


Re: [go-nuts] Re: How does the Golang compiler handle dependencies?

2020-11-15 Thread Aleksey Tulinov
Yeah, that's a good point. A C unit that is using f() won't
necessarily include f's implementation if it is defined somewhere
else. It may create a (weak?) reference to f() and leave the rest to
the linker. However to compile correctly it would *normally* include a
header where f() is declared to at least check that f() is accessed
using the correct interface, so f's declaration would normally be
pulled into a unit.

In C++ what to include into a unit and what not to include is a bit
more complicated especially if templates are involved (which is
usually the case), but perhaps such details are out of the scope of
this mailing list.

But yeah, i didn't realize that my email might be misleading in that
regard, sorry about that.

вс, 15 нояб. 2020 г. в 18:19, Robert Engels :
>
> Object files do not contain dependencies except for code that the compiler 
> inlines. It has linkage referees that are resolved during linking.
>
> On Nov 15, 2020, at 8:05 AM, kev kev  wrote:
>
> Reading Alekseys description, it does seem to be making a bit more sense. 
> The C/C++ compilers use a "file" as a compilation unit. A file is converted 
> to an object file which must contain all of its dependencies. So the includes 
> will need to copy all of the code that they are importing into the file that 
> is being compiled.
>
> In Golang, the object file is more of a blackbox which contains only the 
> necessary data that is needed. I'm assuming that "necessary" relates to type 
> checking and symbol resolution mostly.
>
> It seems that one key difference is that Golang uses a package as a 
> compilation unit, while C++ uses a file. If Golang used a file also and not a 
> module structure, then it seems that similar issues or a significant decrease 
> in performance would be observed. You would have more object files for one 
> and there would be more dependencies between files.
>
>
>
> On Saturday, 14 November 2020 at 05:57:27 UTC aleksey...@gmail.com wrote:
>>
>> There is no direct relationship between headers and object files in C
>> or C++. Compilation process is two stage:
>>
>> 1. Source files are compiled into object files
>> 2. Object files are linked together into executable of sorts
>>
>> (Actually it's a three stage process, but i'm going to describe it
>> using two stages).
>>
>> Stages are isolated from each other and to some extent autonomous.
>> Object files are kind of intermediate representation of source code
>> that is later used to produce machine code. I'm sure someone can
>> correct me on this, but for the sake of simplicity, i think it's OK to
>> think of them as of IR.
>>
>> When *compilation unit* is compiled into an object file, it is also
>> separated from other units. To compile it separately from other units
>> all relevant source code has to be pulled into the current unit and
>> compiled. So `#include ` doesn't include just
>> something.h, it includes something.h, then all includes that
>> something.h includes and so on. This is a process similar to
>> amalgamation of source code, everything is copied into one place and
>> then compiled as a single unit. After all units are compiled, they
>> might be joined together by a linker either into a static library,
>> dynamic library or executable.
>>
>> This is actually more sophisticated than that, but it does allow you
>> to do some cool stuff like you can compile your source code into
>> objects, then ship object files and then link them elsewhere. In fact,
>> static libraries are just a bunch of object files packed together, but
>> headers are still required because you need symbol names to refer to
>> on source code level, therefore libraries are shipped with headers:
>> you compile with headers and then link with objects.
>>
>> Since it's the separate stages, you could, for instance, write your
>> own headers for 3rd party objects, think open source headers for
>> closed source DirectX SDK.
>>
>> This description is very superficial and doesn't cover a lot of what
>> is really going on. The process is very flexible and allows to do all
>> kinds of stuff in various combinations. Alas this process is also not
>> very fast and requires some costly steps like you need to pull all
>> required source code into a single unit to compile it.
>>
>> Modern C++ is also using a lot of templates, even if you're not
>> writing templates, you're going to use templates from the standard
>> library and to use templates you need to transform (instantiate) each
>> template into concrete code and then (simply put) compile instantiated
>> template as regular non-templated source code. Because every
>> compilation unit is being "amalgamated", this process has to be
>> repeated for every unit, which also takes some time.
>>
>> There is such thing as C++ modules, but they are quite new
>> (standardized like a month ago) and not yet widespread. I think they
>> should be more similar to Go *packages* when source code files are
>> logically joined into a single entity and for 

Re: [go-nuts] Re: How does the Golang compiler handle dependencies?

2020-11-13 Thread Aleksey Tulinov
There is no direct relationship between headers and object files in C
or C++. Compilation process is two stage:

1. Source files are compiled into object files
2. Object files are linked together into executable of sorts

(Actually it's a three stage process, but i'm going to describe it
using two stages).

Stages are isolated from each other and to some extent autonomous.
Object files are kind of intermediate representation of source code
that is later used to produce machine code. I'm sure someone can
correct me on this, but for the sake of simplicity, i think it's OK to
think of them as of IR.

When *compilation unit* is compiled into an object file, it is also
separated from other units. To compile it separately from other units
all relevant source code has to be pulled into the current unit and
compiled. So `#include ` doesn't include just
something.h, it includes something.h, then all includes that
something.h includes and so on. This is a process similar to
amalgamation of source code, everything is copied into one place and
then compiled as a single unit. After all units are compiled, they
might be joined together by a linker either into a static library,
dynamic library or executable.

This is actually more sophisticated than that, but it does allow you
to do some cool stuff like you can compile your source code into
objects, then ship object files and then link them elsewhere. In fact,
static libraries are just a bunch of object files packed together, but
headers are still required because you need symbol names to refer to
on source code level, therefore libraries are shipped with headers:
you compile with headers and then link with objects.

Since it's the separate stages, you could, for instance, write your
own headers for 3rd party objects, think open source headers for
closed source DirectX SDK.

This description is very superficial and doesn't cover a lot of what
is really going on. The process is very flexible and allows to do all
kinds of stuff in various combinations. Alas this process is also not
very fast and requires some costly steps like you need to pull all
required source code into a single unit to compile it.

Modern C++ is also using a lot of templates, even if you're not
writing templates, you're going to use templates from the standard
library and to use templates you need to transform (instantiate) each
template into concrete code and then (simply put) compile instantiated
template as regular non-templated source code. Because every
compilation unit is being "amalgamated", this process has to be
repeated for every unit, which also takes some time.

There is such thing as C++ modules, but they are quite new
(standardized like a month ago) and not yet widespread. I think they
should be more similar to Go *packages* when source code files are
logically joined into a single entity and for that entity another
intermediate representation is created which is called BMI (binary
module interface) even though it doesn't have to be binary, so
sometimes it's called CMI (compiler module interface).

This CMI is basically a compiler cache, a package, or in terms of C++,
a module interface, can be compiled once and then reused to compile
object files without recompiling the same source code for every unit.

Regarding how packages compilation actually works in Go - this is an
interesting topic. I'm afraid i won't be able to explain it more or
less correctly and i would be glad to read about it too.

сб, 14 нояб. 2020 г. в 04:17, kev kev :
>
>
> Thanks for the answer. If C/C++ has object files, is it not possible to see 
> “something.h” and then fetch the corresponding object file?
>
> With go, if I import “package something” and that package imports another 
> package called “package bar” then at some point I will need to compile “bar” 
> and “something”. This to me is like your header example.
>
>  I think you are maybe saying that this traversal is only done once for 
> golang and the information is stored in an object file? While in C, the 
> header traversal is done each time I see include?
> On Saturday, 14 November 2020 at 00:14:41 UTC Kevin Chowski wrote:
>>
>> C/C++ also has object file caching (depending on how your build is set up, I 
>> guess). In C/C++ the issue is that you need to possibly open a large number 
>> of header files when you import any header file.
>>
>> For example, if I write a file "main.c" which imports "something.h", which 
>> in turn imports "another.h" and "big.h", and compile just main.c, the 
>> compiler has to open all three header files and include them in the parsing 
>> of main.c in order for the compilation to correctly move forward. In Go, the 
>> compiler arranges things such that it only has to open one file per package 
>> that is imported. The post you linked goes into greater detail, so I will 
>> avoid duplicating the details for now, but feel free to ask a more specific 
>> question and I can try to answer.
>>
>> There's a bit of nuance there, 

Re: [go-nuts] How to drop old value in a channel salety

2020-11-13 Thread Aleksey Tulinov
Try to use two channels: one to signal that the receiver needs a new
value and another one to send new value to the receiver. Supposedly
the sender won't block if you're using `select` to check what
receivers need values, and the receiver can block until a new value is
arrived at the input channel.

However as others pointed out, if you're experiencing resistance from
the framework, it might indicate that you are trying to implement some
less than idiomatic approach and perhaps an overhaul of this approach
might be more beneficial.

Hope this helps.

пт, 13 нояб. 2020 г. в 09:12, 陶青云 :
>
>
> It is not a one-length buffered channel.  I need to drop because the 
> recveiver do heavy work that can't process as quickly as sender.
> 在2020年11月13日星期五 UTC+8 下午2:36:13 写道:
>>
>> On Thu, Nov 12, 2020 at 9:32 PM 陶青云  wrote:
>>>
>>> Thanks. I want the receiver always get the relately new vaule,  I don't 
>>> want the sender blocked and I either choose drop the current value or the 
>>> first value of the channel. But I don't find a way to safely drop the first 
>>> value from the channel.
>>
>>
>> You seem to be talking about a buffered channel of length one. If that is 
>> true why are you using a channel? You can instead use a simple var protected 
>> by a mutex. If you're talking about a buffered channel with size greater 
>> than one it is unclear why a full channel should drop the first entry in the 
>> channel rather than multiple (even all) entries in the queue. This seems 
>> like an XY problem.
>>
>>>
>>> Maybe like this ?
>>
>>
>> No, since that "solution" just replaces one race with another.
>>
>> --
>> Kurtis Rader
>> Caretaker of the exceptional canines Junior and Hank
>
> --
> 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/5f5cb0c2-54e9-4d5f-bbc7-43c902615b8fn%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+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CAMteYTbf6Ly-th4KvZcR10xOEKFUPU5tDK44PLTTDwVr6x6vEw%40mail.gmail.com.


Re: [go-nuts] Efficient bitmask twiddling

2020-09-02 Thread Aleksey Tulinov
https://godbolt.org/z/6n7G8q

I'm actually not sure how good this assembly is, it would be
interesting to hear from you, but it looks promising.

вт, 1 сент. 2020 г. в 22:54, Oliver Smith :
>
> In the process of developing a piece of middleware, I need to translate from 
> a bit-array into a bitmask. I am struggling to find a way to express this in 
> go that doesn't result in terrible performance.
>
> The approaches I would try in most other languages were along the lines of:
>
> ```
> mask = (bool1 << bitno1) | (bool2 << bitno2);
> // or
> mask = (bool1 ? value1 : 0) | (bool2 ? value2 : 0);
> ```
>
> but instead, after reading several old (circa 1.5) posts, I'd landed at
>
> ```
> func maskIfTrue(mask uint, predicate bool) uint {
>   if predicate {
> return mask
>   }
>   return 0
> }
>
> mask = maskIfTrue(mask1, bool1) | maskIfTrue(mask2, bool2)
> ```
>
> Here is a (boiled-down & reduced) comparison of the go implementation vs a 
> simple C implementation compiled with -O0 and -Os:
>
> The go version is branch-crazy.
>
> Is there some way I can write this that will produce simpler/efficient code 
> and also not be code salad? I don't have control over the relative ordering 
> of the bools or the bitfield values, and this is a hot path?
>
> Go branchiness:
> ```
> nop
> cmpb1(AX), $0
> jeq featToMask_pc94
> movl$2, DX
> featToMask_pc19:
> nop
> cmpb2(AX), $0
> jeq featToMask_pc90
> movl$4, BX
> featToMask_pc30:
> nop
> ```
>
> The "FeatToMask" C transliteration when compiled with optimization *disabled* 
> (-O0) looks similar, but even -O1 fixes that:
> ```
> FeatToMask:
> mov eax, edi
> movzx   eax, ah
> mov esi, edi
> shr esi, 16
> mov ecx, edi
> shr ecx, 24
> mov rdx, rdi
> shr rdx, 32
> shr rdi, 40
> or  eax, esi
> or  eax, ecx
> or  eax, edx
> or  eax, edi
> movzx   eax, al
> ret
> ```
>
> and with -Os you get down to something better than the naive-C-implementation 
> at the top of the source
>
> ```
> FeatToMask:
> mov QWORD PTR [rsp-8], rdi
> mov al, BYTE PTR [rsp-7]
> or  al, BYTE PTR [rsp-6]
> or  al, BYTE PTR [rsp-5]
> or  eax, DWORD PTR [rsp-4]
> or  al, BYTE PTR [rsp-3]
> movzx   eax, al
> ret
> ```
>
> --
> 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/ea364cef-3998-469c-8742-3bc794733535n%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+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CAMteYTaMuRmdq0%3DGiGXJ%3DYVP%2BcamdCssGwSxAcAubY4T0DOMiw%40mail.gmail.com.


Re: [go-nuts] A question about copying

2020-07-25 Thread Aleksey Tulinov
You are probably thinking about code like this:

var f2 = *f1

Which will make a copy, although not because `f1` is dereferenced, but
because `=` was called on a value.

Dereferencing a pointer gives a reference to the same value, taking
address of the same value will produce a pointer to the same value. So
in expression like this:

var f2 = &(*f1)

`&` and `*` cancel each other out and it can be simplified to:

var f2 = f1

Which means "make a copy of pointer". If you take the address of `f1`
and `f2` you'll see that those are indeed different pointers.

If you're thinking about something like `f(*f1)`, then I believe the
function call will make a copy because arguments are passed by values.
`f(f1)` will make a copy too, but a copy of pointer.

Does that make sense?

сб, 25 июл. 2020 г. в 11:09, chri...@surlykke.dk :
>
> When running this program:
>
> package main
>
> import (
> "fmt"
> )
>
> type Foo struct {
> i int
> }
>
> func main() {
> var f1 = {i: 0}
> var f2 = &(*f1)
> f2.i = 1
> fmt.Println(f1, f2)
> }
>
> it yields:
>
> &{1} &{1}
>
> (https://play.golang.org/p/qKtURokUCEW)
>
> I (naively) assumed that the expression
>
> &(*f1)
>
> would, first, create a copy of *f1, and then a pointer to that copy, but 
> evidently f2 becomes a pointer to the same struct as f1. Is this something I 
> should have deduced from the language spec?
>
> best regards Christian Surlykke
>
>
> --
> 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/f427ddf6-f4fc-42f4-bee8-d1dab0fef566n%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+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CAMteYTa2Qx1Dc0x%2B1iaNi98m6jCKuru2qgBFiHF%3Dik6D65SbMA%40mail.gmail.com.


Re: [go-nuts] [Generics] Feedback on updated draft

2020-07-23 Thread Aleksey Tulinov
Ian,

First of all, thank you for taking your time to answer this topic. I
know some stuff i say is dumb, i appreciate your patience.

To answer your question: i would assume that OR is about as useful as
AND or NOT.

type Constraint interface {
   Sequence && !Channel
}

With that said. So far i'm only a theorist and you are probably the
best expert in this field, so I would rather listen to what you have
to say than express my own ideas, even though they are not really my
own and credit has to go to other people.

I get it, there is a scope for generics and you are asking this
question because there are other considerations about the scope,
usefulness, timeline and this is a problem with more than one factor
and all factors have to be considered. I hope generics version 1 will
be received very well, and I'm actually sure they will.

I absolutely trust your judgement on this matter, of course I don't
have practical experience with generics in Go, but I saw something
that I didn't like. I'll let someone who applied generics in the field
to provide practical feedback and I will be glad to hear that they are
amazing. Sorry for wasting your time. This is undoubtedly an
improvement to the language and it is very needed. Good luck.

>I've tried to outline what we need from generics in
https://blog.golang.org/why-generics.

Right. I must have read this too, but probably a year ago and forgot
about it. This all makes sense now. Thank you very much.

чт, 23 июл. 2020 г. в 09:16, Ian Lance Taylor :
>
> On Wed, Jul 22, 2020 at 9:41 PM Aleksey Tulinov
>  wrote:
> >
> > This is Java-style inheritance. It isn't bad, but i think that
> > C++-style composition is somehow more in the spirit of Go. Strictly
> > personal opinion of course. Older proposal described constraints as
> > expressions, so to me it appears superior because I could potentially
> > write an expression I want without asking for more features to be
> > added into the compiler.
> >
> > Although i'm no longer sure if I understand what Go generics are
> > supposed to do. You have the point that it's probably for a specific
> > purpose, generic types something something, i don't know, but it
> > probably isn't supposed to do what C++ concepts can do. Maybe i'm just
> > spoiled.
> >
> > If this gets us to where we want to be - that's great, I'm happy if
> > you're happy. It just doesn't feel quite right and i feel like this
> > proposal could benefit from discussion on composition and stuff like
> > that.
>
> There is no question that the older syntax was more powerful.  And I
> suspect that your syntax is also more powerful.  But we got extensive
> feedback that the approach was too complex.  C++ and Go have very
> different tolerances for complexity.
>
> You raised the possibility of a constraint that permits either
> constraintA or constraintB.  I think that supporting that kind of
> constraint would be more powerful than what the current design draft
> provides.  But is it a necessary feature?  How often does one want to
> use such a constraint?
>
> I've tried to outline what we need from generics in
> https://blog.golang.org/why-generics.  I think that that describes the
> minimum set of required features for a viable language change.  The
> possibility of alternative constraints is not in that set.  Supporting
> everything we can think of is not a goal.  It's not an inherently bad
> thing.  But anything more powerful than the minimum set has to not
> make the language more complicated to understand.
>
> Within that context, I think it's a great idea to discuss composition
> or inheritance.  If we can come up with something that is more
> powerful and less complex, that would be great.
>
> 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/CAMteYTYWvtfkRo13dfE1XJyWkwK1EKfKRuQP-22dkLbObpMUwg%40mail.gmail.com.


Re: [go-nuts] [Generics] Feedback on updated draft

2020-07-22 Thread Aleksey Tulinov
I'm not sure if i understood everything correctly.

type structField(type T) struct {
a int
x T
}

But this is a generic type, not a constraint for a type, isn't it?
Constraint is this:

type Custom interface{
type int, float64, uint64
}

type structField(type T Custom) interface {
  type struct { a int; x T },
struct { b int; x T },
struct { c int; x T }
}

What am I missing? And I think it rather well highlights what I am
talking about. Consider the following pseudocode:

type ConstraintIWant interface {
  ConstraintA || ConstraintB // i don't care which one, either is fine
}

Maybe i'm looking in the wrong place, but i think that to do this I
have to extract `CommonPart` (`Custom`) from `ConstraintA` and
`ConstraintB`, add `CommonPart` back to both constraints so they
aren't broken and then request `CommonPart` in `ConstraintIWant`.

This is Java-style inheritance. It isn't bad, but i think that
C++-style composition is somehow more in the spirit of Go. Strictly
personal opinion of course. Older proposal described constraints as
expressions, so to me it appears superior because I could potentially
write an expression I want without asking for more features to be
added into the compiler.

Although i'm no longer sure if I understand what Go generics are
supposed to do. You have the point that it's probably for a specific
purpose, generic types something something, i don't know, but it
probably isn't supposed to do what C++ concepts can do. Maybe i'm just
spoiled.

If this gets us to where we want to be - that's great, I'm happy if
you're happy. It just doesn't feel quite right and i feel like this
proposal could benefit from discussion on composition and stuff like
that.

чт, 23 июл. 2020 г. в 06:29, :
>
> Hey! I would like to join the discussion and add my 5 cents here, since I 
> have been criticizing the contracts draft and I would like to show what were 
> my points in order to support the current design draft.
>
>
> I believe the original problem for the generics is to allow the same function 
> to work on values of different types. So that You do not need to write 
> something like AddInt, AddInt32, AddInt64 and so on. This is an example of 
> situation when we would like to write something like Add(T) and make that T 
> to be one of the list: int, int32, int64 - all of the types what we have the 
> Add function defined for.
>
>
> In this case Add(T) acts much like an expression evaluating to a different 
> function depending on the T.
>
>
> This can be called “parametrization by type” or “type parametrization” and I 
> believe it is an exceptionally simple and straightforward way to do it.
>
>
> Let me say a bit more about problems where need of contracts arise.
>
>
> When we are writing in a context of type-parametrized function something like:
>
>
> var a []T = []int{1, 2, 4}
> a[2] = 3
>
>
> It is okay to write []T[2] = T (assign a value of type T to an element of 
> array of type T by index 2) and we do not need to care what is T.
>
>
> But when we change a bit:
>
>
> var a T = []int{1, 2, 4}
> a[2] = 3
>
>
> It becomes hard to judge whether we are allowed to write T[2] = 3 (assign 3 
> to an element of type T by index 2). In order it to work, we need to state 
> somehow [2] is allowed for T. There are a few ways to achieve it and the 
> first one is the contracts:
>
>
> type T interface{
> require(a, b) {
> a[2] = b
> }
> }
>
>
> Okay, now, let’s say, we are allowed to write T[2] = 3. But let’s try a 
> harder example
>
>
> var a T = []int{1, 2, 4}
> a[2] = 3
> a = append(a, 4)
>
>
> This will not work with the previously defined contract T, since a 
> map[int]int value also fits it.
>
>
> Should we write something like this:
>
>
> type T interface{
> require(a, b) {
> a[2] = b
> a = append(a, b)
> }
> }
>
>
> But what is the point in such syntax? How the compiler could guess and how 
> exactly it should work? What if we write random garbage in the require body, 
> will it allow us to write it right in the code without any checks?
>
>
> type T interface{
> require(a, b) {
> a *@#&@#$= b
> }
> }
>
> var a T *@#&@#$= b
>
>
> Of course, we can restrict it to allow using only operators like [], == and 
> so on, still how can we distinguish between a map and an array?
>
>
> type T interface{
> require(a, b, i) {
> a[:] // only arrays and slices have this operator
> i++ // i is an integer
> a[i] = b // b is an element of array a
> }
> }
>
>
> Is this enough to define what we want? Such a contract would also require the 
> append builtin to be changed, but I believe it will only clutter up the 
> implementation with unnecessary type assertions.
>
>
> These “requires” act very much like predicates and are just tricky way to 
> “shortly” define a list of types. That is to say, a++ means any type having a 
> ++ operator defined for it no matter how exactly (which is a problem itself). 
> Anyway, 

Re: [go-nuts] [Generics] Feedback on updated draft

2020-07-22 Thread Aleksey Tulinov
Hmm. I must have read the previous version, but it probably was some
time ago. I have to say that i like the previous version more than the
current one.

I definitely don't like this:

type structField interface {
  type struct { a int; x int },
struct { b int; x float64 },
struct { c int; x uint64 }
}

If this is more readable than `require (a) { a.x++ }`, then i don't
even know what to say. My understanding of readability must be very
different.

I admit that there is a point in those concerns too, it's not
immediately obvious what `require (a) { a.x++ }` is supposed to do.

However the real point is not in a syntax, but in decoupling require
expression from constraint, so it's more generic and extensibleso to
speak. So maybe:

type IncrementX interface {
  require (a) {
evaluates(a.x) && evaluates(a.x++)
   // where evaluates() is defined elsewhere like `require (x) { x }`
  }
}

And type requirement could be `require { type int, int8, int16, int32,
int64 }`? Even though this still doesn't look right to me.

>The objection you mention to the approach used in the current draft is 
>something like: what if Go changes such that operators (other than == and !=) 
>apply to types other than primitive types?  But we're in charge of Go;

Yeah, sure. But there will be some code out there that depends on
existing constraints. If I understand this correctly, `Ordered` in the
current proposal does not define constraint that require operator `<`,
it defines a specific set of types and exploits a side effect that
operator '<' can be applied to every type from this set. This
introduces other side effects, for example, operator `==` is also
defined for all those types, so at least it defines what it wasn't
supposed to define.

I'm not sure if this is OK or not, just saying, but if Go somehow
changes "interface" of types under `Ordered`, then I think `Ordered`
will indirectly change its meaning because it will inherit those
changes even if they are unrelated to operator `<` or ordering in
general. Just wanted to point out that side effects work both ways,
and if those side effects are already exploited in existing Go code,
then it might be harder to change other parts that at first sight are
completely unrelated to what is being changed. Hope this helps.

But I dig the idea of releasing this in parts, i'll be keeping track
of this, this is a much needed feature. Thank you for looking into
this.

чт, 23 июл. 2020 г. в 00:21, Ian Lance Taylor :
>
> On Wed, Jul 22, 2020 at 1:46 PM Aleksey Tulinov
>  wrote:
> >
> > I'm not really a language designer and i don't use Go extensively, so
> > please take my words with a grain of salt. But I like Go and would
> > like to use it, and I'd like to put my 2 cents into the jar. I'm sorry
> > if this was already discussed, I checked the mailing list but didn't
> > find this.
> >
> > I've read the updated draft (sorry i'm late) and the thing that really
> > rubbed me the wrong way was this one:
> >
> > "We need a way to write a constraint that accepts only types that
> > support <. In order to do that, we observe that, aside from two
> > exceptions that we will discuss later, all the arithmetic, comparison,
> > and logical operators defined by the language may only be used with
> > types that are predeclared by the language, or with defined types
> > whose underlying type is one of those predeclared types. That is, the
> > operator < can only be used with a predeclared type such as int or
> > float64, or a defined type whose underlying type is one of those
> > types. Go does not permit using < with a composite type or with an
> > arbitrary defined type."
> >
> > This is a good observation, but what if Go changes in the future and
> > this observation is no longer true?
> >
> > I think I somewhat understand the underlying problem, interface is a
> > concept from the Java world and in Java "everything is object", and
> > classic interface is limited to describing methods, etc etc. But
> > interface is a form of constraint, so it does make a lot of sense to
> > use it as a constraint for generic types. However, I thought that
> > intention was to describe a constraint on objects composition, but
> > instead it describes constraints on object types. This doesn't feel
> > quite right.
> >
> > "If C++ and Java are about type hierarchies and the taxonomy of types,
> > Go is about composition." Am i right?
> >
> > Was it considered to decouple constraints into 1) constraints and 2)
> > constraints requirement expression? Something like this (here and
> > below everything is pseudocode):
> >
> > type comparable interface {
> >   require (a, b) {

[go-nuts] [Generics] Feedback on updated draft

2020-07-22 Thread Aleksey Tulinov
Hi,

I'm not really a language designer and i don't use Go extensively, so
please take my words with a grain of salt. But I like Go and would
like to use it, and I'd like to put my 2 cents into the jar. I'm sorry
if this was already discussed, I checked the mailing list but didn't
find this.

I've read the updated draft (sorry i'm late) and the thing that really
rubbed me the wrong way was this one:

"We need a way to write a constraint that accepts only types that
support <. In order to do that, we observe that, aside from two
exceptions that we will discuss later, all the arithmetic, comparison,
and logical operators defined by the language may only be used with
types that are predeclared by the language, or with defined types
whose underlying type is one of those predeclared types. That is, the
operator < can only be used with a predeclared type such as int or
float64, or a defined type whose underlying type is one of those
types. Go does not permit using < with a composite type or with an
arbitrary defined type."

This is a good observation, but what if Go changes in the future and
this observation is no longer true?

I think I somewhat understand the underlying problem, interface is a
concept from the Java world and in Java "everything is object", and
classic interface is limited to describing methods, etc etc. But
interface is a form of constraint, so it does make a lot of sense to
use it as a constraint for generic types. However, I thought that
intention was to describe a constraint on objects composition, but
instead it describes constraints on object types. This doesn't feel
quite right.

"If C++ and Java are about type hierarchies and the taxonomy of types,
Go is about composition." Am i right?

Was it considered to decouple constraints into 1) constraints and 2)
constraints requirement expression? Something like this (here and
below everything is pseudocode):

type comparable interface {
  require (a, b) {
a < b
  }
}

When constraint is checked, this requirement can be rewritten as a
function for a concrete type, for example, for interface{}:

func comparableRequireInterface(a, b interface{}) {
  _ = (a < b) // this won't compile, as expected, there is no operator
<, requirement isn't satisfied
}

For struct{}:

func comparableRequireStruct(a, b struct{}) {
  _ = (a < b) // this won't compile either
}

For numeric types, specifically for int:

func comparableRequireInt(a, b int) {
  _ = (a < b) // this will compile for other numeric types too
}

Playground link: https://play.golang.org/p/vzk6l7zvBY_J

Note that `require (a, b) { a == b }` will be satisfied for structs,
interfaces, numerics and strings.

This may (or may not) eliminate the need for predeclared `comparable`
constraint and it might (or might not) answer this: "It's not clear
that we fully understand the use of composite types in type lists":

type IncrementX interface {
  require (a) {
a.x++
  }
}

Which can be rewritten for a concrete type:

type ConcreteStruct struct {
  x float64
}

As

func checkIncrementXConcreteStruct(a ConcreteStruct) {
  a.x++ // note that it can not be rewritten to _ = (a.x++)
}

With empty `struct{}` it will give a sensible error message:
"./prog.go:28:3: a.x undefined (type struct {} has no field or method
x)" and it will detect error when ++ can not be applied:
"./prog.go:24:5: invalid operation: a.x++ (non-numeric type string)"

Does any of this make any sense?

P.S. Yeah, it looks like C++, full disclosure, this is why I'm writing
this email, I thought maybe Go could borrow something from there. I
believe GCC 10+ can compile C++ concepts and there is a "playground"
available at godbolt.org.

-- 
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/CAMteYTbyeYKV55dLja%2BYqtGELA_4vh%3DnsvJRuaa6RUoTZ_Nx_A%40mail.gmail.com.