Hacker News new | comments | show | ask | jobs | submit login

I think Clojure may be your answer; functional programming with access to Java's enormous libraries.

Regarding "betterness", it's a philosophical shift -- some problems are better suited to one domain or another. My favorite metaphor for functional programming is Unix pipes:

cat file | grep XYZ | sort -r -n | ...

There's no explicit state but you can track the flow... output a file, search for something, sort that result, pipe it somewhere else, etc.

Imperative/state-based programming forces you to give names to all those intermediate results, just so you can pass them along. Sometimes variables are just a place to hold data until you can pass them to the next function; functional programming makes that so easy you don't need the variable. And think about how much easier it is to debug; once you get a part of the pipeline working, you can move to the next part (without worrying about global variables and other hidden interactions that can happen with imperative programming).




I second taking a look at Clojure.

Also, your comment of:

The world is imperative! Things have state! We do not live in an imaginary fluffy world of mathematical elegance & correctness.

I would check out article by Rick Hickey on state on the Clojure website:

http://clojure.org/state

It will get you thinking about how often your objects really need to have "state".


I wanted to write about Clojure and the fact that it has access to all of Java libraries, but you overdid me. So I'll mention F# which is in a similar position in the .NET world.


How is that not just:

cat(file).grep('XYZ').sort... ?


Good question. I'm not an expert in functional programming but it's changed my mindset.

Imperative / functional languages are equally powerful, but are they equally expressive? There's a reason I wrote the above in a shell script vs. an OO-language (or C): shell scripting captures my intent with minimal overhead, with the right primitives built-in.

OO-languages force you to define classes, methods, type input parameters, etc. up front. So if you know you just want that exact workflow then you can model it.

What if I want to customize the sort routine? Well, I guess I can define a sorting interface and take that as an argument.

And what if I want a more flexible data structure? (With unix it's all text, but why not a hashmap being passed around?). Well, I can define a generic "list" class with an infinite number of members, and all the operations change this list.

But now we've gotten away from OO programming (saying data is of type "List" is not saying much at all).

We're basically trying to recreate functional programming ideas:

* Simple, flexible, built-in data structures (list of lists)

* Pass around functions at runtime, as you please (no interface to define, instantiate an object of that interface, and pass in)

* Composable functions (at runtime, decide that function Z is really F(G(x)))

It's not that the operations aren't possible, but OO languages seem to lead you down a specification-first path, usually customized to a problem domain.

You can "get around" this by using design patterns like Strategy, but again, you're recreating functional ideas in another language. Not that it's impossible, but it's not quite suited for the problem domain (like doing text processing in C vs. using perl... yes, you can find a regex lib, and a better string class, but why not use a language with it built in?).

Hope this helps -- different languages help you think differently. I've used C# a lot and really love the mix of functional and imperative styles in the latest versions (3.5). Joel had a good post (http://www.joelonsoftware.com/items/2006/08/01.html) on this regarding map/reduce: it's not that it's "impossible" in OO languages, but you don't instinctively think about ideas like "passing around a function and apply it to data".


Your example is way different. You're operating on objects instead of return values. Rewriting what you gave:

  using namespace UnixUtilities;
  sort(grep(cat(filename), 'XYZ'));
No object necessary. No storage necessary. For your example to work the object needs to store the result of each method call in some member variable. Why is that a bad thing? Because it's harder to reason about member variables (that could change) than return values (which will always be the same if there is no state).


The OO example works off of return values, and the next .method() is on the return value of the previous call. It's almost totally isomorphic to your example (calling a function with the output of another), and isn't even really very OO in and of itself.


Ah, of course. That's what I get for commenting when I'm tired. The only comment that I would make is that the dot notation is very OO, indicating the method on the right is a member of the class of the object on the left. The 'using namespace' in my code was used to indicate the methods I called were static, thereby decoupling them from a particular object.


You're right, the location the function/method lives is slightly different. When I said it wasn't really OO, it is because there's no data encapsulation going on. Just running methods on the output of another method. The line of code could belong in an OO system, but is not in itself OO.


Or:

   yourUtility = sort . grep "XYZ" . cat




Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | DMCA | Apply to YC | Contact

Search: