27 ms·
OO in Python is mostly pointless
- kwdc 6y agoI've done plenty of maintenance programming. Most OO involves abuse of the paradigm anyway. Most people don't use inheritance to large AND good effect. Or they use it and create a mess. Deep hierarchies of inheritance need to be carefully designed or they become a mess. All the hiding means less clarity about what is happening when things go wrong. That said, its a valid approach and can yield useful results. Especially when you can just add a thing to a list and simply call a method on it without having to bother to know what it is.
- jope12 6y ago>Deep hierarchies of inheritance need to be carefully designed or they become a mess. Deep hierarchies of anything need to be carefully designed.
- brixon 6y agoI try to use the rule of after three levels of inheritance or abstraction then it needs to be a black box and then you can reset your count.
- kwdc 6y agoThe flip side of my impromptu "rule" is that you can drop the "careful" part as long as you are comfortable with a little or a lot of mess. Obvious common sense lowers the tolerance. I wonder how others set their tolerance? My perspective is that most OO hoerarchies don't go too deep. I've seen 4-5 at rare extremes. Around 2-3 is common. I'm sure someone has encountered 10 or more. I shudder to think how well that turns out in practice.
- throwawaygal7 6y agothe author is right of course, but in practice he's wrong. I've been in a 500k loc codebase mostly in python. As things got complicated, instead of the couple of arguments seen in his example you need up with half a dozen or more, or variable argument lists, people passing callbacks with callbacks and all sorts of shit like that instead of just writing an object and context manager or two. In a large codebase these rapidly become very difficult to reason about and are better structured as objects with a discrete set of operations.
- leontrolski 6y ago(Author here) I used to think that, but I've since found myself working on a similar sized codebase where we use very little OO and none of these problems have manifested themselves. Avoiding large function signatures and passing higher order functions around takes a little discipline, but wrapping those things with a bit of OO doesn't make the root problems go away, it just encourages their proliferation. (To reiterate the article, I'm by and large talking application development as opposed to library development).
- jphoward 6y agoI found when I started programming I never used OOP. Then I used it too much. And then recently I use it incredibly sparingly. I think this is most people's experience. However, there are certain situations where I cannot imagine working without OOP. For example, GUI development. Surely nobody would want to do without having a Textbox, Button, inherit from a general Widget, and have all the methods like .enable(), .click(), and properties like enabled, events like on_click, etc.? Similarly, a computer game, having an EnemyDemon inherit from Enemy, so that it has .kill(), .damage(), and properties for health, speed etc.? I'd really like to know how the most anti-OOPers think situations like this should be handled? (I'm not arguing, genuinely interested)
- leontrolski 6y agoIn game development even there seems to be a shift away from OO, to data + functions under the guise of "Data Orientated/Driven Development" - eg: https://www.youtube.com/watch?v=0_Byw9UMn9g https://www.youtube.com/watch?v=0_Byw9UMn9g Edit: ignore me - this person seems to know more what they're talking about - https://news.ycombinator.com/item?id=25933781 https://news.ycombinator.com/item?id=25933781
- setr 6y agoAt least regarding games, ECS is the popular flavor-of-the-month alternative to OOP as a design strategy. The main problem being that games often have a lot of special cases, which break the inheritance hierarchy quite quickly. E.g. Defining a weapon > {sword, wand} hierarchy, with respective properties for melee and casting, and then defining a unique weapon spellsword which is capable of both melee and casting. You could inherit from weapon, and copy & paste sword/wand code, or inherit from sword/wand, and copy & paste the other, but the hierarchy is broken. ECS would rather have you define [melee] and [casting] components, and then define a sword to have [melee], wand to have [casting] and spellsword to have [melee, casting]. So instead of representing the relationships as a tree of inheritance, you represent it as a graph of components (properties). And then you generically process any object with the melee tag, and any object with the casting tag, as needed. And of course then you could trivially go and reach out across the hierarchies and toss [melee] onto your house object and wield your house like a sword -- I don't know why you'd want to do that, but the architecture is flexible enough to do so (perhaps to your detriment). Dwarf Fortress probably has the best example of this: https://github.com/BenLubar/raws/blob/archive/objects/creature_amphibians.txt https://github.com/BenLubar/raws/blob/archive/objects/creatu... That's probably more an example of "metadata-driven" but it's ultimately the same thing -- an entity in the game is defined by its components, and the job of the game engine is to simply drive those components through the simulation. That particular example has its metadata (e.g. aesthetics: [CREATURE_TILE:249][COLOR:2:0:0]), its capabilities (e.g. [AMPHIBIOUS][UNDERSWIM]) and its data (e.g. [PETVALUE:10][BODY_SIZE:0:0:200]). And it even has inheritance :-) [CREATURE:TOAD_MAN] [COPY_TAGS_FROM:TOAD] [APPLY_CREATURE_VARIATION:ANIMAL_PERSON]
- jgwil2 6y agoThis may be a bit pedantic, but OOP != inheritance. Inheritance is the worst part of OOP. OOP is also modules and namespaces and encapsulation, all of which are great.
- bccdee 6y agoI don't think modules or namespaces really count as OOP. And encapsulation can exist in the absence of OOP if the privacy barrier exists at (eg) the module level instead of the class level. I'd argue that inheritance is really the core of OOP (and by extension methods, which are only different from functions insofar as they interact with inheritance).
- petr25102018 6y agoHow are modules and namespaces OOP?
- jgwil2 6y agoTo me OOP is about separation of concerns, abstract data types, information hiding. Modules/namespaces support decomposition the same way that objects do, and historically they became popular because of and in tandem with object-oriented languages. So it's true as others have pointed out that they can and do exist in other paradigms; I would argue that is evidence of the influence of OOP and the fact that its best ideas have been incorporated all over the place.
- bccdee 6y agoThose are just good programming principles in general though. Abstract data types, information-hiding, and separation-of-concerns were being done in C well before OOP was a thing. Granted, the information-hiding wasn't as sophisticated as it got once OOP was introduced, but I don't think it makes sense to attribute information-hiding to OOP as a result, especially since newer programming language have used visibility attributes in the absence of OOP classes.
- abecedarius 6y ago
- tasty_freeze 6y agoThe example given in the article is not compelling -- there are only two arguments in play, so passing two arguments directly instead of passing an object holding those two things isn't painful. To me the big win of classes isn't inheritance, it is that functions and related data live in a common scope. If you write your code as a bag of data structures and a bag of functions that you pass those ad-hoc data structures to, it is less clear which things play together.
- commandlinefan 6y agoNot only that, but the second example is object-oriented, he's just doing it "by hand" rather than taking advantage of the built-in language syntax (which, in spite of his insistence to the contrary, does make it clearer what's actually going on).
- socialdemocrat 6y agoI would say that is simply down you you not being experienced with writing code this way. Once you begin writing functional code more regularly, you will get much the opposite way of thinking. Today I find it frustrating that I need an object first. In my mind, I already know what action I want to do. I know what function I want to call. I start with that and look at what arguments it takes in. OOP programming is frustrating now, because instead of going straight for the function I have to locate the appropriate object first. That is like a big detour. > If you write your code as a bag of data structures and a bag of functions that you pass those ad-hoc data structures to, it is less clear which things play together. Noting suggest you need to write code like that. People who write functional code tend to have a lot of well defined data types. I use well defined data types in Julia. Haskell and OCaml developers use well defined data types. We are not using using dictionaries or something.
- digianarchist 6y agoThis is exactly how I felt after learning Elixir and then coming back to Python. Object orchestration is painful.
- acdha 6y agoThis post says more about the author's experience than Python, especially with the list of exceptions. The common pattern behind those exceptions is that they're not as simple as the examples, which gets to a better lesson that OO is not pointless but that you should use it cautiously when you know that your problem domain has a sufficiently complex combination of state and code. Anything is going to seem simpler when you have 2 variables and the whole thing is 20 lines and while it's definitely useful to pause before accreting complexity it's also important to remember that projects and teams come in many different forms and there's no guarantee that something which works for you on a project now will be the best option for someone else with different needs.
- leontrolski 6y agoHi, I think you're correct in some domains - I probably should have spelt out that I'm by-and-large talking about application development, where if you have a "sufficiently complex combination of state and code" you probably have a problem rather than a candidate for wrapping in a class.
- yowlingcat 6y ago> where if you have a "sufficiently complex combination of state and code" you probably have a problem rather than a candidate for wrapping in a class Ironically, I think most people in that situation would agree with you that they "probably have a problem" -- the difference is that they see the problem as the important thing to focus investing resources into solving whereas you see its existence as an inherently poisoned entity that must be conceptually purified. While both parties would probably agree on the existence of /a/ problem, the definition of what needs to be addressed and how is likely to differ, and I can't say that the latter attitude is the norm at any high productivity engineering organization I've ever worked at, built, or encountered.
- acdha 6y ago> I probably should have spelt out that I'm by-and-large talking about application development I was as well. My point is just that not everyone works on the same things or has the same resources, and there is no global optimum. I'm generally in the “more functions, fewer classes, minimize inheritance” camp personally but the most important underlying principal is remembering that methodology is a tool which is supposed to help, not hinder, and adjusting based on local conditions. Part of the value an experienced developer brings should be having a good sense for when a particular approach is a good fit for the problem at hand and being willing to say that whatever you're doing needs changes. This can be tricky because methodologies often have a quasi religious aspect where people take the decisions very personally but the worst project outcomes I've seen have been from cases where people treated the status quo as holy writ and refused to consider how problems could be avoided or transformed by picking something different.
- blt 6y agoOne good use for Python's OOP is operator overloading. Since Python doesn't have type signatures, you can't overload the "plus" operator with a free function like you can in C++. Writing numerical code without operator overloading is painful.
- ben509 6y agoI'd argue that's not object-oriented programming. You are using Python's class mechanism, but that's where the OOness ends. The types themselves are immutable value types, carrying no state and reacting to no messages, and they don't exploit a class hierarchy beyond having a common "Number" class. The "methods" don't even behave like methods, e.g. __add__(self, other) has special wiring so it obscures which side of the addition is "self". That's very different than a classic OO scheme like a UI toolkit.
- blt 6y agoTrue!
- jmkr 6y agoWhy not have the client stored in a dictionary, it's just a url location, instead of having a dataclass? You don't even need a "construct_url" function.
- tabulatouch 6y agoOOP is meant for re-use across different projects. Frameworks, or self-contained classes.
- gorgoiler 6y agoIn general, object orientation is a reasonably elegant way of binding together a compound data type and functions that operate on that data type. Let us accept this at least, and be happy to use it if we want to! It is useful. What are emphatically not pretty or useful are Python’s leading underscores to loosely enforce encapsulation. Ugh. I’d sooner use camelCase. Nor do I find charming the belligerent lack of any magical syntactic sugar for `self`. Does Python force you to pass it as an argument to make some kind of clever point? Are there psychotic devs out there who call it something other than `self`? Yuck! And why are some classes (int, str, float) allowed to be lower case but when I try to join that club I draw the ire from the linters? The arrogance! ...but I still adore Python. People call these things imperfections but it’s just who we are. PS I liked the Python5 joke a lot.
- dfinninger 6y agoJust to discuss one point: > And why are some classes (int, str, float) allowed to be lower case Also, boolean. These are primitive data types. For instance, in Java there's a difference between int and Integer. I'd assume that Python special-cases these because they are primitive. But I haven't been through the Python internals, so it's only a guess.
- rbanffy 6y agoThey are far less primitive than Java's - they are classes too, but can't be extended.
- deleted 6y ago[deleted]
- BerislavLopac 6y agoI'm not sure which language did you mean there, but in Python those classes can be extended. Also, the main reasons for special cases are historical; also, they predate PEP8 by a long time.
- 6y ago
- ben509 6y agoI think OO caught on because it encourages people to organize their thoughts, and good structure alone brings a tremendous improvement in code. I think the reaction to it is more the "everything is mutable" approach most OO languages took, which led to things that looked organized but that were a hot mess of side-effects. With dataclasses (or attrs) you can cut back on that by freezing everything, and still get the clarity of methods that lay out the essential functionality of a type. In their own example, "get_items" and "save_items" make a bit more sense if they're stashed away in the Client namespace, and you can see that they're essential to what a Client does. And while Oil's conjecture is probably right, I'm not sure it survives if you add the caveat, "in that same language." For instance, Python doesn't have a native way of expressing sum types outside of inheritance. That's not to say inheritance, especially an always open style, is a good way of working with a sum type, it's just the only native way.
- andrewstuart 6y agoI found Python OO to be a super elegant and practical way to implement a common API for multiple databases.
- nerpderp82 6y agoOne doesn't need OO for that tho, the module system applies just as well to solving that problem.
- snidane 6y agoModule corresponds to a class, not to an object. Afaik, you can't instantiate a module in python multiple times with different parameters. In theory you would like to do this, but it is not supported in python, therefore you would use classes as poor man's modules. conn = import Database(host=..., user=...)
- 0xTJ 6y agoThis is - as the kids put it - a very hot take.
- canada2us 6y agoOne will appreciate OO once he/she saw a 2000-line code in a single file.
- bccdee 6y agoYou don't need to use classes to break a big file into several smaller files.
- banthar 6y agoObject oriented programming is not about defining classes. It's about using objects. You don't have to define new classes to do OOP. Just use existing classes and objects polymorphically! url_layout.format() resp.raise_for_status() resp.json() session.add() All those calls are dynamically dispatched - the essence of object oriented programming. This is what allows you to not worry about: * which string implementation `url_layout` uses * which HTTP protocol, encryption, authentication, chunking `resp` uses * what database is connected to `session` You cannot avoid using objects - that's how all modern operating systems work. Using classes without the need to call them polimorphically just as a nice namespace for methods is a separate issue.
- ed25519FUUU 6y agoLargely I agree with the author's sentiment, but I'm not sure I totally agree with some of the alternatives. For example I think using an @lru_cache decorator over a `get_...()` function to return variables is much better at all than using a global var. In fact, it looks hackier if you ask me. https://leontrolski.github.io/sane-config.html https://leontrolski.github.io/sane-config.html
- OnlyMortal 6y agoNonsense. Everything been a dictionary is incredibly important.
- david422 6y agoOOP also works well when you want different _behavior_. In your bag of functions you have the same behavior for all objects. If you want different behavior, you're going to have to start adding branches in code that really has no business making those branch decisions.
- gfalcao 6y agoI disagree that it's mostly pointless because if you're practicing Test-driven development OO provides a great way to abstract agents and their actions. I've seen a lot of python code that looks like the example from the blog but that's simply just a narrow example and does not reflect all the potential of OO, not only in Python but in any programming language. The thing I see in common in such poorly designed OO code is that it is usually not covered with unit tests that are actually useful and informative. Sometimes it's just not even tested at all.
- gfalcao 6y agoAt the end it comes down to how the developer designs their software, as Fred Brooks argued in "No Silver Bullet" (https://en.wikipedia.org/wiki/No_Silver_Bullet https://en.wikipedia.org/wiki/No_Silver_Bullet) Brooks goes on to argue that there is a difference between "good" designers and "great" designers. He postulates that as programming is a creative process, some designers are inherently better than others. He suggests that there is as much as a tenfold difference between an ordinary designer and a great one. He then advocates treating star designers equally well as star managers, providing them not just with equal remuneration, but also all the perks of higher status: large office, staff, travel funds, etc.
- gfalcao 6y agoSection from "No Silver Bullet" Object-oriented programming. Many students of the art hold out more hope for object-oriented programming than for any of the other technical fads of the day. I am among them. Mark Sherman of Dartmouth notes that we must be careful to distin- guish two separate ideas that go under that name: abstract data types and hierarchical types, also called classes. The concept of the abstract data type is that an object's type should be defined by a name, a set of proper values, and a set of proper operations, rather than its storage structure, which should be hidden. Examples are Ada packages (with private types) or Modula's modules. Hierarchical types, such as Simula-67's classes, allow the definition of general interfaces that can be further refined by providing subordinate types. The two concepts are orthogonal — there may be hierarchies without hiding and hiding without hierarchies. Both concepts represent real advances in the art of building software. Each removes one more accidental difficulty from the process, allowing the designer to express the essence of his design without having to express large amounts of syntactic material that add no new information content. For both abstract types and hierarchical types, the result is to remove a higher-order sort of accidental difficulty and allow a higher-order expression of design. Nevertheless, such advances can do no more than to remove all the accidental difficulties from the expression of the design. The complexity of the design itself is essential; and such attacks make no change whatever in that. An order-of-magnitude gain can be made by object-oriented programming only if the unnecessary underbrush of type specification remaining today in our programming language is itself responsible for nine- tenths of the work involved in designing a program product. I doubt it.
- mywittyname 6y agoI write a lot of Python code. Objects are absent in most of what I write. But the 10% or so of the time I use objects, it is because objects are the best way I can think of to structure the program. So I don't think objects in Python are useless at all. I think Python is designed in a way that allows them to be used effectively if desired, or avoided all together when there's no apparent benefit.
- pmontra 6y agoI maintain a couple of Django projects for a customer of mine. I wrote almost 50% of the code base. Those two projects use very few classes, probably only the models. Everything else is a bag of functions organized in modules. It's very similar to an Elixir /Phoenix project I'm working on for another customer. Modules and functions and a couple of dozens of GenServers that act as objects to maintain status where we need it. And yet, I easily follow the OO model of Ruby of Rails. I feel it right in that context, probably because the rails of RoR are more well defined than the ones of Django. Of course when I script in Ruby I bet rarely write a class. A few functions, actually methods of Object, are all I need there.
- choppaface 6y agoI feel the major reason OO doesn't fit well in Python is because Python was designed to harness "duck typing," which enables polymorphism with less code. Furthermore, attrs / dataclass does away with a lot of the Object boilerplate that most developers would prefer not to write when moving quickly. To top it all off, context of use matters. For scripts without tests or limited extensibility, the value of OO is mostly in clarity to the reader, and here attrs / dataclass can be very concise and effective. That said, when the object jungle gets very large, Python gets a lot more tricky. Look at matplotlib or try to write a billing system with a variety of account and transaction types. Nevertheless it's nice for a post like this to call out the existence of the bijection between OO and 'non-OO' Python programming styles. The issue is worthy of contemplation for any early Python programmer once one gets the feet wet.
- mumblemumble 6y agoI'm not sure I follow. Python's duck typing explicitly relies on its object-oriented features. I'm not sure that it's even possible to implement duck typing in a language that isn't object-oriented.
- davidwf 6y agoI am not a language expert, but Clojure (inspired by CLOS IIRC) does method resolution based on an arbitrary function that can ask any "is it a duck?" question of the arguments: https://clojure.org/about/runtime_polymorphism https://clojure.org/about/runtime_polymorphism It's common for code to "choose" which method to call based on the class of the arguments, but it's also common to choose which method based on whether a particular key is in the hashmap, etc.
- mumblemumble 6y agoI suppose that this is edging dangerously close to starting a semantic argument, but I'd personally argue that ad-hoc polymorphism is a distinct concept from duck typing that just happens to have a lot of overlap in its use cases. One key distinction is that Clojure multimethods need to be explicitly declared somewhere, whereas duck typing is 100% implicit.
- mumblemumble 6y agoI don't know if one has really made any case at all about OOP, neither for nor against, if one hasn't considered cases that involve any sort of conditional branching. Because the key problem that OOP is supposed to solve is not lumping bits of data together. The problem that OOP is supposed to solve is using polymorphism to limit the proliferation of repetitive if-statements that need to be maintained every time the value they're switching on acquires a new interesting case to consider.
- bccdee 6y agoIn practice, I've found that kind of use case for polymorphic dispatch to not be especially common — meanwhile, most OO languages strongly encourage making everything objects. There's absolutely a time and place for a good abstract interface, but it's always struck me that classes are overused in general. That's why I really appreciate the go/rust model, where you can tack interfaces and methods onto structs if you want to, but there's no pressure to do so.
- mumblemumble 6y agoThe main reason why OO languages typically make everything objects is that having only one kind of type greatly simplifies the programming language and the experience of programming in it. There are only three common languages that are OO with a few non-object types: C++, Objective-C and Java. This feature is universally recognized as a serious wart in all three of them. It creates all sorts of little edge cases that you need to learn to program around.
- blt 6y agoI'm curious to know which "serious warts" in C++ would be fixed by making everything an object.
- AlexSW 6y agoIndeed... in Java this is reasonably clear, but I've never found I have a problem in C++. I suppose if you're inheriting from your template argument and you template on an int? Seems awfully contrived and useless though.
- Mikhail_Edoshin 6y agoThis is basically how I use Python :) Truly, recently I tried to remember how to create a class method so that I can have different constructors and I forgot! Got back go just structures and functions. Most OO in most OO languages is just polymorphism and inheritance is merely a roundabout way to construct or traverse the method graph for polymorphic objects. It's often much easier to do polymorphism directly and only if you really need it: quite often you can fare well without polymorphism at all and simply write branching instructions. The useful OO must be about changing state in a controlled manner, but this remains largely unaddressed.
- nemetroid 6y agoWhen writing Python, I usually try to follow this item from the C++ Core Guidelines (replace "struct" with "dataclass"): > C.2: Use class if the class has an invariant; use struct if the data members can vary independently > An invariant is a logical condition for the members of an object that a constructor must establish for the public member functions to assume. After the invariant is established (typically by a constructor) every member function can be called for the object. An invariant can be stated informally (e.g., in a comment) or more formally using Expects. > If all data members can vary independently of each other, no invariant is possible. https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rc-struct https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines...
- zmmmmm 6y agoSo the example manages to evade any need for encapsulation. It's viable because the internal hidden state is so cheap to compute (the full URL) that it can afford to reconstruct it within every call. But imagine if constructing the url was a more expensive operation. Perhaps it has to read from disk or even make a database call. Now you really need to cache that as internal state. But doing that means external manipulation of root_url or url_layout will break things. Those operations need to be protected now. So do you make "set_url_layout" and "set_root_url" functions? And hope people know they have to call those and not manipulate the attributes directly? Probably you'd feel safer if you can put that state into a protected data structure that isn't so easily visible. It makes it clear those are not for external manipulation and you should only be interacting with the data through its "public interface". Of course this brings about all the evils of impure functions, mutated state etc. But if you are going hardcore functional in the first place then it becomes rather obvious OO is not going to fit well there, so its a bit of a redundant argument then.
- brundolf 6y agoI don't think the OP makes very good points, but one thing to point out is that Python only has access-control by convention. This creates a wrinkle for any argument based on using "protected data structures"
- theamk 6y agoWe use python extensively, and I think python's "access control by convention" is pretty great. The reason for access control is not to protect from malicious programmers -- it is protect from programmers who don't know better and from honest mistakes. So all you need is a simple rule ("don't access private methods") and now everyone knows which fields are public (and thus are OK to use) and which fields can disappear any moment. For extra enforcement, you can add pylint to your CI so it flags all the protected accesses. But really, a good team culture is often enough.
- Blikkentrekker 6y ago> So the example manages to evade any need for encapsulation. In Scheme and many other lisps there is no difference between “objects” and “records” and “fields” and “methods”. Defining a record with a number of fields also defines accessor functions, such that: (define-record point (fields (mutable x) (mutable y))) defines the following procedures: make-point point? point-x point-y point-set-x! point-set-y! All these names can optionally be changed to something else. Encapsulation is simply enforced by not exporting any of these procedures from the module wherein they are defined. Any arbitrarily more complicated functions can be built on top of these which can be exported. As such, there is no meaningful difference any more between an object and a record, there is no special “dot notation” for field access and method calls, and normal procedure calls are used. This follows the general lisp design principle of avoiding special syntax as much as possible and using ordinary procedure calls for everything. There is no special “subscript notation” for `vector[i]` either, and `(vector-ref vector i)` is used instead.
- jennyyang 6y agoPointing to someone's bad code example and saying "This is why all OO is pointless", is truly a lazy effort. Good OOP is good. Bad OOP is bad. That's like every other piece of coding. Some excellent examples of great OO code that I've worked with have to do with having an abstract class to define a data api, and then being able to switch providers seamlessly because the internal interface is the same, and all you need to do is write a vendor-specific inherited class.
- sweezyjeezy 6y ago> Good OOP is good That's not the point - the rub is that good OOP is HARD. People get sold on it with examples like your data API, where the abstractions are clear, and reasonably static, whereas for most problems, and for most developers, it's genuinely difficult to get this right.
- hn_saver 6y agoHi Can you please link to some examples of python great OO code?
- yowlingcat 6y agoHow long has the author used Python? OO, while responsible for much of the footguns, is also responsible for an enormous amount of Python's expressive power. Being able iterate or key into arbitrary objects as if they were lists or dictionaries is enormously powerful, but all of that structure is OO based. It's a huge part of what "pythonic" means. > If you've taken the pure-FP/hexagonal-architecture pill Writing software is not something you take a conceptual "pill" for. You learn new tools that you add to your toolchest and use at your own discretion. Tools which purport to be able to displace a whole arena of otherwise stable, mature, and high productivity tools better be at least comparable if not significantly better to encourage upgrade. FP as a tool definitely comes in handy for quite a few use cases. FP as an ideology? Not so much. Regarding the latter, I'm getting a little sick of the FP chauvinism that that pretends that pre-existing software and how it was written is obviously inferior to the new, purely FP way without any real persuasive evidence. Code that's written in an overly FP oriented way is no less immune to the same codebase diseases that code written in an overly OO oriented way is. It's the map-territory problem all over again.
- Geminidog 6y agoThat’s because the ideologists operate based on intuition rather then identifying the exact reason why one paradigm is better. OO is bad because it promotes writing logic with free variables and context. Logic that relies on free variables and context is inherently less modular. Lack of modularity is the root of all structural technical debt. While FP doesn’t force someone to eliminate context or free variables it certainly does not promote writing logic that includes it by default. This generally leads to more modular code. Hence the reason why FP just "feels" better to practitioners and leads to people promoting it without clear reasoning. This in turn makes the promotion of FP seem "ideological." Maximizing modularity in code requires greater restrictions then the ones FP provides, but FP in general is heading in the right direction.
- nicbou 6y agoDjango's class-based views are a perfect example of well-written OO python. A view takes a request, gets some data, and renders a response. Each part of the process (and its subparts) is abstracted in methods that can be overridden. This lets you implement certain things (authentication, formatting, compression, caching, logging, pagination) once in an abstract class or mixin, and add it to all your views. Of course, Django already has those classes and mixins. This means you can write very simple views. Just define the queryset and the template, and you're done. Everything else just works, because it's already implemented in well-tested parent classes.
- dvfjsdhgfv 6y agoWhen Python was being conceived OOP was all the rage, with "everything is an object in Python" motto. Even if you want, you can't have bare structs, you need to create a class. At this point refusing to add a method to it and using external functions to modify its state is just a matter of taste - in many cases it makes sense, and in several it doesn't.
- reedwolf 6y agoThems fightin words.
- m4r35n357 6y agoahem, operator overloading
- benkuhn 6y agoThe author’s OO example is hard to understand, but they’re wrong about why. It’s not bad because it’s OO, but that it’s very badly done OO: the class couples two different concerns (network API client and database). That’s why it makes more sense as a bag of functions. The general version of the point doesn’t work very well, and many of the other OO use-cases the author discusses actually work much better than alternatives. For example, on abstract base classes: if you replace this with a bag of functions I think you end up reinventing virtual dispatch—that is, each function’s top level is a bunch of `if isinstance(...)` branches. This is much harder to read, and harder to add new implementations to, than abstract methods. It’s also no easier to understand. (There is a subset of this advice that I think does improve your code’s understandability, which is “only ever override abstract methods,” but that is very different from “don’t use OO.”) For impure classes, the author suggests e.g. using `responses` (an HTTP-level mocking library) instead of encapsulating these behind an interface. This is a fine pattern for simple stuff, but it is not more understandable than a fake interface. The hand-written fake HTTP responses you end up having to write are a lot less readable than a mock implementation of a purpose-built Python interface. (Source: I once mocked a lot of XML-RPC APIs with `responses` before I knew better; it was not understandable.)
- throwaway894345 6y ago> It’s not bad because it’s OO, but that it’s very badly done OO This argument seems to come up for every criticism of OO. The criticism is invalid because true OO would never do that. It seems like a No True Scotsman. Notably, when you whittle away all of the things that aren’t true OOP, you seem to be left with something that looks functional or data-oriented (something like idiomatic Go or Rust). There isn’t much remaining that might characterize it as a distinct paradigm.
- na85 6y agoI disagree. Good OO is about encapsulation of concerns. Make a Client object and push data to it; let the class worry about the networking and sockets. Make another object to deal with the database. For sufficiently complex systems I don't see how functional or other paradigms can manage without holding a huge amount of global state.
- KaiserPro 6y agoHaving recently started a script that avoided OO because I wrongly assumed that its was going to be 4 functions and done, I disagree. I don't care about inheritance, that's just a way for someone to trip you up and make them feel smug about being "elegant" I don't care for people trying to hide stuff with self._hiddenThing. Its python, nothing is hidden. If I want to reach in and grab your class by the ankles, prepending a "_" isn't going to stop me. I agree wholeheartedly with dataclasses. I just wish that type annotations were actually enforced at run time. At the moment they are only really useful if you have pyre turned up to 11 (bye bye productivity) or have an IDE that understands type hints. but, the hill I will die on is this: storing class state in self.blah. It is correct and proper to do that in a class, it limits the amount of args I have to shove into a function/method, it also allows me to pull out and check things before I do them. Yes they can be abused. Yes it means that you need to call functions in order. Yes it means you have to be more defensive about missing state. But you need to be careful about that anyway. with minimal OO you can avoid a lot of typing and nasty verbose function args in python.
- luord 6y ago> It's somewhat just the return of global variables. No, it's not. This is far from the only objection/disagreement I have with the article, but I can take almost everything else as either opinions or convenient examples in support of those opinions. That sentence, though, just stuck with me as particularly odd because, among other things, using classes doesn't make you more likely to use global variables than using functions exclusively. And I'm not even talking about Python in specific. Anyhow, it had been a while, I think, since a post pitting FP against OOP had reached the front page, and thus causing yet another iteration of that traditional flamewar in the comments. Guess it was due.
- nemetroid 6y agoThe author doesn't mean literally globally scoped variables, but more generally data with a larger scope than necessary. For example, you might have instance methods that only need a small part of the "self" object, but they get access to the entire thing.
- noobermin 6y ago>It encourages you to mutate. I literally shouted "yes!" why throwing my fist in the air in solidarity. I will never understand how OOP became something such that warps everyone's minds. OOP is good for making clean and encapsulated types, beyond that the problems the author points out creep in encouraging bad behavior and obfuscating.
- deleted 6y ago[deleted]
- intrepidhero 6y agoI've underutilized Python's OO system and I've certainly overutilized it. The light bulb moment for me was when I read: "prefer composition to inheritance". Which Wikipedia tells me comes from "Design Patterns" but I'm pretty sure I remember the argument from "Working Effectively with Legacy Code." Obviously it's not a hard rule to avoid inheritance, but once I started asking myself, "Is this relationship an is or a has?", my designs got a lot better. And by better I mean they quit making me angry when I revisited them months later. PS. Highly recommend that book BTW. Especially (and somewhat ironically) for people designing new systems. Everything is eventually legacy. :-)
- Der_Einzige 6y agoUsually when someone says they hate OOP they really mean that they hate inheritance and no one taught them about composition.
- alfl 6y agoOO is about managing state. Generally, stateless code is easier to test and maintain. Around 2012 I started writing mostly functional code (in C++) to scratch my own maintainability itch. I kept doing it through a long sojourn in JavaScript and now Python. I haven’t looked back.
- kazinator 6y agoThe author has just replaced one mechanism for OO with another one. If you think you don't need OO, then prove it by doing this: # [0] is the root_url # [1] is the url_layout for formatting it: must contain {entity}. client_a = [ "https://client-a", "{root_url}/{entity}" ] If you have client.root_url type stuff in your program, then it's using some degree of OO. In he new program, this is obviously OOP: def construct_url(client: Client, entity: str) -> str: return client.url_layout.format(root_url=client.root_url, entity=entity) In the original program, inheritance was used to specialize the formatting behavior. That had to be somehow preserved. How it was preserved was by aggregating a layout string and delegating the formatting task to its layout. (I smell a Design Pattern, but we are not doing OO!) But that can be back-ported to the original program: class ApiClient: def __init__(self, root_url: str, session_cls: sessionmaker, layout: str): self.root_url = root_url self.session_cls = session_cls self.layout = layout def construct_url(self, entity: str) -> str: return self.layout.format(root_url=self.root_url, entity=entity) def get_items(self, entity: str) -> List[Item]: resp = requests.get(self.construct_url(entity)) resp.raise_for_status() return [Item(**n) for n in resp.json()["items"]] def save_items(self, entity: str) -> None: with scoped_session(self.session_cls) as session: session.add(self.get_items(entity)) client_a = ApiClient("https://client-a", session_cls, "{root_url}/{entity}") client_b = ApiClient("https://client-a", session_cls, "{root_url}/a/special/place/{entity}") client_a.save_items("bars") Also, the author eliminated the session_cls member variable, which is only used in the save_items function. That also can be done to the original: class ApiClient: def __init__(self, root_url: str, layout: str): self.root_url = root_url self.layout = layout def construct_url(self, entity: str) -> str: return self.layout.format(root_url=self.root_url, entity=entity) def get_items(self, entity: str) -> List[Item]: resp = requests.get(self.construct_url(entity)) resp.raise_for_status() return [Item(**n) for n in resp.json()["items"]] def save_items(self, session_cls: sessionmaker, entity: str) -> None: with scoped_session(self.session_cls) as session: session.add(self.get_items(entity)) client_a = ApiClient("https://client-a", "{root_url}/{entity}") client_b = ApiClient("https://client-a", "{root_url}/a/special/place/{entity}") client_a.save_items(session_cls, "bars") In the end, all the author shows it that if all we need is minor variations in formatting some string by sticking values into a template string, we might want to do exactly that and not whip out inheritance. But, note, that the original code can compile: The following performs the formatting job using code that can compile: class ClientA(ApiClient): def construct_url(self, entity: str) -> str: return f"{self.root_url}/{entity}" (If an f-string doesn't map to compiled code that doesn't interpret the format string at run-time, someone in Python-land has obvious work to do.) This uses run-time interpretation of a dynamically supplied format string": def construct_url(self, entity: str) -> str: return self.layout.format(root_url=self.root_url, entity=entity) Though that could be optimized by, say, storing JIT-ted code into the layout string the first time format is called, it probably isn't.
- fay59 6y agoI mean, it’s easy to say that OO is useless when you come up with a code example that doesn’t use features unique (or uniquely convenient) to OO languages. Throw in some inheritance or interfaces and it’ll be very different.
- jcoq 6y agoThe author has created a pseudo-class out of the module. There is still a family of functions operating on the same exact data. All that he has done is throw away the init and require more imports. Given that python is an object oriented language, the correct abstraction for this pseudo-class is... a class. As others have already pointed out, the example would benefit from a refactor that separates concerns but this so-called "functional" approach makes that harder to accomplish if these functions have been peppered throughout the codebase. I'm tired of people making trivial arrangements to a codebase like this and calling it "functional", losing most of the OOP benefits of python in the process. Maybe stop rearranging the chairs and get on with sailing the ship. Maybe I'm just a little salty today. ¯\_(ツ)_/¯
- magnusmundus 6y ago> stop rearranging the chairs and get on with sailing the ship I had never heard this before (though it even has a wiktionary entry), what a beautiful way to put it, thank you. It's really ridiculous, the amount of time we waste on readable, testable implementations with enough performance, just because they're not the proper version of an idea in the reviewer's mind. It's not what DDD says! This is not how Scrum works! That's not functional programming! These aren't real unit tests! One thing in common I notice in this sort of pointless bickering is that how they're always about how "X is not real/proper Y", and they almost never point out an actual antipattern you might need to avoid due to reasons. The argument is purely philosophical from the very beginning, without much thought on what the implications are, if any. And I'm beginning to attribute this to incompetence. Not always -- there is always that one colleague who's a genius thinker in one dimension, not quite focused on delivery, and that's fine. We all need the occasional course correction, we all stand on the shoulders of giants. But it's often enough that I feel I'm expected to give one of those acronyms, just so that the other person can use a preset line of scrutiny: nevermind paying any attention to whether the tests actually validate the program, or if the design is unambigous and extensible, etc. It's like a version of the "factory worker"-style developer -- you know, he who exists to be a pseudocode-to-actualcode translator, always expects a perfectly well-defined set of specs, a design to implement that within, and won't move a muscle except to complain about how everyone else isn't doing their job unless those are all satisfied. Yes, it's exhausting. Thank you for accommodating my rant if you read this far, dear reader; thank you OP for bringing out the salt I didn't realize I had today! Apologies if I digressed too far there.
- WoodenChair 6y ago> I've heard this style referred to as the bag-of-functions style. If your main point of abstraction is the subroutine/procedure/function that modifies state, then it’s called procedural[0]. No need to rename it. 0: https://en.m.wikipedia.org/wiki/Procedural_programming https://en.m.wikipedia.org/wiki/Procedural_programming
- welder 6y agoOver the years I've learned when you think something is pointless, you just don't have enough experience to see why it's useful. jphoward's comment is spot on.
- unoti 6y agoThe key thing I disagree about in the article is this: > What about interfaces/abstract base classes? Just try writing without them, I promise it's going to be OK. You could write the code without formal interfaces, but I hope you're going to at least put in comments that define what things you expect to be on the modules/objects you're plugging in. And hopefully your large system is composed of many modules that work together in harmony, as opposed to being just a huge mass of code. In any non-trivial codebase, having good interfaces / contracts is key to keeping a good clean design. You can make a nice clean large codebase without OO, but you can't without good clear interfaces. It's important to know what you can change in one part of the code without having to go change the rest of the code to adapt to that change. Python doesn't have the equivalent of C# interfaces or Java interfaces, but having a clear definition of what's expected is still helpful even in a dynamic language like Python. These definitions are helpful to make the code clear, maintainable, and understandable. At a bare minimum it's helpful to do that with comments, but doing that with something like python's ABC module is even better.
- 2iP1zbR 6y agothey should address these issues with significant OO syntax changes. let's call it python 4.
- beders 6y agoOO is applied for the wrong domains. A typical web app with a database back-end is probably the worst offender. Modelling your data with OO, fitting it somehow (ORM == OMG) into database tables and then use some annotation magic to turn those objects into JSON towards the frontend. Nothing there makes any sense whatsoever. I built several of those and used terrible ORMs. They are hard to change. They are hard to reason about and they consume massive amounts of memory as each transaction creates fresh sets of objects - because we can't share data between threads simply - we throw those objects away again. Gone is this whole ideal notion of objects being their own little agents, sending friendly messages between each other. And the fact that message passing is not well-defined in a concurrent context in most OO-languages puts the icing on the cake. (i.e. objects can receive messages (i.e. calls) from any thread at any time and need to deal with it. Most of the OO code you wrote today cannot.
- harimau777 6y agoI am disappointed that this is not about writing OO Python in point free style.
- shp0ngle 6y ago> You'll notice I put @dataclasss in the refactored code, these are fine - they're just record types. Python 5 will only have these, not 'normal' classes. What is Python 5? Or is that supposed to be some inside joke?
- jgwil2 6y agoCurrent version of Python is 3. It doesn't sound like there are any plans for Python 4[0], so I assume this is just a joke. [0] https://twitter.com/gvanrossum/status/1306082472443084801 https://twitter.com/gvanrossum/status/1306082472443084801
- ExcavateGrandMa 6y agoPOO isn't useless... The main problem with programming patterns is that most ppl using them didn't understand the scope still :Ð
- Geminidog 6y agoThis guy makes a simple concept too complicated. The main thing that's different about python OO is the method. class SomeClass def someMethod(self: SomeClass, someVar: int) -> int: return self.x + somVar The explicit passing of context through "self" gives python methods combinator-like properties. Because of this, you can copy and paste the method and run it outside of the context of the class: def someMethod(self: SomeClass, someVar: int) -> int: return self.x + somVar The above will work in global context. This makes python code significantly more refactorable than other OO languages. For example C++: class SomeClass { int someMethod(int someVar) { return this.x + someVar; } } If you copy and paste the method outside of the class: int someMethod(int someVar) { return this.x + someVar; } It won't work. The python way just allows the method to be easily refactored to operate on a generic type (caveat: you have to ignore typing which the python interpreter actually does). Given a self.x, any value for self will be valid so long as it contains an x. Python does this automatically and that is the main difference. The main problem with OO is unfortunately still not resolved under either example. OO promotes context to follow logic around preventing the logic from being reused in other contexts. Ultimately, this is what's needed for the greatest modularity: def someMethod(x: int, someVar: int) -> int: return x + someVar And although you can write the above with OO, the style ultimately promotes practices that steers programmers away it.
- sweezyjeezy 6y agoSurprised I had to scroll down this far to read this. Not just refactoring, also debugging. If there's a buggy method in a class somewhere, I can just copy the offending method into Jupyter, set self = a suitable instance of the class and start teasing apart what is going on line by line.
- Geminidog 6y agoWhy can't you just call the method on the instance directly? This is only useful for when a, is not quite the same type as the the class you're copying the method from.
- _ZeD_ 6y agoSo you're trading object with closures? The venerable master Qc Na was walking with his student, Anton. Hoping to prompt the master into a discussion, Anton said "Master, I have heard that objects are a very good thing - is this true?" Qc Na looked pityingly at his student and replied, "Foolish pupil - objects are merely a poor man's closures." Chastised, Anton took his leave from his master and returned to his cell, intent on studying closures. He carefully read the entire "Lambda: The Ultimate..." series of papers and its cousins, and implemented a small Scheme interpreter with a closure-based object system. He learned much, and looked forward to informing his master of his progress. On his next walk with Qc Na, Anton attempted to impress his master by saying "Master, I have diligently studied the matter, and now understand that objects are truly a poor man's closures." Qc Na responded by hitting Anton with his stick, saying "When will you learn? Closures are a poor man's object." At that moment, Anton became enlightened. From https://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg03277.html https://people.csail.mit.edu/gregs/ll1-discuss-archive-html/...
- andrewflnr 6y agoGood koan, utterly irrelevant here. OP is still using good old structures for their state, not closures.
- zer0tonin 6y agoI would not recommend trying to use closures in python.
- pansa2 6y agoWhy not? `nonlocal` is pretty straightforward, isn’t it?
- agumonkey 6y agoSlightly offtopic, what I liked about python OO is the smalltalkish vibe in relation to the syntactic overloads. Playing with dunder methods __or__ and all that is .. fun. I rarely try this in other languages but in python it's a very natural thing. ps: this is not a python fan comment. -- sent from my sml/nj
- asimjalis 6y agoMore interesting than OO is why it was so popular for so long. Why is programming so faddish?
- GizmoSwan 6y agoThe languages with full featured OO capability are slow to compile as interpreter. Less features -> faster to compile and run
- sriku 6y agoJulia shines with this style, especially since the way modules compose works much better with multiple dispatch that crosses module boundaries. Sometimes a few surprises crop up, but by and large it's such a pleasure to work with.
- childintime 6y agoSeeing is believing: could you translate an example to Julia?
- ddragon 6y agoThat example in Julia would look the exact same since it's a very simple example with just one object/struct and only one version of each function (so it doesn't even need function overloading, let alone multiple dispatch), which is also why it might not be a good example against Python OOP, even though I'm inclined to agree, since it doesn't even need single dispatch (which if needed can be achieved by functools.singledispatch in Python). The difference would start when you get later a different entity like for example an Organization. Now you have to either create a save_items_org (and check which one it is to choose the correct method) or you add the same check to save_items(Union[Client,Organization]...) and all other methods. If you had used the object then it would be client.save_items() or org.save_item(). Using functools.singledispatch or Julia, save_items(org...) and save_items(client...) will work like the object version and dispatch without trouble and keep as concise as the object version. Now, the difference with Julia, is that Python's native dispatch capability ends here. If you now want a method to link Users with Users, Users with Organizations and Organizations with Organizations (sorry for the weird usecase, I don't want to add more types) you can just implement in Julia a link(Users, Organization), link (Organization, Organization), link(User, User) and any combination and whatever combination of User and Organization you receive it will dispatch to the correct version (while in Python you'll be forced to do the runtime check with an if to choose the implementation). For example the product operator (*) in Julia has around 300 implementations for all kinds of combinations of arguments, and the compiler makes it extremely fast by inferring and doing static dispatch.
- sriku 6y ago
- mkl95 6y agoI have worked both on OO and functional Python projects, and my conclusion is that any coding approach in Python is pointless if you are not a disciplined developer, and you don't care about refactoring your code once in a while. For instance mature Flask apps usually have a mix of clean and barely readable modules. You can't force developers to care about whoever is going to replace them in the future. Some people care, some people don't.
- leontrolski 6y agoThere's a lot of backwards and forwards in the comments. What I'd really like is to test my conjecture - could people post/email me a (< 500 line, ideally not deep library code) bit of code that they think is "so innately OO friendly that the conjecture won't hold". Given some examples, I'll do a follow-up blog post.
- jayd16 6y agoHow about C#'s Task Parallel Library? There's a lot of complexity that is (imo elegantly) abstracted below the surface with the usage of inheritance, while still remaining very configurable and extendable. I'm not sure how you would go about replicating similar async/await sugar without tying functionality to Task instances but I'd like to see it.
- aidenn0 6y agoHow about file-like objects in python? Many file-like interfaces are necessarily stateful, and having the state wrapped in an object that encapsulates the state allows for graceful reuse. As a bonus, there's no need for inheritance in python due to duck typing.
- leontrolski 6y agoI think you could be on to something - that feels like an area with tightly coupled state and functionality. (Sorry for spamming this thread with comments like this), but would you mind emailing some example code, and we can test what happens?
- chriszhang 6y ago> How about file-like objects in python? Many file-like interfaces are necessarily stateful. Still the state and the functions that operate on them can be separated out. Right? No reason why the state and the functions need to be tied together inside a class.
- aidenn0 6y agoAre you suggesting everything that currently takes a file-loke object "f" instead takes "fstate" "fread" "fwrite" "fclose" "fflush"...?
- otabdeveloper4 6y ago> OO in Python is mostly pointless You could drop the "in Python" part and still be right. Functional programming won in the end; Python programmers these days are mostly using Python because of pandas and similar packages.
- alisnic 6y ago> The difference between OOP and FP is the first argument of the functions
- johndoe42377 6y agoI think HN should have some tools for demoting self-publishing attention-seeking narcissists with meaninless content. No, OO has been studied extensively for decades and the conclusion is that it is a good enough tool for modularity and establishing of abstraction barriers, especially in dynamic typed languages, even if not taken into extreme like Smalltalk did. Please, post your clickbait bullshit somewhere else.
- janosett 6y agoI agree, OO can be useful and this article doesn't add much to the conversation of when stateful objects and inheritance are the best choice vs. functions and composition vs. some hybrid. That said, please consider the community guidelines: "When disagreeing, please reply to the argument instead of calling names."
- okamiueru 6y agoIn this case, I don't see how he is name calling. It's a bit harsh, but he isn't replying to an argument. He's clearly stating his own opinion on the matter. Hacker news shouldn't devolve into click bait titles of age old questions. "Tabs vs spaces. A clear winner in productivity" "Common programming paradigm somehow useless - Says this person" And on and on. It's the mild version of shock journalism. It reaches exposure here, not because of the intellectual merit, but the contentious nature. Maybe not narcissistic, but certainly attention seeking.
- chriszhang 6y agoCalling someone a "narcissist" is clearly name calling. I did not find anything narcissistic in the OP's post. It is a controversial topic but nothing about it came off as narcissistic.
- okamiueru 6y agoI won't presume to know the intention behind the original comment that is now removed, and I did feel it went a bit too far in how harsh it was. It would also be presumptive to know what the article writer had in mind as well. That said, and this might be an age thing, I'm not sure. When I see these computer science concepts and constructs that were figured out half a decade ago or more, which have their particular usefulness and limitations. It is hard for me to believe intellectual honesty motivating those kinds of posts. It's the same recipe. Take something trivial, well understood, and write a post with a title that suggests something highly opinionated, and possibly contrary to what the reader might have experienced themselves. Then explain how in some use case, it doesn't fit very well. Then, maybe for the kicks of it, walk back on the original "click-baity" statement that got people to read it to begin with. And wrap it up as if there some deeper or more profound knowledge to be gained. I will admit, I haven't read the article, because my bullshit detector started ringing. When you've seen a hundred of these, you don't need to read one more. But I'll take a quick look now, for the sake of it. Yes, pretty much the same recipe as I mentioned. Perhaps slightly less pointless than I had expected.
- arghwhat 6y agoBoth examples are OO. OO with and without syntactic sugar for methods of course, but both are 100% OO regardless. The implicit instance argument had just been replaced by an explicit instance argument. Programming paradigms have nothing to do with syntactic sugar.
- StreamBright 6y agoI agree with this assessment. I try to use OOP in Python but I found it useful in a very small amount of situations. Mostly it is just annoying to have the same function defined with (self, ...) and without when not using OOP.
- franga2000 6y agoThe issue the article presents is neither unique to Python, nor a good criticism of the OO model, so I'm not sure what to take away from this. One thing I haven't seen many comments talk about is how methods as far more discoverable and memorable than functions. Let's say I have a User object. How do I get their (calculated) age? In OO, I can pretty much guess and let autocomplete do the rest: u.get<TAB> and I immediately see getAge(), along with everything else I can get from the object - much easier than looking through documentation or a huge list of functions. I used to teach highschoolers how to write basic Minecraft plugins as quick intro to Java and the first thing I taught them was to write the name of the variable, then a dot, then press CTRL+Space. This worked absolutely brilliantly and it meant that they really didn't have to think about types and naming conventions all that much. Is it player_teleport() or entity_teleport()? What about NPCs? Nobody cares! thing.teleport() worked on anything you could reasonably be expected to teleport and everyone just understood that with basically no prior programming experience.
- namelosw 6y agoI can get what the author is trying to say. But the article missed the most important point - OO for dynamically typed languages like Python/Ruby/JavaScript is for polymorphism, so that you can write a function accept an object that has print() method without knowing what it is. Languages extensively use the 'bag-of-functions' style usually have a way to dispatch functions based on type, so that people can extend packages without having to modify the source code. It could be multi-methods in Clojure, protocols in Elixir, polymorphic modules in OCaml, or even powerful ones like type classes in Haskell. But yeah, I agree 'bag-of-functions' is generally a net win in terms of language design - if the polymorphism counterpart exists.
- TristanBall 6y agoCouldn't agree more. I'm a sysadmin living in a powershell world right now, and the ability to abstract away "things that mostly behave like filesystems, but aren't” behind some classes with standard interfaces is extremely useful, as it clarifies the actual logic of the code a lot, and means I can support different backends usually with just a new class I absolutely could have done it without classes, in fact I did that first, until it clicked that I really was doing things the dumb way. Everything else is a bag of functions.. its only a couple of thousand lines of code, but limited OO was still very useful, and to me, more elegant
- oakpond 6y agoIsn't OO entirely pointless if you don't know what should be an object and what shouldn't?
- timonoko 6y agoI barely understand what this dudeson is aiming at. There is no need for OO-architecture if there is only one client for your services. He may not know that in python you can declare class Global: i=42 And then use it right away Global.i+=13 No inheritance-shit needed at all.
- enforcer 6y agoI don't think a few code snippets prove the point. My conjecture is that any complex enough piece of code with essentially (not accidentally!) convoluted concepts will benefit from OOP more than any other style Can we just appreciate the fact Python is such a Swiss Army Knife and allows for multi-paradigm approach? Let's just not use low "bashing" of any paradigm as an excuse to neglect the design. In some other thread someone mentioned lack of quality metrics. Well, this question has been asked previously, a recommended read from me: http://www.wirfs-brock.com/PDFs/How%20Designs%20Differ.pdf http://www.wirfs-brock.com/PDFs/How%20Designs%20Differ.pdf