Live data from Hacker News

Things Java Programmers can learn from Clojure

lispcast.com

21–30 of 58 posts

Re: Things Java Programmers can learn from Clojure

#21
post #8

I thought that classes+methods were meant to transform an object from one consistent state to another consistent state. So why is immutability suddenly a big deal? (I.e., if it's a big deal, may it be because encapsulation is lacking? IOW, is immutability a rediscovered "private" keyword, just much more cumbersome to use?)

Because the particular style of OO you're describing has turned out not to work very well. It turns out that often you can't effectively encapsulate state in a class such that no one else but the class itself needs to know about that state.

As the size of a class grows, mutable member variables approach globals. If you wisely break the class into smaller ones, classes will still contain instances of other classes, so to reason about the behaviour of your class you often have to understand the possible state of its sub-instances. This is especially true if multiple classes reference the same instance.

Re: Things Java Programmers can learn from Clojure

#22
post #15
post #7

Earlier quoted context omitted.

Yeah, replying to myself. I'm not sure if that's considered weird but ok. According to this logic, most mainstream languages don't make sense. Notably, Java, C#, C, C++, Clojure are all screwed up. Not sure about other lisps. Ruby, PHP, JavaScript, Python, F#, Scala and Haskell have it right though. (yeah sure, you can do mutability in Scala and immutability in Java, but the languages and their community lean toward…

Clojure's dynamic typing is somewhat different from other languages, though, as it really just has two non-atom types: seqs for collections and maps for data objects. Virtually all collections and objects can be manipulated as one of these two types. So "calling a method" on an inappropriate type is basically passing an inappropriate map to a function. You might want to disallow it, but Clojure allows it for good rea…

> this makes it possible to have many data access/manipulation functions that work on all objects.

This is not actually true. Add proper type inference and structural typing, and it's perfectly possible to have all those generic data manipulation functions while also having strong static typing.

Re: Things Java Programmers can learn from Clojure

#23
post #19

Re >2. Do no work in the constructor The author doesn't propose a solution here, so I'm worried he's thrown out the baby with the bath water. Yes, it's true that you should have no File IO in a constructor when it violates the SRP. At the same time (and as the author notes), it's very convenient to have Foo.fromFile(String path) or similar. Here's what I think the compromise looks like: public static OptimizedPage fr…

So yes - static factory methods - or, if it gets complex enough, a distinct factory object - are the right place to do work that would otherwise need to be done in the constructor. Use package-private constructors to enforce that people don't bypass them.

Re: Things Java Programmers can learn from Clojure

#24
post #15

Earlier quoted context omitted.

Clojure's dynamic typing is somewhat different from other languages, though, as it really just has two non-atom types: seqs for collections and maps for data objects. Virtually all collections and objects can be manipulated as one of these two types. So "calling a method" on an inappropriate type is basically passing an inappropriate map to a function. You might want to disallow it, but Clojure allows it for good rea…

> this makes it possible to have many data access/manipulation functions that work on all objects. This is not actually true. Add proper type inference and structural typing, and it's perfectly possible to have all those generic data manipulation functions while also having strong static typing.

But using structural typing (on the JVM, where Clojure lives) is slow, because it requires using reflection, which severely limits its use currently.

Re: Things Java Programmers can learn from Clojure

#25
post #6

Nice article. It does, however, trigger a thought: > By making values mutable, this magical-changing-at-a-distance is always a possibility. I agree, very much so. However, I could also simply promise that none of my code, nowhere, will modify that DateTime. On top of that, I'll ask all my colleagues to not mistreat it either. Now, that's what many of us are doing now, and the entire point if the OP's first section is…

Huh?

If I do this:

    (defn to-rubles [x] (* x 1.2))
    (to-rubles (java.util.Date.))
I get an error:

    ClassCastException java.util.Date cannot be cast to java.lang.Number
How is this unreasonable?

Re: Things Java Programmers can learn from Clojure

#26
What bothers me just a wee bit in section 1 of his example is that Date is more or less a simple container class for data - one that could be implemented as a HashMap.

It is easy to make classes like Date immutable, but that does not help with a lot of problems. Date is super-easy to test, only state, no logic. Similarly, static methods are easy to test.

The real pain in Java is when a class has both state and logic - and those are precisely the classes you cannot easily make immutable.

Re: Things Java Programmers can learn from Clojure

#27
post #9

Why these things in stay in books and blogs and never make their way into Java web apps: 1. Use immutable values: Models used in client server communication need to follow Java Bean spec which is like the exact antagonistic concept to immutability. Service methods that implement business logic are stateless. As objects are not shared across threads, nobody feels the need for immutability. The most popular frameworks…

(1) The "Java Bean spec" is not closely followed for precisely this reason. Technically it requires setters for all attributes but in practice many libraries (certainly Spring) permit initialization via the constructor and treat getters as sufficient.

(2) Because of (1) constructors are indeed still used. In fact they're very actively preferred because IF you use the constructor then all immutable attributes can be declared final making the compiler warn you of unintentionally altered state.

(3) I violently disagree. Vast interfaces are a code smell and would fail code review in every team I've ever worked in. If you can't do this then odds are in a deficiency not in the principle but in your understanding of the domain.

(4) Sounds like a problem with your process not the principle.

Re: Things Java Programmers can learn from Clojure

#28
OK but these things are not enough. I'm a long time Java dev and all these were known in c.l.j.p. and IRC since a very long time. I was doing precisely that, even using the "functional Java" libs when they came out and doing even more radical things...

And I can tell you that even when doing that switching to Clojure is pure joy.

Because even when doing what TFA talks about, this still doesn't solve lots of very nasty Java issues, like the totally outdated approach to concurrency.

What Java programmers can learn from Clojure is that it's possible to create a language targetting the JVM which cannot deadlock and which can offer a dramatic reduction in the size of the source code.

Sadly you simply cannot apply these to "Java the language": Java is utterly verbose and there's no way to have a "sane" way to deal with concurrency in Java (yes, I've got my Java "Concurrency In Practice" copy since it came out).

