📜 ⬆️ ⬇️

Golang and OOP

If you are still not fed up with posts in the blogosphere on the topic “whether Go is an OOP language”, here's another one. And the short answer is “yes, but that’s not important.”
However, I will try not to dwell on terminology and academic definitions, but to focus on how we do it in Go.



What is OOP?


As a rule, the question of Go's object-orientation comes from the frighteningly popular fallacy “OOP-language must have classes”, which are not known in Go. Slightly deeper thinking leads questioners and respondents to formulations like “if the language supports encapsulation, polymorphism and inheritance, then it is the PLO”, to which Alan Kay, who actually invented the PLO, looks with undisguised incomprehension.

I would venture to suggest that for most readers the canon of OOP language is C ++, about which Alan Kay himself says the following:
I made up the term
')
- Alan Kay, OOPSLA '97

(Video, by the way, is excellent, look, if not yet.)

And immediately, about what was meant by OOP :
OOP is a means of messaging, protection and hysing of state processes, and extreme late binding of all things.


In general, if you delve into the topic, and do not insist that your favorite book on the PLO is the most correct, then the idea was still in transferring the experience of perception of the real world into the code development model. There are objects in the world, objects have properties and behavior, objects can interact. Point. We understand the world in the end. All other definitions and concepts that emerged later are only ways to implement this simple concept.

Go does not like late binding, but loves messaging, and the concept of the “properties and behavior” of objects is implemented perfectly, and this gives reason to call Go a great OO language.

Subjectively - after one and a half years of working with Go, to have a fundamental division into “properties” and “behavior” seems to be the most natural way of representing entities, and one wonders why this did not come to mainstream languages ​​before. Classes with methods and properties in one heap are sincerely inconvenient and old atavism to me now.

OOP by example


Take an example close to life, instead of the usual Dog and Animal) For example, you are Snowden's former partner and write a system that monitors the private information of famous personalities :) You need to get all the messages that mentioned the phrase “if grandma”. Messages can be voice, skype, e-mail, twitter messages or any other.

In class-oriented languages, we would most likely create a MessageSource class with a virtual method, LookupWord (), which would return objects of the Message class. To work with, for example, Twitter or Skype, we would inherit from MessageSource, implement LookupWord () and call class TwitterSource for Twitter, and SkypeSource - for Skype. Habitual and clear to all who are accustomed to classes.

In Go, we can express it more straightforwardly - separately describe the properties, and separately the behavior, and use composition instead of the usual inheritance, which is not in Go.

Structures

We first describe the properties - for this we will create structures containing the necessary fields for the properties of the objects. Structures in Go are the primary way to create your own data types.

type Message struct { Data []byte MimeType string Timestamp time.Time } type TwitterSource struct { Username string } type SkypeSource struct { Login string MSBackdoorKey string } 

Of course, the actual implementation will contain more interesting things, but the idea is clear. Message describes message data, TwitterSource and SkypeSource - data about message sources.

Visibility

In Go, the case of the first letter of the name is used - if the name begins with a capital letter - this is public access, if with a lower case - private. At first, it may seem like an encroachment on the freedom of speech as an inconvenience, but from the first lines on Go, you understand how convenient this solution was.

If we are developing an API and want to hide a field, just call it username instead of Username. And no one forbids us to create getters and setters. In Go, it is customary to use the form X () and SetX () for the getter and setter, respectively.

Interfaces

Now let's do the behavior. The first thing that comes to mind is that the source of the messages should be able to search for words. Excellent, and write:

 // Finder represents any source for words lookup. type Finder interface { Find(word string) ([]Message, error) } 

This is a common practice when an interface with a single method is called the name of this method + 'er': Find - → Finder. Most of the interfaces in Go describe 1-2 methods, not more.

Now, any data type for which the Find () methods with the above signature will be defined will automatically satisfy the Finder interface. Duck typing - if it floats like a duck, looks like a duck, and quacks like a duck - then this is a duck.

Methods

The methods in Go are functions defined for a specific type. You can think of methods as class methods, or you can think of them as ordinary functions with a pointer (or copy) to this / self. The object that will be “this” is indicated in parentheses between the func keyword and the name.

 func (s TwitterSource) Find(word string) ([]Message, error) { return s.searchAPICall(s.Username, word) } func (s SkypeSource) Find(word string) ([]Message, error) { return s.searchSkypeServers(s.MSBackdoorKey, s.Login, word) } 

Just do not use the names this and self - this is unnecessary tracing from other languages, so they don’t write to Go.

Having created these methods, we actually got two objects that can be used as a Finder.

A bit of animation for a change:



Now let's put it all together:

 type Sources []Finder func (s Sources) SearchWords(word string) []Message { var messages []Message for _, source := range s { msgs, err := source.Find(word) if err != nil { fmt.Println("WARNING:", err) continue } messages = append(messages, msgs...) } return messages } 

We have added a new type of Sources - an array of Finders, of everything that can give us the ability to search. The SearchWords () method for this type returns an array of messages.

Literals

In Go, any object can be initialized with a declaration using literals:

 var ( sources = Sources{ TwitterSource{ Username: "@rickhickey", }, SkypeSource{ Login: "rich.hickey", MSBackdoorKey: "12345", }, } person = Person{ FullName: "Rick Hickey", Sources: sources, } ) 


Embedding

Personality, in the NSA view, consists of the name and sources of private information about it. By adding a nameless field of type Sources, we use embedding, which is “embedding”, which, without unnecessary manipulations, allows an object of type Person to directly use the Sources functions:

 type Person struct { FullName string Sources } func main() { msgs := person.SearchWords("  ") fmt.Println(msgs) } 

If we override the SearchWords () method for Person, it will take precedence, but we still have the opportunity to call Sources.SearchWords ().

Conclusion

Now, the output of the program will look something like this:

 $ go run main.go WARNING: NSA cannot read your skype messages ;) [{[82 101 109 101 109 98 101 114 44 32 114 101 109 101 109 98 101 114 44 32 116 104 101 32 102 105 102 116 104 32 111 102 32 78 111 118 101 109 98 101 114 44 32 208 181 209 129 208 187 208 184 32 208 177 209 139 32 208 177 208 176 208 177 209 131 209 136 208 186 208 176 46 46 46] text/plain 2014-11-18 23:00:00 +0000 UTC}] 

This is the standard scheme for the string representation of structures. The standard library makes extensive use of a simple Stringer interface that defines one method, the String () string. Any object that implements this method automatically becomes a Stringer and, when used in standard output functions, will be displayed in the manner that is implemented by this method.

For example:

 func (m Message) String() string { return string(m.Data) + " @ " + m.Timestamp.Format(time.RFC822) } 

Now the output of fmt.Println (msg) will look more pleasant:

 $ go run main.go WARNING: NSA cannot read your skype messages ;) [Remember, remember, the fifth of November,   ... @ 18 Nov 14 23:00 UTC] 


Entire code: play.golang.org/p/PYHwfRmDmK

findings


So is Go an OO language?
Of course, perhaps even one of the most OO-x, in the understanding of Alan Kay.

But even if not, and Alan Kay will not approve the Go approach - what difference does it if OO-design Go delights you and makes it possible to effectively transfer the problem area to the development language?

Keep calm & write you next program in Go.

Source: https://habr.com/ru/post/243593/


All Articles