18

For the entire past year I've been written Scala code (coming from a Java background). I really liked how you could create simpler and cleaner code, with vals, case classes, map/filter/lambda functions, implicits and the type inference. I've used it mostly for an Akka-based application.

This year I'm on a Scala project with a new team, who really like functional programming. They heavily use Scalaz, and the code is filled everywhere with applicatives, context bounds, reader/writer/state monad, even the main method is "wrapped" in an I/O monad. Their reasoning is that this makes the compiler "work for us" in asserting that the code is correct, and each function is free from side effects.

Even so, from my point of view all this syntax really gets in the way of the business logic. For instance, a type of "MyBusinessObject" is fine, as well are types like "List[MyBusinessObject]", "Option[MyBusinessObject]" or even "Future[MyBusinessObject]". They all have a clear meaning and purpose. On the other hand, code like:

def method[M[_]: Applicative] = {
  case (a, b) => (ca[M](a) |@| cb[M](b)) {
    case t @ (ra, rb) =>
      if (ra.result && rb.result) t.right
      else t.left
  }
}

does it add complexity to the program, or is it just me that I'm not used to this way of programming?

12
  • 6
    What's your objectively answerable question? Commented Apr 4, 2014 at 5:31
  • 1
    Looks like it leads to a ton of code with one or two letter variable names. Looks like APL a bit. That is not a complement.
    – user949300
    Commented Apr 4, 2014 at 6:09
  • 3
    I started playing with Haskell last year. It looked incredibly complex at the time, when I didn't understand concepts like currying, functors, monads, etc.. Haskell is similar to Scalaz in that it has a lot of short, symbolic functions, like >>= and <$>, which mean nothing until you know what they do. After learning what they mean, however, they read very naturally and quickly to me now. Not really an answer, just my objective experience with things like this. I use Scala as well, but have no experience with the Scalaz library.
    – KChaloux
    Commented Apr 4, 2014 at 12:24
  • 3
    You are just unfamiliar with the idioms. @user949300 short variables are not really a problem for lot of functional code (think about Math style conventions!). Also read Tony Morris' blog for a more in-depth discussion of what better conveys meaning, types or verbose variable names.
    – Andres F.
    Commented Apr 4, 2014 at 12:49
  • 3
    @user949300: short variable names are preferred locally, that's the same in the functional and imperative worlds (you wouldn't write for(i=0; i<7; ++i) { trivialOperation(i); } with some awkward trivialOperationCount variable, would you?) Now, functional programming languages with pattern matching will sometimes introduce some more variables where you'd just write out accessor method calls in OO. The result is generally more concise; perhaps a little less self-explanatory, but looking up the data declaration normally makes it clear quickly. Static typing helps a lot, it's not like in APL. Commented Apr 4, 2014 at 18:56

4 Answers 4

37

This has nothing to do with functional programming - you can find this kind of situation in context of any other programming language - developers who love the advanced constructs of "their" language so much that they ignore any common sense about readability and keeping things simple. I have encountered such a situation in C, C++, Perl, Java, C#, Basic, and other non-functional languages. It's not functional programming that adds complexity to code - programmers do.

Don't get me wrong, I don't recommend avoiding advanced language features - but it's important to find the right balance in the given context. When writing a generic library for the usage of >100,000 developers all over the world, there are different measures to apply as when you are writing an individual report generator just for your local office.

5
  • 8
    It also has a lot to do with the community. For a developer with a Java or C# background, the code is barely understandable (and his/her community wouldn't understand it either). But if you write Haskell, for example, and you don't use monads, applicatives, functors and so on, you are baffling that language's community. The "naturalness" of code is not inherent, but relative to its community and established practices.
    – Andres F.
    Commented Apr 4, 2014 at 12:55
  • 1
    This is hard to see because most of us come from imperative backgrounds, which sometimes leads us to make the wrong assumptions about what's natural.
    – Andres F.
    Commented Apr 4, 2014 at 12:56
  • just look at the SLT C++ library, that could be written to be so much more readable for the amateur Commented Apr 4, 2014 at 15:22
  • @ratchetfreak: I guess you mean STL. I think this is a very good example (and indeed, I had this in mind in my answer). Using template meta programming makes lots of sense when you are an STL programmer, because it makes the STL more reusable. And the people having to maintain that code are normally used to template metaprogramming, too. Using template metaprogramming in an STL-like fashion throughout your standard business application can easily lead to overcomplicated, hard to maintain code. One can surely find (rare) cases where TMP is fine even in business application, of cours.
    – Doc Brown
    Commented Apr 4, 2014 at 15:34
  • @DocBrown yeah dyslexia kicked in at the wrong time, but honestly if I had half a mind to (and much more time than I have now) I could rewrite many of the function bodies to be much more readable. Commented Apr 4, 2014 at 15:37
