36

I'll just post my code:

/*
*  Role will ALWAYS reserve the session key "role".
 */
package goserver

const (
    ROLE_KEY string = "role"
)

type Role string

//if index is higher or equal than role, will pass
type RolesHierarchy []Role

func (r Role) String() string {
    return string(r)
}

func NewRole(session ServerSession) Role {
    return session.GetValue(ROLE_KEY).(Role)
}

func (this Role) IsRole(role Role, hierarchy RolesHierarchy) bool {
    if role == this {
        return true
    }
    if len(hierarchy) == 0 {
        return false
    }
    var thisI int = 0
    var roleI int = 0
    //Duped roles in hierarchy are verified in verifyConfig during parse
    for i, r := range hierarchy {
        if this == r {
            thisI = i
        }
        if role == r {
            roleI = i
        }
    }
    //TODO I can probably condense what follows into one if
    if thisI == 0 && roleI == 0 {
        return false
    }
    return thisI >= roleI
}

func (this *Role) AssumeRole(session ServerSession, role Role) {
    session.SetValue(ROLE_KEY, role)
    *this = role
}

It should be noted that ServerSession is also an interface, calling "ServerSessioner" just feels wonky to me.

I'm toying with the idea of creating an interface with IsRole() and AssumeRole(), however "Roler" seems very wonky. It's dawning on me that I don't really know or have ever come across naming conventions for interfaces, other than the standard "er" suffix. I do seem to recall the VS C++ convention is to just throw an "I" in front of everything. Is this "idiomatic"?

Any suggestions?

icza
  • 389,944
  • 63
  • 907
  • 827
Dale
  • 1,220
  • 2
  • 10
  • 20
  • 1
    I would just call it `RoleSupport` but reaching for English.SE would be an interesting endeavor indeed. Please consider not using `this` to name method receivers: this is frowned upon as being unidiomatic Go. [One example](http://stackoverflow.com/q/23482068/720999) of discussing these matters. – kostix Aug 09 '16 at 06:21
  • Yeah, I've been struggling with receiver names. I know the go idiom is to use single letter variables....I'm sorry, I can't do that. "this" or "self" are so prevalent in any other language it disambiguates meaning. "RoleSupport" is ok, but doesn't really fit a neat pattern. – Dale Aug 09 '16 at 06:27
  • 1
    Not single letters but rather meaningful abbreviations -- with single letters being OK for short functions (yours included). "Any other language" is a gross exaggregation for sure. Well, for some reason this is not a problem for me: different languages just *feel* differently. Novice programmers indeed try hard to be one-trick dogs trying to carry their set of learned skills into any new language they face (been there myself for sure) but it's always better to understand the philosophy behind the language and stick to it. – kostix Aug 09 '16 at 08:09
  • 1
    At least this lowers the WTF factor for the next programmer dealing with your code. ;-) – kostix Aug 09 '16 at 08:09
  • 2
    WTF factor, "this" or "self" is "idiomatic" in at least half a dozen languages I "know" – Dale Aug 09 '16 at 08:53
  • 3
    @Dale It's not in Go, see: [In Go is naming the receiver variable 'self' misleading or good practise?](http://stackoverflow.com/questions/23482068/in-go-is-naming-the-receiver-variable-self-misleading-or-good-practise) – icza Aug 09 '16 at 09:00
  • I've refactored this project to not include this or self. https://play.golang.org/p/hGDELp3OBA is pretty cool. IIRC the first thing pushed onto a stack in a function call in C++ is a reference to "this" followed by the function parameters. "this" can be thought of as an implicit first parameter, I'm glad to see this happening here. This is not unlike python where they just removed the implicit part. I'm still not entirely convinced given what I know so far, but I'm ignorant, so I'll go along. – Dale Aug 11 '16 at 05:11

3 Answers3

50

In your case I would just name them RoleChecker and RoleAssumer, the "merged" one RoleCheckerAssumer. Or if you'd go with a single interface, that could be RoleHelper or RoleChecker.

ServerSession is also fine, or even just Session (especially if there is no "client" session). ServerSessioner on the other hand is bad, Session is not a verb and not a method of the interface.


There has been many posts about the conventions.

Effective Go: Interface names:

By convention, one-method interfaces are named by the method name plus an -er suffix or similar modification to construct an agent noun: Reader, Writer, Formatter, CloseNotifier etc.

There are a number of such names and it's productive to honor them and the function names they capture. Read, Write, Close, Flush, String and so on have canonical signatures and meanings. To avoid confusion, don't give your method one of those names unless it has the same signature and meaning. Conversely, if your type implements a method with the same meaning as a method on a well-known type, give it the same name and signature; call your string-converter method String not ToString.

Interface Types @ What's in a name? - Talks at golang.org

Interfaces that specify just one method are usually just that function name with 'er' appended to it.

type Reader interface {
    Read(p []byte) (n int, err error)
}

Sometimes the result isn't correct English, but we do it anyway:

type Execer interface {
    Exec(query string, args []Value) (Result, error)
}

Sometimes we use English to make it nicer:

type ByteReader interface {
    ReadByte() (c byte, err error)
}

When an interface includes multiple methods, choose a name that accurately describes its purpose (examples: net.Conn, http.ResponseWriter, io.ReadWriter).

For receiver names, don't use this or self or similar ones. Instead:

Receivers @ What's in a name? - Talks at golang.org

Receivers are a special kind of argument.

By convention, they are one or two characters that reflect the receiver type, because they typically appear on almost every line:

