No, that's not why OO sucks
librador.com
librador.com
In programming, if you lose in the popularity politics badly enough, your tool will die. Just ask the Dolphin SmallTalk or Lisp Machine programmers.
:)
http://infoq.com/interviews/johnson-armstrong-oop/ http://erlang.org/pipermail/erlang-questions/2010-August/052...
I mean, you could critique C++, but at this point that seems kind of cruel. :)
From what I understand, a lot of universities do force students to use Java for many introductory courses, mine included (though we're migrating to Python.)
Compare these hello world programs for instance:
Java:
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, world!");
}
}
Python: print "Hello, world!"
Ruby: puts 'Hello, world!'In that case, why not teach Basic? Its hello world is just, print "Hello World"
Me, I don't mind Java so much, but the loads and loads of ceremonious bullshit that Java forces upon me is annoying and I absolutely despise web development in any of the existing tools[1]. I'd love something more friendly for what I do. (I would punt many adorable helpless kittens for a working C# on the JVM.)
[1] - Please don't reply to this to tell me I need to try Play. I have. It's not much better to work with, its developers are absentee and don't seem to want outside contributions, and it has no community to speak of. Not good.
Before Java EE, I was coding similar type of applications with CORBA frameworks, and before that RPC frameworks.
Now I am doing .NET, and we have to use a Java EE like framework as well.
Enterprise architecture has a Midas touch to make everything complex.
It's largely cultural (and though they aren't doing a great job the Play guys should be commended for trying), but no less a problem.
IOW: not everybody is in charge of what technology they use. Further, not everybody has the resources nor the inclination to rearrange their entire life (and that of their dependents) in order to start their own company, all because of Java.
And sometimes it's just kibitzing or venting or what have you.
While I'm here, what would you recommend as "a lighter OO implementation"?
If OO were reduced to a relatively minimal, agreed concept then fewer people would be rejecting it because of one or another piece of baggage
One way to see types are things with fundamentally different access pattern: individual entities, sequentially retrieved ones (e.g. lists), fixed-length ordered lists whose elements are accessed positionally (e.g. tuples/vectors, fixed-length maps whose keys are known at compile-time/records/objects can also be viewed this way), unordered collections of distinct entities (sets), etc. I'd argue Armstrong's view is similar to this based on what he put in Erlang.
I can't tell what the author's view is, aside from "a class is a data type". This suggests that he equates a type with the set of functions that can be called on something and not have the compiler or runtime blow up (or perhaps, the set of functions that the programmer, by putting them in the same file, has explicitly said won't blow-up, whether or not that set is correct or complete). This throws fundamentally different things like lists, tuples, sets onto the same level as Person, Account, and PayrollRecord—which are often just short-hand names for tuples with different arities or names for their elements' positions.
If one has the later view, confusion over the point 3 is understandable: creating a new type for time is easy, just do class Time and define a bunch of properties and methods. In Armstrong's example, time is just a 6-tuple (or 3-tuple if all you want is hms). If you wanted to store it or send it over the wire, anything that could handle a tuple of integers would already know how to use it. If one function calls the last member "sec" and another "second", they're local names, so it doesn't matter as long as they're both accessing the same member.
One can object that it's easy to write serializers or that a compiler or library could figure it out, or that having different names for the same data elements indicates inconsistency in code that should be caught earlier. De gustibus non est disputandum. But, don't throw up your hands and say "this makes no sense!" without considering another perspective first.
So this: { type: "hms", hour : 10, minute : 45, second : 16 }
is better than this:
["hms", 10, 25, 16 ]
Either go across the wire fine. The names are not just local names, they describe the meaning of the data.In the JavaScript world we would call the map an object.
Coupling N algorithms and M structures may lead to M * N implementations where you really want only N + M implementations.
Additionally, decoupling algorithms and structures will probably make you write better interfaces for your structures.
Beyond that, I think you're conflating how method bodies are placed in a file with "belonging to a class". I can define C++ methods outside of the class definition, but surely no one would say that such methods don't belong to a class.
And no, I'm not conflating those. In C++ and Java, classes are, among other things, namespaces. When you declare a method in a class, it ends up in that namespace. Where it is defined is unimportant.
It's not about getting "somewhere". It's called computer SCIENCE, remember?
This is particularly true when someone is talking about "what's wrong" with OOP
By putting the functions in the class definition, they become locked into that class. Other data structures could potentially make use of the function, but now they don't own it. I would say the alternative is a namespace, which you don't instantiate.
Armstrong's grief is the idea that the functionality for classes can then only come from direct lineage. As I understand it, though, the OO-heavy languages (Java, C#, probably others) lean much more heavily on interfaces now to mix in behavior, which gets away from that specific problem.
[EDIT] I forgot that interfaces don't give implementation, so the mixing is pretty limited.
Not sure what I think of the state issue, though. Too green on the functional stuff to say how else it should work. I would point out, though, that programs hide state from each other; couldn't objects just be the same thing on a smaller scale? (That is, an opaque interface with a few access points.) It really comes down to how well it's made in both cases.
This is probably a worthwhile tradeoff, but checking in hundreds of lines of code that do literally nothing is still a bad place to be.
response.setHeader("X-Foo", "Bar");
In a functional language we'd change the data structure directly: (assoc-in response [:headers "X-Foo"] "Bar")
If, for instance, 90% of your application can be factored out into static methods, OOP starts to look like the wrong paradigm.But there aren't strict dividing lines between these two types, you end up mixing and matching functions and data as you see fit to help organize things. So you might put state into your function classes, such as the DB connection in a DAO:
db = DBGetter.get("serverAddress;dbName;username;password;")
userDao = new UserDao(db)
User user = userDao.getUserById(123)
You might also end up putting functions in your data classes, but you might not. As an example, to calculate the distance between two addresses you could put the function in the Address class: float miles = address1.distanceTo(address2)
Or you could create a DistanceCalculator class that mostly just holds functions: float miles = distanceCalculator.distanceBetween(address1, address2)
There are pros and cons to either design, personally I would go with the second one, but the point is that you have a choice. OO provides a flexible framework and there are many ways to design your classes. That's why there are a bunch of books on OO patterns and best practices, to help design the structure of classes. You can even work in a very functional/stateless style if you want to.What OO gives you are tools for organizing your code but you can organize in many ways, some ways that help and some that hinder. As others have said, it's just a tool.
Code reuse. Functions that are tied to a data type are less likely to be reused, and if you find that you want to reuse one it will, a lot of the time, require major refactoring (perhaps you have to move the function to a parent class, or create an entirely new class that represents the thing that is common between this data type's use and other data types' use of the function).
Whereas if your data and function are never coupled you actually wind up writing more generic functions that don't care about the type they are operating on.
OO really isn't dogmatic in forcing one style or the other.
I don't get how "stick function X so that it's useable by class Y and Z" is relevant for consideration. As the name suggested, utility classes are function libraries that can be used by all.
Yeah it works fine most of the time, but it's a bit like the opposite of primitive obsession. You wouldn't use an Integer class for an index in a for loop.
In Java you have little choice but to dump it all in one place. Contrariwise, Python offers you more options; you can just make a module and put a bunch of top-level methods in there if you want. Go has some notion of "objects" but you can have methods or top-level functions in a given package. And so on.
What are the bunch of baggage and implication to use class as a way to organize functions?
I don't see the difference in usage you mentioned with Python module. Putting a bunch of "top-level" methods in a module is the same as putting a bunch of static methods in a class.
Why is this bad in Java, while in Python where all types are objects it is ok?
It is less convenient than it is on other languages, where the wrapper class is not needed.
Separating functions from data is not the natural initial solution in an OO language, and is done as a refinement. It is not promoted as a default solution.
At some point the language is getting in the way and it better to go with something that supports what you are doing.
Other than that, most use of OO is really just applying the language's OO structures to software idioms that exist outside OO, such as modules, or data hiding, or closures, and so forth.
The only times OO actively sucks is when you're trying to do non-OO stuff in a highly-OO language, such as trying to do algorithmic code in Java.
From my experience many are also pretty bad at doing ADTs in module based languages.
OO has quite a few powerful concepts, and not all languages that are OO based explore the same set of concepts.
This is why the best languages to work with, are the ones which offer multi-paradigms, allowing the developers to pick the best abstractions for each scenario.
This is why Modula-2 was named like that.
The original idea of ADT (Abstract Data Types) with modules, is that the module exports the public operations of your type along with its visible definition.
Then all operations on the ADT are done via the public operations.
This was the way of modular programming before OO became mainstream.
What people talk about the evilness of state really is the scope of the state. In a typical program, there could be global state in global variable, local state in function local variable, and the state passed around in function parameter. OO adds the instance level scope state for instance variables.
All these different levels of scoping are tools for programmers to manage the complexity in a program. If you don't like global scope, don't use it. If you don't like instance level scope, don't use it. Pure functional code are NOT appropriate 100% of the time. A global variable can be simpler and cleaner to get the job done. There are times for different tricks in a toolset. Use the right tool for the right problem.
edit: added the NOT. Bad omission completely changed the meaning.
To expand on that wrt OO: OO tells you to encapsulate state in objects, generally, and then ignore it b/c abstraction, implementation detail, etc. But state makes it harder to reason about your program because now (ostensibly) the same function gives different answers depending on when you call it, not just how you call it. It couples your program that much more tightly to the order of operations. It introduces a bunch of assumptions dispersed implicitly throughout your code, as everything else now has to ensure that it does the right thing when the order of operations and/or input is correct vs not. That leads to bugs.
The counter-narrative is along the lines of what you suggest, which is to reduce state to a very small and limited scope, and put up a bunch of red flags around it. You say "these answers can change and this is the place to handle all the possibilities." You handle it in as few places as possible, and not laterally, everywhere else a method call chain or where there is state which depends on other state. Haskell is an example of this idea taken to the Nth degree.
But "the right tool for the right problem" isn't that helpful, although I think it's a worthwhile sentiment. The goal is to get people to think about the complexity they add to their programs, not to lambaste them for their choices or take away those choices in the first place.
Let us not forget that tools themselves are designed, and some designs can be downright pathological. A kettle is a tool for making tea, but (in deference to Donald Norman) there is a reason we don't make kettles with the spout on the same side as the handle. Just because someone designed a tool to solve a particular problem does not mean that it's the best way to solve that problem. We can and should be critical of our tools without emotional attachment to them.
Actually, you can. The Clojure/Java interop is pretty good (http://clojure.org/java_interop, http://clojure.org/compilation) -- you can call Java from Clojure and Clojure from Java.
That said, I think Joe's original article against OO was ill-informed (which is surprising, given his status), and this article rightly points out that Joe's arguments are bogus.
I don't think anyone disagrees that religious battles are stupid. But to sweep all discussion about tools under the "hey man, different tools for different jobs" just avoids critical thinking. If you don't want to participate in these discussions, don't. It's like a discussion on Windows Phone 7 UI, and someone comes along and says "lol, doesn't matter, Windows Phone 7 will never take off".
I really do not understand why this tool argument comes up. Do you never evaluate the quality of your tools? I was planning to come up with a good analogy to some carpenter's tool that is objectively bad and not used any more, but then it turns out I know effectively nothing about carpentry.
The latter concept is what Alan Kay had in mind when he "invented" OO although arguably C++ and Java have really popularized OO as class-based programming.
I think the most multi-paradigm languages are certain lisps. As long as you only care about different declarative styles (basically the opposite of C), Haskell is surprisingly good: point-free programming is like stack-based programming and you can easily embed non-deterministic code as well. And you can write imperative code about as easily as writing functional code in PHP or C.