Why not remove the `recordFactory` type then?

type Record interface {
    Key() string
    Marshal() []byte
    Unmarshal([]byte) error
}

func put[R Record](db *SimpleDatabase,  t UpdateTransaction, v R) error {
    k := v.Key()
    b := v.Marshal()
    if err := db.put(t, k, b); err != nil {
        return fmt.Errorf("db error: %w", err)
    }
    return nil
}

You might need to do the Pointer Receiver Trick (not sure if there's an FAQ
entry to link to here, so I'll just link to my not super great talk
<https://youtu.be/QP6v-Q5Foek?t=2718> explaining it) to implement get, i.e.:

type Record[T any] interface {
    *T
    Key() string
    Marshal() []byte
    Unmarshal([]byte) error
}

func get[R any, PR[R]](db *SimpleDatabase, t ViewTransaction) (R, error) {
    var r R
    k := PR(&r).Key()
    b, err := db.get(t, k)
    if err != nil {
        return r, err
    }
    err = PR(&r).Unmarshal(b)
    return r, err
}

(Note: This assumes that the `Key() string` method is still stateless, but
ISTM your factory type assumes that as well?)

On Fri, Jul 28, 2023 at 10:48 AM Salvatore Domenick Desiano <
neard...@gmail.com> wrote:

> I guess I didn't ask an actual question... is there a more idiomatic way
> of doing this?
>
> Thank you!
>
> -- Salvatore
> smile.
>
>
> On Monday, July 24, 2023 at 4:00:59 PM UTC-4 Salvatore Domenick Desiano
> wrote:
>
>> Ever since 1.18 came out I've been struggling to find an idiomatic way to
>> implement a certain kind of adapter. I'm starting to suspect I'm Holding It
>> Wrong (TM) so here I am.
>>
>> In short, I have an adapter that is effectively a collection of static
>> methods and it doesn't look right.
>>
>> Imagine you have a generic key-value database (transaction and life-cycle
>> methods omitted for brevity):
>>
>> type SimpleDatabase interface {
>> Get(t ViewTransaction, key string) ([]byte, bool, error)
>> Put(t UpdateTransaction, key string, value []byte) error
>> }
>>
>> You then want to build something more specific on top using generics to
>> avoid repetition of tricky code:
>>
>> type ApplicationDatabase struct {
>>   impl *SimpleDatabase
>> }
>>
>> func (db *ApplicationDatabase) PutProjectRecord(t UpdateTransaction, r
>> *ProjectRecord) error {
>>   return put[ProjectRecord](db.impl, projectRecordFactory, t, r)
>> }
>>
>> type recordFactory[V any] interface {
>>   dbKey(value V) string
>>   encodeValue(value V) []byte
>>   decodeValue(data []byte) (V, error)
>> }
>>
>> func put[V any](db *SimpleDatabase, f *recordFactory[V], t
>> UpdateTransaction, value V) error {
>>   key := f.dbKey(value)
>>   valueBytes := f.encodeValue(value)
>>   if err := db.put(t, key, valueBytes); err != nil
>>     return fmt.Errorf("db error: %w", err)
>>   }
>>   return nil
>> }
>>
>> This is nice and clean -- adding a new record type is just a matter of
>> adding a new recordFactory implementation. Adding more complexity to the
>> put/get (recovery, etc.) only has to happen once. The part that bugs me,
>> though, is that the implementation has no state and really looks like it
>> shouldn't be instantiated:
>>
>> type projectRecordFactory struct{}
>> func (f *projectRecordFactory) dbKey() string { return .... }
>> func (f *projectRecordFactory) encodeValue(value V) []byte {
>> json.Marshal(...) }
>> func (f *projectRecordFactory) decodeValue(data []byte) (V, error) {
>> json.Unmarshal(...) }
>>
>> and, frankly, if I didn't instantiate it, it would feel like either Java
>> or C++ metaprogramming.
>>
>> I'm open to a completely different structure but I am really hoping to
>> add new record types by adding a new package or type.
>>
>> Thanks!
>>
>> -- Salvatore
>> smile.
>>
>> --
> 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/318e98c2-d13e-4188-b65b-bbc7644e3ab7n%40googlegroups.com
> <https://groups.google.com/d/msgid/golang-nuts/318e98c2-d13e-4188-b65b-bbc7644e3ab7n%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 on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CAEkBMfFLJYt9N8fvMALfthk-s7q2WTE3yKx95u7puwDEfA5p5g%40mail.gmail.com.

Reply via email to