The other major thing to learn about Clojure + Datomic is that there's a world out there made of something else than the special kind of hell that Java/C# + ORM ([N]Hibernate) + XML + SQL is. (and before you start whining like cry-babies, Datomic can be backed by SQL DBs)

Programmers who haven't done it so yet should really go watch videos by Rich Hickey, here are three particularly good ones:

"Simple made easy"

"The value of values"

and "The Database as a value"

http://www.infoq.com/presentations/Datomic-Database-Value

Now sure some will criticize Clojure as being a Lisp-1 and not having real reader macros, others will rightly point out that Clojure's documentation sucks big times and that stacktraces are still a serious issue.

But at least Clojure is showing that there's a saner way than this Java madness.

You have to realize that Clojure is Rich Hickey's fourth attempt or so at a Lisp dialect and that he had lots of very painful experience working on Java Real-World [TM] maddening codebases.

Re: Things Java Programmers can learn from Clojure

#29
post #6

Nice article. It does, however, trigger a thought: > By making values mutable, this magical-changing-at-a-distance is always a possibility. I agree, very much so. However, I could also simply promise that none of my code, nowhere, will modify that DateTime. On top of that, I'll ask all my colleagues to not mistreat it either. Now, that's what many of us are doing now, and the entire point if the OP's first section is…

One difference is that in dynamic typing, if the object doesn't have the method, the runtime will tell you it can't be done.

If you mutate DateTime when the rest of the code expects it not to change, the runtime will let you, and you'll only notice through a logic error somewhere, that probably won't be obvious until way too late and the error has propagated through your system and screwed a chunk of your data.

On a conservative/liberal scale, decisions seem less conservative if the stakes are higher.

Re: Things Java Programmers can learn from Clojure

#30
post #9

Why these things in stay in books and blogs and never make their way into Java web apps: 1. Use immutable values: Models used in client server communication need to follow Java Bean spec which is like the exact antagonistic concept to immutability. Service methods that implement business logic are stateless. As objects are not shared across threads, nobody feels the need for immutability. The most popular frameworks…

1: Just because some ubiquitous libraries have dictated a practice doesn't make it a good idea or a good model. In fact, Hibernate's tracking of mutable objects in the current session is one of the most painful things about it. There's nothing inherent about client server communication that forces beans on you?

2: That's good, but work in the constructor is by no means gone.

3: That sounds like god objects. "FinancialInstrumentService" is way too much functionality (or poorly named). Getting a current quote, getting historical quotes, doing quant-stuff and placing a trade are all completely separate concerns. Opening a document, saving it, printing it - all separate concerns that are better kept in separate interface. Now, there's little harm in having an implementation implement several interfaces if the implementations has much in common. Extra bonus: Easier to write tests for.

4: Mostly agree, but:

> Believe me in a quarterly release- developers get around only 3 weeks – rest is divided into BA, QA, UAT, freeze, deployment time.

I won't believe you, because I've worked on a team that pushed out releases every two weeks, and got 8-9 days development in for each.

Post reply on HN