func (b *Buffer) Read(p []byte) (n int, err error)

func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request)

func (r Rectangle) Size() Point

Receiver names should be consistent across a type's methods. (Don't use r in one method and rdr in another.)

Go Code Review Comments: Receiver Names:

The name of a method's receiver should be a reflection of its identity; often a one or two letter abbreviation of its type suffices (such as "c" or "cl" for "Client"). Don't use generic names such as "me", "this" or "self", identifiers typical of object-oriented languages that place more emphasis on methods as opposed to functions. The name need not be as descriptive as that of a method argument, as its role is obvious and serves no documentary purpose. It can be very short as it will appear on almost every line of every method of the type; familiarity admits brevity. Be consistent, too: if you call the receiver "c" in one method, don't call it "cl" in another.

icza
  • 389,944
  • 63
  • 907
  • 827
  • 2
    Single method interfaces are "easier". The "Is()" was throwing me off. I ended up just using "checker()". Yeah, sorry, not going to use single or two letter identifiers. I don't care what is idiomatic here. I know half a dozen languages that use this or self, why would I break convention here simply because some doc in a language spec says I should? This or self is exactly what I mean and what I want. At the end of the day, I need to read my code, and if I'm rummaging through my speghetti for some single letter identifier, what is the point? – Dale Aug 09 '16 at 08:52
  • 4
    @Dale You do whatever you want. No one will force you to do anything. And as long as you code "alone" it won't bother anyone else. But if you want to work with others, or others have to work with your code, you need to speak a "common" language. Regarding `this` and `self` as the method receiver: [In Go is naming the receiver variable 'self' misleading or good practise?](http://stackoverflow.com/questions/23482068/in-go-is-naming-the-receiver-variable-self-misleading-or-good-practise) – icza Aug 09 '16 at 08:59
  • 1
    Thank you. I don't want to be argumentative. I do plan on open sourcing this heap. Perhaps feedback will force me to rethink my decision. I'm still not convinced of the designers' decisions here. That being said, just about everything else I've seen in Go has been very impressive. – Dale Aug 09 '16 at 09:04
4

I got it, turns out I can use the "er" convention.

/*
*  Role will ALWAYS reserve the session key "role".
 */
package goserver

const (
    ROLE_KEY string = "role"
)

type Role string

//if index is higher or equal than role, will pass
type RolesHierarchy []Role

type RoleChecker interface {
    IsRole(Role, RolesHierarchy) bool
}

type RoleAssumer interface {
    AssumeRole(ServerSession, Role)
}

type RoleCheckerAssumer interface {
    RoleChecker
    RoleAssumer
}

func (r Role) String() string {
    return string(r)
}

func NewRole(session ServerSession) Role {
    return session.GetValue(ROLE_KEY).(Role)
}

func (this Role) IsRole(role Role, hierarchy RolesHierarchy) bool {
    if role == this {
        return true
    }
    if len(hierarchy) == 0 {
        return false
    }
    var thisI int = 0
    var roleI int = 0
    //Duped roles in hierarchy are verified in verifyConfig during parse
    for i, r := range hierarchy {
        if this == r {
            thisI = i
        }
        if role == r {
            roleI = i
        }
    }
    //TODO I can probably condense what follows into one if
    if thisI == 0 && roleI == 0 {
        return false
    }
    return thisI >= roleI
}

func (this *Role) AssumeRole(session ServerSession, role Role) {
   session.SetValue(ROLE_KEY, role)
   *this = role
}

Thank you Sarathsp for getting me thinking about this properly.

Dale
  • 1,220
  • 2
  • 10
  • 20
3

In golang, by convention, one-method interface names are nouns denoting the doer of an action. For example:

the `Read` method implements the `Reader` interface, and
the `Generate` method implements the `Generator` interface.

It would be best to make the specifics of the convention clear, regardless of what they are. This goes good when there is only one function or a very specific set of functions are required by the interface.

There is a practise of using I prefix to Lowest Common Denominator of the functions, in this case IRole would be a better interface name as the interface defines two functions that has to be satisfied by all the types representing Role.

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
  • IsRoler and AssumeRoler -> IsserAssumer? lol, this might be better in the english stack exchange.... – Dale Aug 09 '16 at 06:01
  • @Dale https://talks.golang.org/2014/names.slide#14 => Sometimes the result isn't correct English, but we do it anyway: – Sarath Sadasivan Pillai Jan 27 '17 at 03:01
  • @SarathSadasivanPillai.. let me try to understand... if i bring into this context an struct (That is the data structure that is associated with a method), i would rather say "any struct implementing the method 'Read' becomes a Reader", that has sense?; an let me add another quick question here: what would be the name for a struct that is used as source of read? "Sourcer"??, (I know that it would be "Readable" in Java!) – Victor Jul 24 '18 at 22:27
  • @Victor interface name depends on the functions it implements – Sarath Sadasivan Pillai Jul 26 '18 at 00:44
  • @SarathSadasivanPillai, i thing i get it. The think is that for some reason my OO based mind (after years in JAVA) still keep me saying that interfaces describes objects (of a same kind) behaviour, and interfaces in go describies object behaviour too. Both ways are for describing a methods (1 or many) with an object, we agree on that?. Guess in JAVA you are looking for a *word* describing what a client can DO with the object (things that the object can be "tell" to do), and in GOLANG the word is solely related to what the object can DO. That strive me to the question of Sourcer/Readable. – Victor Jul 27 '18 at 13:46