7

I would say that you not being accustomed to the way they code is at least part of the picture. I'm in a similar situation as you (coming from C# into F# and working with people with Haskell background), and while I find it an interesting experience, I do have moments when I'm banging my head against the wall, untangling a particularly convoluted point-free function composition just to get a hang of what's going on there. It's a cultural thing.

As for whether this particular code adds complexity to the program - I don't know. Agreed that a generic piece of code can be complex itself. But it's a utility, not a part of business logic. If you want to know whether it makes the codebase more complex or simpler, you would have to imagine how it would have to look without that piece of code. It's often the case with such generic constructs that they're complex themselves, but it's a complexity that you can fit on a single screen. In the same time they make the entire codebase a fair bit simpler. This particularly is the case with monads.

Then again, it also can be a case of 'art for art's sake', like @Doc Brown suggests. Can't rule it out either.

0
6

I would argue that in general functional programming reduces complexity by eliminating mutable state, thereby reducing the number of cases that must be considered when trying to understand how a section of code works.

However, functional programming makes higher degrees of abstraction possible, and while highly abstract code can be extremely useful it can also be difficult to understand because it is by definition divorced from the context which you would ordinarily use to guide your understanding. Your comment "They all have a clear meaning and purpose" about business objects is undoubtedly true, but is really a reflection of the fact that that logic is very specific to a need and context you already understand. The existence of a construct like Monad allows you to make something very useful with little effort, but the web is littered with pages trying to explain what a Monad is. That's abstraction for you.

Also, Scalaz was written by folks who had been eating and breathing FP for a long time; they wanted to bring functionality available in Haskell to Scala. In doing so they made no attempt to be pedagogical. Scalaz makes use of a vocabulary and style which seem clear and straightforward to the authors but alien to the uninitiated. Methods which are puzzling to the rest of us seemed so obvious to the authors, given their Haskell background, that they didn't even warrant a comment.

Furthermore, as a functional programming language Scala has some shortcomings (in part because the JVM has shortcomings) that forced the Scalaz authors to write uglier code in some cases. For example, the lack of general tail call elimination forces the use of trampolines in some code, and the lack of a "kind system" can complicate type signatures.

And finally, Scalaz makes great use of itself. That could be thought of as a sign of its power, but for the uninitiated it can make the source a puzzle -- any random piece of code you look at is likely to make use of something else that looks alien to you.

Hang in there. And this might help.

-3

Does it add complexity to the program, or is it just that you're not used to this way of programming?

Why do you think these possibilities aren't the same thing?

Well written code can be read by people who aren't familiar with the specific programming language. Some languages (BASIC, Pascal, etc) can be read and understood by school-children who have never even seen any programming languages before.

If someone who has experience with other languages and experience with Scala (and who I assume has worked with Scalaz for at least a week and has colleagues to explain the trickier things) is still confused; then that's proof that it has added complexity.

11
  • 11
    This is simply not true: "Well written code can be read by people who aren't familiar with the specific programming language."
    – Andres F.
    Commented Apr 4, 2014 at 12:57
  • @Andres: It is true... to a point. Well written code will separate the business logic from the implementation details, and the business logic should be readable, because most of what it is doing is making straightforward calls to well-named helper functions. Those helpers may use all kinds of language features, of course, and require heavy experience with the language and libraries to understand.
    – Ben Voigt
    Commented Apr 4, 2014 at 17:14
  • 4
    I believe the following is idiomatic APL: x[⍋x←6?40]. What do you think it does? I sure wouldn’t have known…
    – bdesham
    Commented Apr 4, 2014 at 18:15
  • 3
    @Brendan Only within the same paradigm (and even then, sometimes not). For example, Prolog, Java, and APL are so different that I would argue that if you only know one of those (and no other languages), you cannot read the other two, no matter how well you know the first one. (Seriously, in bdesham's example, how the devil are you supposed to interpret "christmas tree" if you don't know any APL?)
    – Izkata
    Commented Apr 5, 2014 at 4:19
  • 1
    Brendan, your definition of well-written is nonstandard. Well-written is always relative to the language and its community. A program in language X is well-written if it's not buggy, it's efficient and clear... for the given audience! This applies to written language in general, by the way: always know your audience. What is suitable for (say) a scientific paper is probably not suitable for an email to your mom.
    – Andres F.
    Commented Apr 5, 2014 at 13:31

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.