5 ms·
>Encapsulation, modularization, abstraction - let's not pick nits about the precise meaning of these terms, they are all about the same thing, really: Managing
by usrbinbash 5y ago
>Encapsulation, modularization, abstraction - let's not pick nits about the precise meaning of these terms, they are all about the same thing, really: Managing complexity of your own code.
The thing is, code complexity can be managed superbly without the concept of a class.
Golang doesn't have classes. C doesn't have classes. But both have structs and they have functions taking a pointer to, or a struct of type T. (what OO calls a "method" for some reason). So we can have "objects" as in, custom datatypes, and we can have functions to act on them.
And on top of that, we have modularization in libs and packages.
So, why do we need more complicated languages? "Show a locked door before you show a key" indeed.
- eitland 5y ago> What more do we need? Good languages with good IDE support? I'm old enough that at some point assembly and C were my favourite languages and PHP was what I was most productive in and Python was also something I enjoy. These days no way I go back for new projects. After Java "clicked" for me and the introduction of Java generics shortly afterwards it became my favourite language and later TypeScript and C# had been added to that list. I'm not to dumb, but I prefer using my smarts to develop programs, to work together or even pair program with the language to mold something, not to babysit languages that cannot even help me with trivial mistakes.
- zelphirkalt 5y agoIs not the point, that a language with optional typing can help you out with trivial mistakes, if you give it sufficient information? Java makes (made?) you give all the info all the time, even when you do not need its help. Java holds your hand in an annoying way. TypeScript does not because you can gradually add types to your program, but is based on the shakier foundations of JS.
- dmurray 5y agoYes, I would agree that structs are the solution to the complexity the author describes. But Python doesn't have structs: if you don't learn about classes you will probably eventually organize some data using dictionaries or heterogeneous tuples. In another language you might introduce structs first (C and Go only have structs, C++ has both classes and structs but they are the same thing) but in Python you don't have that option - you can use data classes or named tuples but those already need most of the ceremony you introduce for dealing with classes.
- willjp 5y agoIf it’s useful: Python now has dataclasses, they are very struct-like.
- Banana699 5y agoOO implies far far more than simply grouping data in a struct and passing it by reference.
- usrbinbash 5y agoSuch as? The only other things that come to mind when I think about "OOP" are: * inheritance, which at this point even lots of proponents of OOP have stopped defending * encapsulation, which usually gets thrown out the window at some point anyway in sizeable codebases * design patterns, which usually lead to loads of boilerplate code, and often hide implementation behind abstractions that serve little purpose other than to satisfy a design pattern...the best examples are the countless instances of "Dependency Injection" in situations where there is no choice of types to depend on.
- kaba0 5y agoHow is encapsulation thrown out the window in sizeable codebases?? It is the single most important thing OOP gives, and is used by the majority of all programmers and has solid empirical evidence for its usefulness.
- usrbinbash 5y agoCould I see some examples of this evidence? Let's consider a really simple object graph: A -> B C A holds a reference to B, C has no reference to other objects. A is responsible for Bs state. By the principles of encapsulation, B is part of As state. What if it turns out later, that C has business with B? It cannot pass a message to A, or B. So, we do this? A -> B <- C Wait, no, we can't do that, because then B would be part of Cs state, and we violate the encapsulation. So, we have 2 options: 1. C -> A -> B 2. C <- X -> A -> B Either we make C the god-object for A, or we introduce an abstract object X which holds references to A and C (but not to B, because, encapsulation). Both these implementations are problematic: in 1) A now becomes part of Cs state despite C having no business with A, and in 2) we introduce another entity in the codebase that serves no purpose other than as a mediator. And of course, A needs to be changed to accomodate passing the message through to B. And now a new requirement comes along, and suddenly B needs to be able to pass a message back to C without a prior call from C. B has no reference to A, X or C (because then these would become part of its state). So now we need a mechanism for B to mutate its own state being observed by A, which then mutates its own state to relay the message up to X, which then passes a message to C. And we haven't even started to talk about error handling yet. Very quickly, such code becomes incredibly complex, so what often happens in the wild, is: People simply do this: A -> B <-> C And at that point, there is no more encapsulation to speak of. B, and by extension B is part of A's state, and B is part of Cs state.
- kaba0 5y ago> The thing is, code complexity can be managed superbly without the concept of a class. It can be managed by modules/namespaces, but without even that (a la C), I really don’t see it managing complexity well. The important point of OOP is the visibility modifiers, not “methods on structs”, that would provide no added value whatsoever. What OOP allows is - as mentioned - not having to worry about the underlying details at call site. Eg, you have a class with some strict invariant that must be upheld. In case of structs you have to be careful not to manually change anything/only do it through the appropriate function. And the bad thing is that you can make sure that your modification is correct as per the implementation, but what classes allow for is that this enforced invariant will remain so even when the class is modified - while now your call site usage may not fulfill the needed constraints.
- usrbinbash 5y ago> The important point of OOP is the visibility modifiers, OOP is not required for implementation hiding. It can be done entirely by convention (eg. names starting with an underscore are internal and not to be used). Go took this a step further and simply enforces a convention at compile time: Any symbol in a package not starting with an uppercase letter, is internal and cannot be accessed by the consumer.
- kaba0 5y agoWell yeah, and typing doesn’t need enforcement by compilers, we just have to manually check their usages. Maybe we should go back to Hungarian notation! I mean, snark aside, I really don’t think that variable/field names should be overloaded with this functionality. But I have to agree that this functionality is indeed not much more than your mentioned convention.