go for object oriented programmers or object oriented programming without objects
DESCRIPTION
Object Oriented (OO) programming has dominated software engineering for the last two decades. The paradigm built on powerful concepts such as Encapsulation, Inheritance, and Polymoprhism has been internalized by the majority of software engineers. Although Go is not OO in the strict sense, we can continue to leverage the skills we’ve honed as OO engineers to come up with simple and solid designs. Gopher Steve Francia, Author of [Hugo](http://hugo.spf13.com), [Cobra](http://github.com/spf13/cobra), and many other popular Go packages makes these difficult concepts accessible for everyone. If you’re a OO programmer, especially one with a background with dynamic languages and are curious about go then this talk is for you. We will cover everything you need to know to leverage your existing skills and quickly start coding in go including: How to use our Object Oriented programming fundamentals in go Static and pseudo dynamic typing in go Building fluent interfaces in go Using go interfaces and duck typing to simplify architecture Common mistakes made by those coming to go from other OO languages (Ruby, Python, Javascript, etc.), Principles of good design in go.TRANSCRIPT
Go for Object Oriented Programmers
!
or !
Object Oriented Programming Without Objects
• Author of Hugo, Cobra, Viper & More
• Chief Developer Advocate for MongoDB
• Gopher
@spf13
— txxxxd
“Most of the appeal for me is not the features that Go has, but rather the features that have been intentionally left out.”
— Rob Pike
“Why would you have a language that is not
theoretically exciting? Because it’s very useful.”
“Objects” in Go
Does Go have Objects?
• Go lacks Classes
• Go lacks “Objects”
What is an Object?
– Steve Francia
“An object is an abstract data type that
has state (data) and behavior (code).”
type Rect struct { width int height int }
Type Declaration (Struct)
func (r *Rect) Area() int { return r.width * r.height }
Declaring a Method
func main() { r := Rect{width: 10, height: 5} fmt.Println("area: ", r.Area()) }
In Action
type Rects []Rect
Type Declaration (Slice)
func (rs Rects) Area() int { var a int for _, r := range rs { a += r.Area() } return a }
Declaring a Method
func main() { r := Rect{width: 10, height: 5} x := Rect{width: 7, height:10} rs := Rects{r, x} fmt.Println("r's area: ", r.Area()) fmt.Println("x's area: ", x.Area()) fmt.Println("total area: ", rs.Area()) }
In Action
http://play.golang.org/p/G1OWXPGvc3
type Foo func() int
Type Declaration (Func)
func (f Foo) Add(x int) int { return f() + x }
Declaring a Method
func main() { var x Foo !
x = func() int { return 1 } !
fmt.Println(x()) fmt.Println(x.Add(3)) }
In Action
http://play.golang.org/p/YGrdCG3SlI
Go Has “Objects”
“Object Oriented”
Go
– Wikipedia
A language is usually considered object-based if it includes the basic capabilities for an
object: identity, properties, and attributes.
A language is considered object-oriented if it is object-based and also has the capability of
polymorphism and inheritance.
Go is Object Based. !
Is it OO?
Inheritance• Provides reuse of objects
• Classes are created in hierarchies
• Inheritance lets the structure and methods in one class pass down the hierarchy
Go’s approach• Go explicitly avoided inheritance
• Go strictly follows the composition over inheritance principle
• Composition through embedded types
Composition• Provides reuse of Objects
• One object is declared by including other objects
• Composition lets the structure and methods in one class be pulled into another
– Steve Francia
Inheritance passes “knowledge” down !
Composition pulls “knowledge” up
type Person struct {
Name string
Address }
!
!
type Address struct {
Number string
Street string
City string
State string
Zip string
}
Embedding Types
Inner Type
func (a *Address) String() string {
return a.Number+" "+a.Street+"\n"+ a.City+", "+a.State+" "+a.Zip+"\n"
}
Declaring a Method
func main() { p := Person{ Name: "Steve", Address: Address{ Number: "13", Street: "Main", City: "Gotham", State: "NY", Zip: "01313", }, } }
Declare using Composite Literal
func main() { p := Person{ Name: "Steve", Address: Address{ Number: "13", Street: "Main", City: "Gotham", State: "NY", Zip: "01313", }, }
fmt.Println(p.String())
In Action
http://play.golang.org/p/9beVY9jNlW
Promotion• Promotion looks to see if a single inner type can
satisify the request and “promotes” it
• Embedded fields & methods are “promoted”
• Promotion only occurs during usage, not declaration
• Promoted methods are considered for interface adherance
func (a *Address) String() string { return a.Number+" "+a.Street+"\n"+ a.City+", "+a.State+" "+a.Zip+"\n" } !
func (p *Person) String() string { return p.Name + "\n" + p.Address.String() }
Not Overloading
func main() { p := Person{ Name: "Steve", Address: Address{ Number: "13", Street: "Main", City: "Gotham", State: "NY", Zip: "01313", }, } ! fmt.Println(p.String()) fmt.Println(p.Address.String()) }
Both Methods Available
http://play.golang.org/p/Aui0nGa5Xi
func isValidAddress(a *Address) bool { return a.Street != "" } !func main() { p := Person{ Name: "Steve", Address: Address{ Number: "13", Street: "Main", City: "Gotham", State: "NY", Zip: "01313"}} ! fmt.Println(isValidAddress(p)) // cannot use p (type Person) as type Address // in argument to isValidAddress fmt.Println(isValidAddress(p.Address)) }
Types Remain Distinct
http://play.golang.org/p/KYjXZxNBcQ
Promotion is NOT Subtyping
Polymorphism• “The provision of a single interface to
entities of different types”
• Typically implmented via Generics, Overloading and/or Subtyping
Go’s approach• Go explicitly avoided subtyping &
overloading
• Go does not provide Generics (yet)
• Go’s interface provide polymorphic capabilities
Interfaces• A list of required methods
• Structural vs Nominal typing
• ‘‘If something can do this, then it can be used here”
• Convention is call it a Something-er
type Shaper interface { Area() int }
Interface Declaration
func Describe(s Shaper) { fmt.Println("Area is:", s.Area()) }
Using Interface as Param Type
func main() { r := &Rect{width: 10, height: 5} x := &Rect{width: 7, height: 10} rs := &Rects{r, x} Describe(r) Describe(x) Describe(rs) }
In Action
http://play.golang.org/p/WL77LihUwi
–James Gosling (creator of Java)
“If you could do Java over again, what would you change?” “I’d leave out classes,” he replied. After the
laughter died down, he explained that the real problem wasn’t classes per se, but rather implementation inheritance (the extends
relationship). Interface inheritance (the implements relationship) is preferable. You should avoid
implementation inheritance whenever possible.
Go Interfaces are based on
implementation, not declaration
The Power of Interfaces
type Reader interface { Read(p []byte) (n int, err error) }
io.Reader
io.Reader• Interface
• Read reads up to len(p) bytes into p
• Returns the # of bytes read & any error
• Does not dictate how Read() is implemented
• Used by os.File, bytes.Buffer, net.Conn, http.Request.Body, loads more
type Writer interface { Write(p []byte) (n int, err error) }
io.Writer
io.Writer• Interface
• Write writes up to len(p) bytes into p
• Returns the # of bytes written & any error
• Does not dictate how Write() is implemented
• Used by os.File, bytes.Buffer, net.Conn, http.Response.Body, loads more
func MarshalGzippedJSON(r io.Reader, v interface{}) error { raw, err := gzip.NewReader(r) if err != nil { return err } return json.NewDecoder(raw).Decode(&v) }
io.Reader in Action
f, err := os.Open("myfile.json.gz") if err != nil { log.Fatalln(err) } defer f.Close() m = make(map[string]interface{}) MarshalGzippedJSON(f, &m)
Reading a json.gz file
Practical Interoperability• Gzip.NewReader(io.Reader)
• Works on files, http requests, byte buffers, network connections, …anything you create
• Nothing special needed in gzip to be able to do this… Simply call Read(n) and leave the abstracting to the implementor
func main() { resp, err := http.Get("...") if err != nil { log.Fatalln(err) } defer resp.Body.Close() out, err := os.Create("filename.ext") if err != nil { log.Fatalln(err) } defer out.Close() io.Copy(out, resp.Body) // out io.Writer, resp.Body io.Reader }
Pipe http response to file
Go
— Steve Jobs
Simple can be harder than complex: You have to work hard
to get your thinking clean to make it simple. But it's worth it in the end because once you get there, you can move mountains.
Go is simple, pratical & wonderful
Go build something
great