6 ms·
Is Go an Object-Oriented Language?
- AUmrysh 12y agoYou can do this same thing in C to get Objects. Also I believe there may be a typo in your last paragraph >while staying clear of the brittle mess than is inheritance It should be "that" instead of "than", I think.
- jerf 12y agoC is not an object-oriented language because it has no language features intended to make objects easier to use or work with. You can't actually attach "methods" to structs in C. You can use objects in C, and there's numerous in-the-wild big examples. But you have to implement it yourself or use some library, and there isn't one "standard" for the language. Go clearly does have some features designed to make objects a first-class element. Equally clearly there are some other languages that have "more" such features. This post I'm making is merely descriptive; there's no positive or negative attached to these statements.
- slm_HN 12y ago"You can't actually attach "methods" to structs in C." You can have structure members that are function pointers which is basically attaching a "method".
- pdpi 12y agoYou still have to explicitly pass a `this` to that function, which is kind of my earmark for telling methods and functions apart. (In this regard, Python treads a fine line where it has an explicit `self` parameter that is passed in automatically).
- knome 12y agoYou can manually pass in the `self` parameter to unbound methods if you like. import itertools class Test(): def __init__( self, number ): self._number = number return def aaa( self ): print 'AAA<%s>' % str( self._number ) return def bbb( self ): print 'BBB<%s>' % str( self._number ) def main(): instances = [ Test( n ) for n in range( 100 ) ] functions = [ Test.aaa, Test.bbb ] for instance, function in zip( instances, itertools.cycle( functions ) ): function( instance ) if __name__ == '__main__': main()
- jerf 12y agoIn that case you get something not typically associated with "OO", which is the ability to override a method on a per-object basis. I say "not typically" because there are still languages conventionally called OO that can do that, like Python and Javascript. I take a pretty expansive definition of OO, pretty much the same one the author of the post takes, on the grounds that it isn't that helpful to insist that Javascript or Go isn't an "object oriented" language, because then one must sit there and explain what they are. They clearly aren't "procedural", excepting to the extent that Java is "procedural" (i.e., used as opposed to functional or declarative). And in the end, while there are significant dialect differences within the family of OO languages, when you start your language with a binding between methods and structures (be it a class or a prototype or a whatever), you end up with the same sort of end language. When viewed from the perspective of Haskell or SQL, Go and Java are next-door neighbors, even if within the mighty city of Object Orientation they consider themselves distant. Really persnickety definitions of "OO" just don't match to the programming reality very well. Argue as much as you like about whether one must "really" have a particularly persnickety definition of Polymorphism or whether you "must" have a concept of "private", but in the end, a project optimally done in Java, Python, Go, and $OTHER_OO_LANGUAGE will often end up pretty similarly structured. (And I'd observe to the extent that is not true, the spoilers will be something unrelated to OO like concurrency support or runtime characteristics, not details of the OO.)
- seanmcdirmid 12y agoC has nice infrastructure for building v-tables that I found very useful back when I was writing in C. Heck, I wasn't even aware that I was merely reinventing objects at the time. Go is definitely an object-oriented language. It lacks classes, but those aren't required. We might argue that structural subtyping isn't really very OO. But given Go's lack of generics, this is a moot point.
- AUmrysh 12y agoThank you for clarification. I've not really used Go, so I don't know how it differs from C for objects. I'm a little familiar with using structs in C for OOP, I apologize if my comment came across as to lessen the article, because I found it pretty interesting, and I love to see things like this where a new programmer might have their eyes opened to something those of us who've been around a while might already know from somewhere else.
- ben336 12y agoI think the "object"-less OO tag is a bit overblown. Structs are objects. Just because Go creators didn't choose to name them that doesn't mean there's a fundamental difference between Go structs and other languages' objects.
- grey-area 12y agoThe fundamental difference (and there is one), is that Go omits the concept of inheritance, preferring composition instead. So in contrast to many mainstream languages today - Java, Obj-C, C#, C++, Ruby, Python, PHP , etc. there is no concept of inheritance, only composition of objects and conforming to interfaces. There's a good quote in the article about this under 'Inheritance Is Best Left Out' - James Gosling responds to someone asking what he'd change in Java in retrospect - “I’d leave out classes,” he replied.
- voidlogic 12y ago>>The fundamental difference (and there is one), is that Go omits the concept of inheritance, preferring composition instead Right, but that doesn't mean Go is not object oriented, it simply eschews inheritance for composition. Go also offers something else n lieu of inheritance that many other OO languages don't have, embedding.
- afternooner 12y agoYea, I liked the idea of what go was waning to do. They wanted classes and objects without the classes and inheritance, but all they've done is replace that headache with an interface headache.
- mseepgood 12y ago"O-O is important because it provides uniformity of interface. Subtype inheritance encourages non-uniform interfaces." - Rob Pike http://www.infoq.com/presentations/Go-Google http://www.infoq.com/presentations/Go-Google 43:00
- kd0amg 12y agoWhat have’t we done. Attached that behavior to the struct itself so that invoking a struct's "area" function could give any of several different behaviors depending on exactly what "rect" struct you have.
- jerf 12y agoTo do that in Go, you just add: type Area interface { area() int } though I'd note I'm deliberately just copying the article as written, as an "area" that's confined to an int is awfully weird. Note you can indeed just add that, and you're able to take "Area"s anywhere you like, and you can even do it in a different module entirely; nothing has to "declare" than a rect implements Area. To forstall the usual next question, no, Go has no further overloading based on type or anything else. My personal advice if you want to use that a lot is to use a different language. I like Go, but I look on the people trying to use it for machine learning or matrix math or other intensely mathematical computational loads with a bit of mystification. It isn't what it's good for, and I see no sign the core devs even consider it a marginal use case (to say nothing of a core use case) and have no intentions of changing the language to make this easier. If you really, really need overloading for your core use case, pick something else. Go is built for the environments where overloading is generally dangerous and used by people to do excessively "clever" things on the server, not for the environments where it is necessary. (Or perhaps "environment", singular, since "intensely mathematical code" is the only such thing I know of; everywhere else I've ever seen it it's asking for trouble.)
- rakoo 12y ago> Go has no further overloading based on type or anything else You can overload in Go: see for example how a zlib compressor is implemented [0]. The gist is that you take a standard io.Writer, embed it in your struct, and override the Write() method. This way you have a new io.Writer you can use wherever a io.Writer is needed. This pattern is actually standard in Go (and I guess in other languages where interfaces are more important than implementations) Or maybe I didn't understand ? [0] http://golang.org/src/pkg/compress/zlib/writer.go?s=4340:4391#L136 http://golang.org/src/pkg/compress/zlib/writer.go?s=4340:439...
- Jare 12y agoSurprised there is no mention of hiding or message passing, which are two more common aspects of Object Orientation. Without them, I think the idea that methods are "attached" to objects is rather incomplete.
- jdmichal 12y agoMore common, but certainly not required. For instance, JavaScript does not provide hiding at all as part of its OO mechanisms. (Implementations that allow hiding use closures to provide it.)
- Jare 12y agoExactly, that would fit with the tone of the article, which does away with the idea of OO defined in terms of axioms like inheritance, etc. and instead explores how these pieces of the OO picture work and relate to each other.
- adamlett 12y agoI would say the defining property of OO, is polymorphism. It's the property that allows some code to call a Bar() method on object Foo and not be concerned with the exact type of object Foo. Without polymorphism, there is little differnce between Bar.Foo() and Foo(Bar). Implementation inheritance is a property of _some_ OO languages and one that is hard to imagine separate from OO. Which is why perhaps so many insist upon it being a required property for some language to be called OO. I am firmly in the camp that thinks implementation inheritance is a bad idea and it is best to avoid it even in langauges that support it. Thus I don't agree with anyone who claims that it is an important characteristic of a language. Whether object instances find their genesis in classes, factories or prototypes are IMO the least important aspect to consider when discussing whether or not some language is truly OO. It's the object instances that do the important work. Where they came from is not so interesting.
- abrahamsen 12y ago> I would say the defining property of OO, is polymorphism. Make it dynamic polymorphism, and I agree.
- panzi 12y agosubtype polymorphism
- groovy2shoes 12y agoSubtype polymorphism. Dynamic dispatch. http://en.wikipedia.org/wiki/Subtype_polymorphism http://en.wikipedia.org/wiki/Subtype_polymorphism http://en.wikipedia.org/wiki/Dynamic_dispatch http://en.wikipedia.org/wiki/Dynamic_dispatch Polymorphism is a feature of the type system, and thus inherently static. Dynamic dispatch is something you often wind up with as a consequence of subtyping, but neither requires the other, strictly speaking.
- jbert 12y agoSomething I've done in some golang code recently is to fake some OO features. I'd appreciate some commentary on the approach. So I want a few different, but similar things. These are actually stages in a processing pipeline, each stage doing different processing steps. What I'm currently doing, which mostly works well, is to have a struct type ('Stage') which does all the generic work (equivalent to an abstract base class in C++). The Stage contains a function ptr ('Each') to actually do the processing step. I can then have various 'derived' types which embed 'Stage'. Each one is assembled via a ctor which sets up the 'Each' function ptr. Effectively this provides inheritance with method overloading for the Each function. I also have an interface ('Stager') which is satisfied by the Stage type, and so consequently by all the derived types (since they embed Stage). So, I seem to have most of the benefits of C++ abstract base class and 'inheritance' (of data and methods), including overriding of methods by subclasses (using explicit assignment to function ptr). It feels pretty nice to work with. The main concern I have is the slight klunkiness of the Stage/Stager duality. I also don't think I'd like this if I had many overridden methods (I just have one atm). Anyone care to comment on a better way to this or other critique?
- AYBABTME 12y agoIf it works well, it's not feeling like a square peg in a circle hole, if it makes your life easier; I'd say it's fine. I've done that a few rare times, and I think in some case it makes a clean solution. See [1] for an example. However I don't think that's how people should do _all of the time_ when they try to force an OO model onto Go. [1]: https://github.com/aybabtme/loghooks/blob/master/hooks.go#L25 https://github.com/aybabtme/loghooks/blob/master/hooks.go#L2...
- AnimalMuppet 12y agoTo me, it feels like you're implementing too much of the OO behavior yourself. That is essentially the same as saying that the language isn't really object oriented.
- NateDad 12y agoI think you'd do better making the stages into plain functions that take an interface... why do the stages need to be structs at all?
- ChuckMcM 12y agoReminds me of the (possibly) apocryphal story of Nickolas Wirth telling his audience at Apple that Modula-2 was OO and having one of the audience members object. To which Dr. Wirth replied, "Who are we to say what object oriented means exactly?" and the objector, who turns out to be Alan Kay, says, "Well I invented the term so I get to define it, this isn't object oriented." I would say that similar objections would be made about Go calling it self 'object oriented' however I also don't know what is being asserted. Go has many constructs that make abstraction easier, and that is what many programmers want out of the OO idea, so its fine. I'm sure there specific things that some people require before they will label something as OO. Is it a functional question or a religious question as to whether or not Go is Object Oriented?
- arethuza 12y agoI've long since given up thinking about a precise definition of "object oriented" - for example, CLOS (which I used for years and thought was awesome) doesn't sit very well with most peoples ideas around what constitutes "object oriented" which seem to be largely define by experience with C++, Java or C# (which all look the same if you squint hard enough). e.g. This discussion: http://c2.com/cgi/wiki?HowObjectOrientedIsClos http://c2.com/cgi/wiki?HowObjectOrientedIsClos [NB I now just tend to think whether something is useful, leaving ideological purity to others.]
- seanmcdirmid 12y agoDo you program with entities that have names and you can talk about their interactions as if they had behavior of their own? If so, then you have objects. Do you program with anonymous values without names independent of their structure, and you can then reason about them equationally? If so, then you have values and probably lambdas to plumb them through the program as they lack their own behavior (you can have lambdas over objects also, but we don't call that functional these days). Does the language encourage you to think about named entities or does it encourage you to reasoning about values? Of course, not many languages beyond Haskell try to push you to reason about everything as values. And most OOP languages include some form of values these days (if not, we definitely program with immutable objects like points that lack names/identity and might as well be called values). This is also why OOP is necessarily tied up with state: it doesn't make sense for an immutable container of something to even have a name as it can be only really be identified by its structure.
- optymizer 12y agoThe problem with the author's case for Go's is-a relationships is that it breaks down the moment you want to pass the object to a function expecting the original object. For example, http://play.golang.org/p/EmodogIiQU http://play.golang.org/p/EmodogIiQU type A struct { } type B struct { A } //B is-a A func save(A) { //do something } b := &B{} save(b); //OOOPS! b IS NOT A If Go had is-a relationships, the code above would be valid. Instead, Go only implements has-a relationships, and simply provides shortcuts to calling B.A.foo() as B.foo(). One could create B.save(), which would call save(b.A), but the very reason you're now proxying the call to save() is because there is no is-a relationship in Go. We all know about interfaces, but the problem is that is-a relationships do exist, and you can't always use interfaces, because often you want to share the data encapsulated by the objects, not only the behavior. One ends up creating methods to fetch each piece of data, but in code that is supposed to be performant, calling methods instead of accessing fields is suboptimal.
- lloeki 12y agoIOW, the Liskov substitution principle is unsatisfied. The language has chosen by design not to resolve "methods"† up the "hierarchy"†, therefore the only way to reinstate it is to implement func save(B) { }, which has either the benefit of making you think whether you need to persist more fields or make explicit that you don't. And as you said, implementing proxy accessors to satisfy an interface just to simulate inheritance is obviously not the right choice. † neither of which exist, since there's no objects and no inheritance. In simplifying things, this brings a constraint. Given how method resolution is a pain point WRT implementation complexity and performance (see e.g Ruby), this is a reasonable tradeoff. I am glad we have such an interesting choice of languages.
- jaekwon 12y agoJust call save(b.A) or save(&b.A). No need for methods, is performant. I can't think of a reason--besides extra typing--why this wouldn't be sufficient. http://play.golang.org/p/7vE_wN6EBv http://play.golang.org/p/7vE_wN6EBv
- AnimalMuppet 12y ago
- chimeracoder 12y ago> Since a standard definition doesn’t exist, for the purpose of our discussion we will provide one. Who said a standard definition doesn't exist? From Alan Kay, who 'invented' object-orientation and coined the term: > OOP to me means only messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things. It can be done in Smalltalk and in LISP. There are possibly other systems in which this is possible, but I’m not aware of them[0]. Yes, you can make the argument that the term has evolved in common parlance beyond what Kay originally conceived of, but it's silly to propose a "modern" definition of object-orientation and not at least mention the original definition. [0] From a 2003 email: http://userpage.fu-berlin.de/~ram/pub/pub_jf47ht81Ht/doc_kay_oop_en http://userpage.fu-berlin.de/~ram/pub/pub_jf47ht81Ht/doc_kay... [1] Note that he does not mention Java, even though he write this during the height of Java's popularity: http://www.tiobe.com/index.php/paperinfo/tpci/Java.html http://www.tiobe.com/index.php/paperinfo/tpci/Java.html
- vidarh 12y agoKay's definition is by no means "standard". "Standard" usage of the term started deviating from Kay's definition almost as soon as it was conceived. By time the term was widespread, it already meant something different to what he envisioned. It may be "silly" not to mention the original, but in this context the original a distraction: the original definition would exclude pretty much every language we today tend to consider object-oriented.
- kd0amg 12y agoThe blog post gives us, "To me this feels very much like an object. I am able to create a structured data type and then define methods that interact with that specific data." Defining OOP as functions that consume structured data fails to exclude a lot of languages we don't consider object-oriented.
- deleted 12y ago[deleted]
- jnks 12y agoThe author of this blog post is a little confused about embedded structs. His examples of has-a and is-a are both has-a's, and the syntax change involved (leaving off a name for the embedded type) doesn't actually do anything. type Person struct { Name string Address Address } is equivalent to type Person struct { Name string Address } And in fact, these are equivalent too: p.Address.Zip = "01313" p.Zip = "01313" http://play.golang.org/p/aKH3YxT5Mb http://play.golang.org/p/aKH3YxT5Mb Go doesn't really support is-a for structs, as pointed out elsewhere in the comments here. Interface implementation is the only way to get the sort of "this type can be substituted for this other type" idea that is-a inheritance provides in other languages.
- asgard1024 12y agoI have to say, I like Go model better than "standard" OOP (as in Java, C#..). Class is a single construct used for three different abstractions, namely: - modularity/hiding - inheritance - polymorphism This eventually turned out to be a bad idea (as evidenced by all the mess with virtual methods, multiple inheritance and structural patterns), and interfaces (and namespaces) were added to partly remedy this. In Go, you instead get three orthogonal constructs: - modules - embedded structures - interfaces These directly correspond to basic principles of OOP. Nice and clean.
- stcredzero 12y agoOne could say that Go errs on the side of caution, making sure it doesn't have too many of the trappings of OOP.
- dragonwriter 12y agoI like that Go and Rust reexamined some of the underlying traditions of the C++/Java/C# approach to OOP rather than reflexively repeating them -- and while I think Go and Rust both, on a high level, took good (but very different) approaches, I think the one thing that Rust did right that would be better even with the rest of Go's approach than the way Go did it is explicit and detached declaration of interface implementations for data types.
- NateDad 12y agoSo you're saying you'd prefer it if you had to explicitly tell Go that your type implements an interface? Something like this? type Shape interface { Area() int } type Square struct { sideLen int } // Somehow denote that this function is implementing // Shape's Area function func (s Square) Shape.Area() int { return sideLen * sideLen } Because, one of the things I like best about Go's interfaces is that you don't have to do that.
- dragonwriter 12y ago> So you're saying you'd prefer it if you had to explicitly tell Go that your type implements an interface? I'd prefer that to having to avoid using the most natural names for methods to avoid implementing an unintended interface -- it seems to me that Go's approach in this area makes easy things easier and hard things harder.
- NateDad 12y agoThis is honestly kind of a dumb question, because the answer depends on who is asking the question. Object oriented has become such an overused and little understood term, that you can't just give an answer without trying to discern what the person asking is looking for. There's almost always a better question to ask than "Is x language object oriented?".