4 ms·
Slightly OT: I like Go, but the "-er" convention, while useful, has always bothered me because of the following inconsistency, well illustrated by two examples
by jonahx 3y ago
Slightly OT: I like Go, but the "-er" convention, while useful, has always bothered me because of the following inconsistency, well illustrated by two examples from the article:
Writers write.
Readers read.
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
In a Go interface, a reader doesn't read: a reader gets read from. The reader (in the English language sense) is the client code of the Reader interface (in the Go sense).
That said, I find the Java "-able" convention even uglier, though it answers my complaint.
- deleted 3y ago[deleted]
- tareqak 3y agoWhy not use both? -er’s do stuff to things while -able’s get stuff done to them and use them as it make sense. Use the one that makes the most sense given the situation.
- jonahx 3y agoYou could, but this is not Go's convention. Go's convention is that when you have an interface with a single method "x", you name the interface "xer". This has the advantage of being simple and mnemonic. It has the downside I already mentioned.
- taeric 3y agoWorks if you consider the reader is what you use to do the reading. You have a source you want to read, so you get a reader that can do that. Literally, you get a reader when you want to read something. You get a writer when you want to write something. Though, beware thinking you can solve this with word choice.
- jonahx 3y ago> Works if you consider the reader is what you use to do the reading. You have a source you want to read, so you get a reader that can do that. This strains ordinary language imo: Say you have a "log" which implements the Reader interface. When I call "log.read()" surely we are reading from the log, no? The log itself isn't the reader. This matches everyday usage. Perhaps your argument is that you can envisage the "log" object as an abstract "reader" of the bytes on disk, or something like that -- so the mental model is not a "log being read from" but instead "bytes on disk, an object able to read them (the Reader), and the code using that object to do the reading". In this worldview one never does anything oneself, but always uses a tool to do that thing -- the "-er" tool. I dislike this as it introduces an unnecessary layer of abstraction, but I grant it resolves the issue consistently. Also in this conception now I have a variable named "log" which does not represent the log but "a reader of the log". So you have to either ignore that inconsistency or name the variable "logReader", which introduces extra verboseness everywhere. The other resolution is simply to say this is a programming language, not ordinary language, and we decided that having a consistent, mnemonic way to name one method interfaces was more important than respecting natural language analogies. So f it, we're using "-er" to mean "-able". I would be curious to know what the actual conversation was during the development of Go.
- taeric 3y agoBut odds are high your code isn't reading from any device. It is literally using a "reader of ___" to get the data read into a buffer that your code will process. So, still seems to work for me.
- jonahx 3y agoTypically you are reading from a file, or the network. someFile.read(dest) network.read(dest) I'm reading from a file or network in both cases. You can say you're using "the reader" to read, but as I said it a) introduces an unnecessary concept, b) is not how we naturally talk, and c) does not fit with the variable names (unless you want append "Reader" to all of them, which I think is ugly and bloated.) It's not the worst thing in the world, and I understand the benefits of the choice, but still it slightly grates on me.
- jiggawatts 3y agoA diagram that made things click for me is putting different abstractions on a grid showing the different combinations of high level contracts they fulfil. Every combination of push/pull, read/write, and sync/async can exist and makes sense. The Go interface is “sync pull read” which is “Readable”. Then “Reader” is “sync push read”, etc… Another axis is “single item”, “sequence of items”, or “contiguous array chunks of items”. These are “property”, “iterator”, and “stream” respectively of synchronous. They’re “task”, “asynchronous iterator”, and “async stream” if non-blocking. Etc…
- paulddraper 3y agoThe Reader is doing the reading. reader.Read(p); // reader, please read into this array The caller is obtaining the result of the read operation. --- What mows a lawn? A person, or machinery? In English, either can be referred to as a "lawn mover." However, most often "lawn mower" has the most direct meaning: the machine.
- jonahx 3y agoSee my reply here for the problems with that: https://news.ycombinator.com/item?id=36926392 https://news.ycombinator.com/item?id=36926392 EDIT: To elaborate my reply there tailored to your lawn mower example... > What mows a lawn? A person, or machinery? Yes, in this case the tool analogy matches real life (and your interpretation of Go interfaces as tools): I use a lawn mower to mow the lawn. My issue is that there isn't always a tool, but the Go worldview forces there to be one: What reads a book? A person, or a ...?
- mannschott 3y agoI've always suspected that 'Reader' and 'Writer' were names borrowed from Oberon since that's one of the influences that contributed to early Go design: https://github.com/Project-Oberon/Source-Code/blob/cf7f6a6cda1c5e58299726ec578ffde76ce8a6bf/CERES%20Oberon%20V2/ASCII/Texts.Mod.txt#L74 https://github.com/Project-Oberon/Source-Code/blob/cf7f6a6cd... Please enjoy this microdose of historical trivia even though it doesn't answer the question of why those names were chosen (when designing Oberon).
- gabereiser 3y agoIn defense of Go “er” structure. It’s written this way because you, as the caller, are the reader. It’s almost an Actor pattern, almost… but it definitely takes the side of “when using this interface, what am I?” mentality. Once you realize the API’s were designed for you, the consumer, and not the provider, you appreciate it much more.
- layer8 3y agoJava has Reader and Writer as well, and I agree with your critique of that naming.
- naasking 3y ago> In a Go interface, a reader doesn't read: a reader gets read from. It's both. The Reader is reading from an underlying type.