Quick Review of Object-Oriented Programming in Go 02-201
Structs: Grouping Variables as Objects type Rectangle struct { x1 float64 y1 float64 width float64 height float64 type Circle struct { x1 float64 y1 float64 radius float64
Area Functions for Shapes? func Area(R Rectangle) float64 { return R.width * R.length func Area(C Circle) float64 { return math.pi * C.radius * C.radius
Area Functions for Shapes? func Area(R Rectangle) float64 { return R.width * R.length func Area(C Circle) float64 { return math.pi * C.radius * C.radius Error! Can t name two functions the same thing.
Workaround: Methods func (R Rectangle) Area() float64 { return R.width*R.length func (C Circle) Area() float64 { return R.radius * R.radius * math.pi Call these methods with R.Area() and C.Area() same setup that we used for accessing fields.
Pointers Help Us Change Fields Inside Method We couldn t access fields inside a method... func (C Circle) DoubleRadius() { C.radius = 2*C.radius Solution: Take a pointer to a Circle as the input. func (C *Circle) DoubleRadius() { C.radius = 2*C.radius // note double-meaning of *
Inheritance and Polymorphism 02-201
Rectangle Fields/Methods type Rectangle struct { x1,y1 float64 width, height float64 fillcolor color.color strokecolor color.color linewidth int Natural to create an object type for each shape: Circle Oval Triangle Star Square. These methods are needed for all shapes. func (r *Rectangle) Area() float64 func (r *Rectangle) MoveTo(x,y int) func (r *Rectangle) Resize(w,h int) func (r *Rectangle) Draw(d *DrawingCanvas) func (r *Rectangle) SetLineWidth(w int) func (r *Rectangle) ContainsPoint(x,y int)
Circle Fields/Methods type Circle struct { x0,y0 int radius int fillcolor color.color strokecolor color.color linewidth int Natural to create an object type for each shape: Circle Oval Triangle Star Square. These methods are needed for all shapes. func (c *Circle) Area() float64 func (c *Circle) MoveTo(x,y int) func (c *Circle) Resize(w,h int) func (c *Circle) Draw(d *DrawingCanvas) func (c *Circle) SetLineWidth(w int) func (c *Circle) ContainsPoint(x,y int)
Applying Canvas Methods to All Shapes type ShapeCanvas struct { width, height int backgroundcolor color.color shapes []???? But what type should go here???! func (c *ShapeCanvas) ShapeArea() float64{ sum := 0.0 for shape := range c.shapes { sum += shape.area() return sum
Solution: Interfaces type ShapeCanvas struct { width, height int backgroundcolor color.color shapes []Shape type Shape interface { Area() float64 MoveTo(x,y int) Resize(w,h int) Draw(c *DrawingCanvas) SetLineWidth(w int) The interface contains the methods shared by its types.
Solution: Interfaces type ShapeCanvas struct { width, height int backgroundcolor color.color shapes []Shape func (c *ShapeCanvas) ShapeArea() float64{ sum := 0.0 for shape := range c.shapes { sum += shape.area() return sum Note: We don t have to say that Circle/Square are Shapes!
interface{ As a Universal Type We also can use interface{ as a universal type. func main() float64{ var x interface{ // x can take any type! x = 3 fmt.println(x) x = AGT // no error here! fmt.println(x) Note: This is not a reason to ignore types.
interface{ As a Universal Type
Information-Hiding in Go When we examine the details of fmt.print(), we see 1300 lines of ugly, complicated functions.
Information-Hiding in Go When we examine the details of fmt.print(), we see 1300 lines of ugly, complicated functions. But do we need to know any of this in order to print an int?
Information-Hiding in Go When we call fmt.println( Hello world! )... this function calls within the fmt package fmt.fprintln(os.stdout, Hello world! )... which in turn calls p := newprinter() p.doprintf( Hello world!, true, true)...
Information-Hiding in Go which is very complicated... func (p *pp) doprint(a []interface{, addspace, addnewline bool) { prevstring := false for argnum := 0; argnum < len(a); argnum++ { p.fmt.clearflags() // always add spaces if we're doing Println arg := a[argnum] if argnum > 0 { isstring := arg!= nil && reflect.typeof(arg).kind() == reflect.string if addspace!isstring &&!prevstring { p.buf.writebyte(' ') prevstring = p.printarg(arg, 'v', 0) if addnewline { p.buf.writebyte('\n')
Information-Hiding in Go Not only do we not need to know exactly what this does... p := fmt.newprinter() p.doprintf( Hello world!, true, true)... but this gives us a compile error! // undefined: fmt.newprinter Think: Why would Go not allow us to access this function?
Public/Private Functions in Go 1. Public: accessible outside of the package (with import packagename ). Begin with upper case letter. 2. Private: accessible only to other functions within the package; can never be accessed with import packagename ). Begin with lower case letter. func UPGMA(mtx [][]float64) *Tree // can be accessed from outside package (public) func averagedist(mtx [][]float64, clusters []Cluster, i,j,k int) float64 // helper function for UPGMA (private)
Has vs. Is A struct has certain properties. A circle has a radius A Contact has a first name A Flight has a duration But how can we represent is? A circle is a shape A Contact is a person A City is a node in a network
Ordering Shapes Hierarchically Shapes Ellipses Triangles Stars Quadrilaterals Circles Equilateral Isosceles Parallelogram Rhombus Rectangle Square
Ordering Vehicles in a Video Game?
Previously: Interfaces type ShapeCanvas struct { width, height int backgroundcolor color.color shapes []Shape type Shape interface { Area() float64 MoveTo(x,y int) Resize(w,h int) Draw(c *DrawingCanvas) SetLineWidth(w int) But interfaces only allow objects to share methods...
One Possible Field-Sharing Solution type Automobile struct { width, height float64 topspeed float64 numoftires int type Car struct { auto Automobile numberofdoors int type Ferrari struct { car Car // other stuff that makes a Ferrari func main() { vroom := new(ferrrari) vroom.ctopspeed = 187.4 // error!
One Possible Field-Sharing Solution type Automobile struct { width, height float64 topspeed float64 numoftires int type Car struct { auto Automobile numberofdoors int type Ferrari struct { car Car // other stuff that makes a Ferrari func main() { vroom := new(ferrrari) vroom.car.auto.topspeed = 187.4 // ugly!
Better Idea: Anonymous Fields type Automobile struct { width, height float64 topspeed float64 numoftires int type Car struct { Automobile //a Car is an Automobile numberofdoors int type Ferrari struct { Car //a Ferrari is a Car // other stuff that makes a Ferrari func main() { vroom := new(ferrrari) vroom.topspeed = 187.4 // this works!
Better Idea: Anonymous Fields Furthermore, a Ferrari can be used in place of a Car or Automobile anywhere we like in functions. func (a *Automobile) Start() { // It would probably be more natural to use interfaces for most functions, though each car will drive differently. func main() { vroom := new(ferrari) vroom.start() // this works!
Another Example of Anonymous Fields type Parallelogram struct { x1, y1 float64 width, height float64 theta float64 type Rectangle struct { Parallelogram //anonymous field func (p *Parallelogram) Area() float64 { return p.width * p.height func main() { r := new(rectangle) r.width, r.height = 3.0, 5.0 //OK! fmt.println(r.area()) //OK! Prints 15
! Four Defining Principles of OOP Abstraction! Encapsulation! Object-! Oriented! Programming! Inheritance!! Polymorphism!
Abstraction If it walks like a circle, swims like a circle, and quacks like a circle...
Abstraction An abstraction denotes the essential characteristics of an object that distinguish it from all other kinds of object and thus provide crisply defined conceptual boundaries, relative to the perspective of the viewer. Courtesy: Gary Booch!
Abstraction The main example of abstraction in Go is with structs and methods. type Rectangle struct { x1,y1 float64 width, height float64 fillcolor color.color strokecolor color.color linewidth int func (r *Rectangle) Area() float64 func (r *Rectangle) MoveTo(x,y int) func (r *Rectangle) Resize(w,h int) func (r *Rectangle) Draw(d *DrawingCanvas) func (r *Rectangle) SetLineWidth(w int) func (r *Rectangle) ContainsPoint(x,y int)
Encapsulation Encapsulation: group together related things, and hide as many details as possible from the user. Examples in Go: Functions: to use fmt.printf() we only need to know what it takes and what it returns. Packages: Inside the fmt package is 1279 lines of code, but we only need to know public functions. Interfaces: I have a Shape, but I don t need to know what kind of shape in order to resize it.
Say something about HW6 Here
Note about HW6 This is why we are anal about the function requirements in HW6 In practice, the boss won t care about how you implement something. They just want the product to have certain properties.
Inheritance Inheritance: the ability for one class of objects to inherit the properties of another class. type Automobile struct { width, height float64 topspeed float64 numoftires int type Car struct { Automobile //a Car is an Automobile numberofdoors int type Ferrari struct { Car //a Ferrari is a Car // other stuff that makes a Ferrari
Polymorphism Polymorphism: the ability to have the same interface for presenting different objects. type Shape interface { Area() float64 MoveTo(x,y int) Resize(w,h int) func (C *Circle) Area() float64 { return math.pi * C.radius * C.radius func (R *Rectangle) Area() float64 { return R.width * R.length
Polymorphism This may seem heavily related to inheritance, so let me give a better example. x := Hello y := World! a := 3 b := 4 fmt.println(a+b, x+y) Strings and ints are unrelated, but Go can interpret the + symbol in different ways for both types.