18

I am using Gorp for database access, Gorp has a standard DbMap type, as well as a Transaction type for when you want to be able to roll back. Both types implement the SqlExecutor interface.

I am therefore programming against the SqlExecutor interface, so I can use transactions if I want without needing to change my code.

I then initialise a Gorp DbMap or Transaction and pass it in as a field property. The problem is that I need a pointer to the Gorp "object", else how will I be able to roll back if I use a Transaction if the Gorp "object" is passed by value instead of reference.

I then get a message such as

r.Gorp.Get undefined (type *gorp.SqlExecutor has no field or method Get)

when I try use my code. How do I call the methods?

A code sample is below.

package repositories

import (
    "github.com/coopernurse/gorp"
)


type Repository struct {
    Gorp *gorp.SqlExecutor // <<<< Need pointer so I can rollback
}

func (r *Repository) GetById(i interface{}, key interface{}) interface{} {
    obj, err := r.Gorp.Get(i, key)
    if err != nil {
        panic(err)
    }
    return obj
}
0

2 Answers 2

22

Maybe you are overthinking the problem, or you may still be under a "call by reference" influence from another language:

  1. gorp.SqlExecutor is an interface and you will never use a pointer to an interface value. Never ever. (Technically this is untrue, but if you actually need a pointer to an interface, you will have mastered Go enough to understand why "never ever" is a really good advice.)
  2. Never think about "call by reference". There is no such thing in Go. Passing a pointer to a function is not "call by reference". Leave that behind.

I assume you did not try to use transactions and do rollbacks on the non-pointer-to-interface code?

Background: In Go, you pass around a pointer to something because of two reasons:

1) You want to, because your struct is really large and you want to avoid copying, or

2) you need to, because the callee wants to modify the original (this is typical for methods with a pointer receiver).

Now an interface value is really tiny (just two words) so reason 1, to pass a pointer to an interface value, does not apply. Reason 2 does not apply in most cases as passing a pointer to an interface value will allow you to change the interface value itself, but most often you would like to modify the value stored inside the interface value. This value stored inside the interface value often is a pointer value which allows to change the value of a struct by calling methods on an interface value which wraps a pointer to this struct. This sounds complicated but isn't: The novice Go programmer just doesn't use pointers to interfaces (as this won't do any good) and the experienced Go programmer doesn't use pointers to interfaces (as it won't do much good) unless he needs to modify an interface value, typically during reflection.

Sign up to request clarification or add additional context in comments.

6 Comments

I now pass in a non-pointer to the interface, and I get this message: cannot use gorp (type gorp.DbMap) as type gorp.SqlExecutor in assignment: gorp.DbMap does not implement gorp.SqlExecutor (Delete method has pointer receiver)
My delete looks like this func (r *Repository) Delete(list ...interface{}) int64 { count, err := r.Gorp.Delete(list...) if err != nil { panic(err) } return count }
This answer is useless as it neither explains why not to use pointers nor suggests the alternatives.
"Passing a pointer to a function is not "call by reference". Leave that behind." Contradicted by "you pass around a pointer to something because of two reasons: 1) You want to, because your struct is really large and you want to avoid copying" (How can you do that without PASSING A REFERENCE is beyond me indeed!)
@Adonis A pointer is not a "reference" (PL technical term). The technical term "reference" has technical meaning not covered by the colloquial english word "reference". I'm not talking english here but PL technical jargon. If you pass a pointer you pass a value, not a reference (technical term). Of course pointers are references (english, colloquial meaning). But this is Stack Overflow, not English 101.
|
9
  1. gorp.SqlExecutor is an interface and you will never use a pointer to an interface value. Never ever.

  2. If this is your goal, you're going about it incorrectly. An interface is a wrapper, and a contract that guarantees behavior. If your interface requires that the methods mutate the implementing type, then the implementing type should be a pointer. A pointer to the interface itself will not suddenly make the implementing type mutable.

  3. Your struct should be

    type Repository struct {
        Gorp gorp.SqlExecutor 
    }
    
    
    func (r *Repository) GetById(i interface{}, key interface{}) interface{} {
        obj, err := r.Gorp.(gorp.SqlExecutor).Get(i, key)
        if err != nil {
            panic(err)
        }
        return obj
    }
    

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.