Now that I think about it again - I guess your suggestion could work for my case with some caveats:
1. There can be contention on the map - but as you point out there is sync.Map as well 2. The state should be removed from the map but that can also be arranged by deferring a delete operation 3. If contention is indeed a problem I can mitigate by sharding the map 4. If contention continues to be a problem perhaps weak pointers with this recipe https://github.com/golang/go/issues/67552#issuecomment-2195479919 may help. It won't be pretty but hey - help beggars can't be choosers! Kind regards: al_shopov На пн, 12.05.2025 г. в 17:22 Jason E. Aten <j.e.a...@gmail.com> написа: > Forgive me if this off base, as I'm still a little fuzzy on the exact > constraints > of you problem... but, as stated, if you want > to associate additional optional behavior and state with any given response > that is constrained to the generated, just use > the responses's pointer (to its struct) (if local an ephemeral is all you > need, or a cryptographic hash of > its contents, if you need to survive reboots) as the key into a separate > map/sync.Map/ > database. Standard Go does not move pointers; the GC is a non-moving > collector > by intent to enable sane interfacing with C code, and does very well at > avoiding > fragmentation (the motivation for compaction/copying GC) by using > size classes instead. Since you can rely on the pointer not moving, just > use it as a key to a map[*generated.Response]*EnrichedResponse to > lookup your additional state on either the caller or responder side. > > On Monday, May 12, 2025 at 1:12:25 PM UTC+1 Alexander Shopov wrote: > >> seems a very common assumption >> >> >> I would have guessed it is due to compatibility with C but >> https://pkg.go.dev/cmd/cgo#hdr-C_references_to_Go explicitly states: >> *Go struct types are not supported; use a C struct type. * >> So it may be completely at the decision of the implementer. >> The caveats in https://go.dev/wiki/cgo#common-pitfalls also sound too >> tricky. >> >> The pointer to the entire value stays alive while any pointer to one of >> its fields is alive >> >> That requires some cooperation from the GC. In the case where structs are >> reasonably small and they contain values rather than pointers this would >> probably hold. >> >> Thanx for even further details (I am writing down the offset trick) but >> I'd prefer to not stray too far away from usual conventions. >> >> Kind regards: >> al_shopov >> >> >> На пн, 12.05.2025 г. в 12:14 Axel Wagner <axel.wa...@googlemail.com> >> написа: >> >>> >>> >>> On Mon, 12 May 2025 at 11:12, Alexander Shopov <a...@kambanaria.org> >>> wrote: >>> >>>> Is the equality of pointer to struct and pointer to its first member >>>> actually always guaranteed by Go lang? >>>> https://go.dev/ref/spec#Package_unsafe says The effect of converting >>>> between Pointer and uintptr is implementation-defined but I guess it >>>> is not the same thing. The sections on Struct types and Alignment do not >>>> give such guarantees. >>>> >>> >>> Perhaps not, though it seems a very common assumption and if an >>> implementation violates it, I would expect that to break a bunch of code. >>> You can always make sure, by accounting for a potential offset: >>> https://go.dev/play/p/whdFALRG20P >>> I guess that still makes the assumption, that a pointer to the entire >>> value stays alive while any pointer to one of its field is alive. I'm not >>> sure *that* is guaranteed either, but at least it's a weaker assumption. >>> >>> >>>> In the end it is not wise to use such a technique on a large code base >>>> shared by many developers. I will not be going this way but many thanx for >>>> the example it taught me something I did not know. >>>> >>>> Axel, you may use it for a 2nd part of Advanced Generics Patterns (nice >>>> presentation! I liked it) - Advanced Type Patterns (use types wrongly so we >>>> can learn how to make the wrong way the right way). >>>> >>>> >>>> I was hoping that there is a trick that I am missing. Like - a returned >>>> function can access state in a closure but I see no way to do it for >>>> methods. I definitely do not want to go the direction - since I want to add >>>> a method I should change the code generation, types (struct vs >>>> interface-s) to suit that small change. >>>> >>>> Kind regards: >>>> al_shopov >>>> >>>> На пн, 12.05.2025 г. в 7:12 Axel Wagner <axel.wa...@googlemail.com> >>>> написа: >>>> >>>>> On Mon, 12 May 2025 at 07:05, Axel Wagner <axel.wa...@googlemail.com> >>>>> wrote: >>>>> >>>>>> A less evil, but still bad way, would be to store it in a global map: >>>>>> https://go.dev/play/p/ZHBJVCduf25 (note: I'm not sure this use of >>>>>> weak pointers is actually correct, I haven't used them yet). >>>>>> >>>>> >>>>> Okay, I'm pretty sure it's not correct. It should be possible to make >>>>> this work somehow, but I'm a bit too lazy to try right now, especially as >>>>> you shouldn't do it anyways. >>>>> >>>>> >>>>>> Otherwise, no. The state has to live somewhere. And really, both of >>>>>> these tricks are still really bad and you shouldn't do them. The best way >>>>>> is to respect the type system and if you want extra methods, you need a >>>>>> new >>>>>> type and if that needs extra state, that should be stored in the type. >>>>>> >>>>>> ----- >>>>>>> Why would I want to do this? What am I trying to achieve? >>>>>>> >>>>>>> Basically there is a lot of generated code and I want to keep >>>>>>> compatibility with it. >>>>>>> Similar to the way Go embeds wider interfaces into narrower ones I >>>>>>> want to be able to add methods to the generated code without having to >>>>>>> change it. >>>>>> >>>>>> >>>>>> Change the code generator, and/or add additional code in an extra >>>>>> file. Hacking the language will cause you more pain, in the long run. >>>>>> >>>>>> >>>>>>> Then - whenever some code calls the *Get* method on the server - >>>>>>> based on the whether the returned value implements the *Enriched* >>>>>>> interface or not and the value it returns - I can dispatch behavior. >>>>>>> >>>>>>> Kind regards: >>>>>>> al_shopov >>>>>>> >>>>>>> -- >>>>>>> You received this message because you are subscribed to the Google >>>>>>> Groups "golang-nuts" group. >>>>>>> To unsubscribe from this group and stop receiving emails from it, >>>>>>> send an email to golang-nuts...@googlegroups.com. >>>>>>> To view this discussion visit >>>>>>> https://groups.google.com/d/msgid/golang-nuts/bbe6bcd8-e33c-41bf-868a-e498561c3e72n%40googlegroups.com >>>>>>> <https://groups.google.com/d/msgid/golang-nuts/bbe6bcd8-e33c-41bf-868a-e498561c3e72n%40googlegroups.com?utm_medium=email&utm_source=footer> >>>>>>> . >>>>>>> >>>>>> -- > You received this message because you are subscribed to a topic in the > Google Groups "golang-nuts" group. > To unsubscribe from this topic, visit > https://groups.google.com/d/topic/golang-nuts/5gx3CCMfyJg/unsubscribe. > To unsubscribe from this group and all its topics, send an email to > golang-nuts+unsubscr...@googlegroups.com. > To view this discussion visit > https://groups.google.com/d/msgid/golang-nuts/e823a08d-11c3-49d0-bd24-89eef57efc0an%40googlegroups.com > <https://groups.google.com/d/msgid/golang-nuts/e823a08d-11c3-49d0-bd24-89eef57efc0an%40googlegroups.com?utm_medium=email&utm_source=footer> > . > -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion visit https://groups.google.com/d/msgid/golang-nuts/CAP6f5MmNXt-AuUPA4XGc1ZbbYqaMibtdzcxikx04KWNUpy21nA%40mail.gmail.com.