The Artima Developer Community
Sponsored Link

Weblogs Forum
What Do You Consider "Readable" Code?

34 replies on 3 pages. Most recent reply: Apr 15, 2009 1:24 PM by Marty Fried

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 34 replies on 3 pages [ « | 1 2 3 | » ]
James Iry

Posts: 85
Nickname: jiry
Registered: Nov, 2007

Re: What Do You Consider "Readable" Code? Posted: Mar 19, 2009 11:19 AM
Reply to this message Reply
Advertisement
> Can’t you write significantly higher level code with a
> good library that abstracts the details?
>
> // Java written in Java using google collections
>

> List<Person> minors = Collections2.filter(people,
> isMinorPredicate);
> List<Person> adults = Collections2.filter(people,
> isAdultPredicate);
>


Excellent point! But oops, missing some code

// Completely equivalent code written in Java using google collections
Predicate<Person> isMinorPredicate = new Predicate<Person>() {
public boolean apply(Person arg) {
return arg.age() < 18;
}
}

Predicate<Person> isAdultPredicate = Predicates.not(isMinorPredicate);

List<Person> minors = Collections2.filter(people, isMinorPredicate);
List<Person> adults = Collections2.filter(people, isAdultPredicate);


Okay, now we've got equivalent code. Is it surprising people write the loop rather than that? FWIW, I'm willing to grant you a tuple class and a partition method, so we can get to this

// Hypothetically extended Google collections
Pair<List<Person>,List<Person>> pair = Collections2.partition(people, new Predicate<Person>() {
public boolean apply(Person arg) {
return arg.age() < 18;
}
});
List<Person> minors = pair.get1();
List<Person> adults = pair.get2();


That helps a bit, no? Also more efficient than filtering twice. Now, imagine if the Java community would just embrace closures, we could get that down to 3 lines

// Hypothetical closure based api
Pair<List<Person>,List<Person>> pair = Collections2.partition(people, {Person p => p.age() < 18});
List<Person> minors = pair.get1();
List<Person> adults = pair.get2();


Even nicer. Really gets close to the real requirement. Not quite as nice without Scala's tuple extraction, but what're ya gonna do?

> I think 1 liners are just facades for 1K liners.

Why? does it help to think that way about Java? Consider all the hundreds of thousands of lines of x86 machine code that executing even a small Java program can produce.

> Also, I am not a language expert but I wouldn’t like if a
> language had 1000 built-in features. I prefer if it
> allowed me to create a 1000 features by letting me
> “extend” some simple and basic ones.

Ah, then you'll love Scala. There was nothing "special" about the code I wrote. "partition" is an ordinary method on an ordinary class. The _.age syntax is Scala's way to do partial function application - available at all times and quite useful1. And the val (minors, adults) bit is basic, ordinary pattern matching deconstruction, also usable in your own classes.

Along the way, Scala has ditched tons of special case aspects of Java.

John Cowan

Posts: 36
Nickname: johnwcowan
Registered: Jul, 2006

Re: What Do You Consider "Readable" Code? Posted: Mar 19, 2009 11:35 AM
Reply to this message Reply
Master Foo once said to a visiting programmer: “There is more Unix-nature in one line of shell script than there is in ten thousand lines of C”.

The programmer, who was very proud of his mastery of C, said: “How can this be? C is the language in which the very kernel of Unix is implemented!”

Master Foo replied: “That is so. Nevertheless, there is more Unix-nature in one line of shell script than there is in ten thousand lines of C”.

The programmer grew distressed. “But through the C language we experience the enlightenment of the Patriarch Ritchie! We become as one with the operating system and the machine, reaping matchless performance!”

Master Foo replied: “All that you say is true. But there is still more Unix-nature in one line of shell script than there is in ten thousand lines of C”.

The programmer scoffed at Master Foo and rose to depart. But Master Foo nodded to his student Nubi, who wrote a line of shell script on a nearby whiteboard, and said: “Master programmer, consider this pipeline. Implemented in pure C, would it not span ten thousand lines?”

The programmer muttered through his beard, contemplating what Nubi had written. Finally he agreed that it was so.

“And how many hours would you require to implement and debug that C program?” asked Nubi.

“Many”, admitted the visiting programmer. “But only a fool would spend the time to do that when so many more worthy tasks await him”.

“And who better understands the Unix-nature?” Master Foo asked. “Is it he who writes the ten thousand lines, or he who, perceiving the emptiness of the task, gains merit by not coding?”

Upon hearing this, the programmer was enlightened.

--Eric S. Raymond, _Rootless Root_

Bill Venners

Posts: 2284
Nickname: bv
Registered: Jan, 2002

Re: What Do You Consider "Readable" Code? Posted: Mar 19, 2009 11:50 AM
Reply to this message Reply
> 2. brevity because the language hides essential detail
> from you
: variable definition/initialisation with
> type-inference; Scala implicits and extractors: i for one
> can't write or understand programs without knowing the
> types of all my variables, if/what implicit conversions
> are applied, or if/what extractors are used in my Scala
> pattern matching expressions - to name just a few
> examples. It's just that Scala hides some of these
> essential details from me, in a way that is less obvious
> and straighforward than e.g. a method hiding it's
> implementation details. So most of the time my mind has to
> add that hidden detail (e.g. by determining the type of an
> initialisation expression to know what type a variable is;
> or by hunting for implicits). These are extremely powerful
> features, and they reduce the amount of code
> significantly, but they directly translate into cognitive
> effort on the part of the programmer to fill in the
> missing details. (This is also where/why tool support is
> really essential in Scala, even more so than in Java.)
>
I don't think this matches my experience. Most of the time I am able to just think at the abstraction level of the Scala I've seen.

But what I have found is that occasionally I can run into some Scala code that though concise, is hard to understand. I can give a specific example from yesterday. I was trying to understand this "Matchers composition for object graphs" syntax in Specs:

http://code.google.com/p/specs/wiki/MatchersGuide#Matchers_composition_for_object_graphs

I think perhaps part of trouble I was having was in understanding the intent, i.e., what it was actually trying to accomplish. The way I went about trying to figure it out was to try and understand how it worked, to see what it was doing, to then try from that to figure out what it's goal is. (As well as asking the guy who wrote it to explain it.) And because I had never experienced the problem it was attempting to solve, or tried to solve it myself, I think it was harder for me to understand the intent. In this case, I think it would have been clearer to me if it used less fancy stuff and just showed the how, even if the result was more verbose.

robert young

Posts: 361
Nickname: funbunny
Registered: Sep, 2003

Re: What Do You Consider "Readable" Code? Posted: Mar 19, 2009 1:31 PM
Reply to this message Reply
> “And who better understands the Unix-nature?” Master Foo
> asked. “Is it he who writes the ten thousand lines, or he
> who, perceiving the emptiness of the task, gains merit by
> not coding?”
>
> Upon hearing this, the programmer was enlightened.
>
> --Eric S. Raymond, _Rootless Root_

I am of an age to remember the fight that went on about 4GLs in the 80's and early 90's. The opponents wrote General Ledgers in C, and scoffed at the PowerBuilder (to name one) folk who did so in a fraction of the time.

Still today, the same argument goes on. The names of the languages change, and the primacy of the RDBMS is questioned, but it remains the same argument. Today the argument is phrased as "declarative" or "higher abstraction" versus "low level". I'd wager that some, or many, of those who today argue for "higher abstraction" were in the group who scoffed at PowerBuilder.

Some things have to be done close to the metal, but not much.

Vijay Kandy

Posts: 37
Nickname: vijaykandy
Registered: Jan, 2007

Re: What Do You Consider "Readable" Code? Posted: Mar 19, 2009 3:21 PM
Reply to this message Reply
I wasn't arguing against closures per se (I actually like closures). Something like this (or the GScript code**) looks much cleaner for sure:

Pair<List<Person>,List<Person>> pair = Collections2.partition(people, {Person p => p.age() < 18});

I'll make my point like this - let's go a step further. Why call another method, create a list etc? Let's introduce a list comprehension too:

// hypothetical list comprehension
// collect all p's using [] such that for each p in people, p.age() < 18
List<Person> minors = [p || Person p <- people, p.age() < 18];

That way I can sort like so:

List<Person> minorsSortedByAge = Collections.sort([p || Person p <- people, p.age() < 18]);
minorsSortedByAge.first(); // youngest minor
minorsSortedByAge.last(); // oldest minor

Now I can write a really cool 1-liner:

Person oldestMinor = [p || Person p <- people, p.age() < 18].sort().last(); // you can probably pass a closure to sort() method

My question is when do we stop? I like concise code too and I don't like spelling out everything as it should happen on the processor. But at what expense? That's the reason I asked why aren't libraries enough? From your responses its clear that libraries aren't always enough or ideal. But we have to draw a line somewhere.
----------
** GScript code reads better because of "where" method. It feels more generic than partition, select, find ... I didn't see a download link anywhere on GuideWrire site though.

James Iry

Posts: 85
Nickname: jiry
Registered: Nov, 2007

Re: What Do You Consider "Readable" Code? Posted: Mar 19, 2009 7:39 PM
Reply to this message Reply
> I'll make my point like this - let's go a step further.
> Why call another method, create a list etc? Let's
> introduce a list comprehension too:

But note that a list comprehension is a special purpose tool - it only works with lists or, perhaps in some languages, collections. Closures and pattern matching, in contrast, are general purpose tools - they work with all manner of things.

It's worth mentioning that there is a generalization of a list comprehension called a monad comprehension and that Scala's "for" and C#'s LINQ are based on the idea. I think monad comprehensions rise to the level of being worthwhile more than list comprehensions do. Other languages may choose differently.

> List<Person> minors = [p || Person p <- people, p.age() <
> 18];

In this case, your comprehension is more verbose than the straight method call which you saw in GScript. In Scala its

val minors = people filter (_.age < 18)

In a hypothetical closures based Java API it would be

import static Collections.filter;
List<Person> minors = filter(people, {p => p.age() < 18})


> My question is when do we stop? I like concise code too

Language design is about trade-offs. You have to ask if benefit of something outweighs the cost of additional complexity. Scripting languages tend to include a lot of additional complexity in order to get syntactically nice lists and maps and such. Scala aims instead for relatively little specialized syntax (tuples are the only data structure that get special syntax) and lots of library support. In Scala when you see Map("one" -> 1, "two" -> 2) there's nothing in the syntax that's specialized for maps. If you wanted to use the same arrow notation for your own treemap, you would be free to develop something that was usable as TreeMap("one" -> 1, "two" -> 2).

> reason I asked why aren't libraries enough? From your
> responses its clear that libraries aren't always enough or
> ideal. But we have to draw a line somewhere.

Libraries can get you awfully far once the language has a few key features. Lambdas are a minimum.

> ** GScript code reads better because of "where" method. It
> feels more generic than partition, select, find ...

I do want to emphasize that "partition" is an ordinary method on an ordinary class. Nothing special about it. But to answer your comment "partition" does something different from "where" - it splits a collection into two based on a predicate. The equivalent of GScript's "where" in Scala's library is "filter." Still, Scala is flexible enough to let you add a "where" method if you preferred it. Here's an actual session with the REPL where I add it. I've bolded what I typed, everything else is computer's response.

scala> implicit def iterableWithWhere[T](iterable : Iterable[T]) = new {
| def where(p : T => Boolean) = iterable filter p
| }

iterableWithWhere: [T](Iterable[T])java.lang.Object{def where((T) => Boolean): Iterable[T]}

scala> case class Person(name : String, age : Int)
defined class Person

scala> val people = List(Person("Bob", 28), Person("George", 17), Person("Sarah", 12))
people: List[Person] = List(Person(Bob,28), Person(George,17), Person(Sarah,12))

scala> val minors = people where (_.age < 18)
minors: Iterable[Person] = List(Person(George,17), Person(Sarah,12))

This might look like "monkeypatching" but the scope of the additional method is statically defined and the compiler will warn you about ambiguities.

James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: What Do You Consider "Readable" Code? Posted: Mar 20, 2009 9:39 AM
Reply to this message Reply
> > “And who better understands the Unix-nature?” Master
> Foo
> > asked. “Is it he who writes the ten thousand lines, or
> he
> > who, perceiving the emptiness of the task, gains merit
> by
> > not coding?”
> >
> > Upon hearing this, the programmer was enlightened.
> >
> > --Eric S. Raymond, _Rootless Root_
>
> I am of an age to remember the fight that went on about
> 4GLs in the 80's and early 90's. The opponents wrote
> General Ledgers in C, and scoffed at the PowerBuilder (to
> name one) folk who did so in a fraction of the time.
>
> Still today, the same argument goes on. The names of the
> languages change, and the primacy of the RDBMS is
> questioned, but it remains the same argument. Today the
> argument is phrased as "declarative" or "higher
> abstraction" versus "low level". I'd wager that some, or
> many, of those who today argue for "higher abstraction"
> were in the group who scoffed at PowerBuilder.
>
> Some things have to be done close to the metal, but not
> much.

I am of the age where I was maintaining PowerBuilder apps written in the early 90s. It took hundreds or even thousands of hours to make minor changes to the applications (for example, adding a new field to a table.)

I don't disagree that high-level languages are almost always better for a given task but there's a danger of going too far and throwing out the baby with the bath water. That is, sometimes when it's so easy to just add another datawindow, the value of taking the time to do things like build a base abstraction get's forgotten until the time comes that you have to make changes to 500+ different datawindows to support one new feature.

I think Scala's on the right track in that it steers you to good long term approaches by making those approaches easier. I just think Scala may be a little more complex than it really needs to be for most purposes.

Vijay Kandy

Posts: 37
Nickname: vijaykandy
Registered: Jan, 2007

Re: What Do You Consider "Readable" Code? Posted: Mar 20, 2009 10:53 AM
Reply to this message Reply
Thanks for your kind and patient responses. I am surprised how easily you added a "where" clause behavior. That's a lot of power in the programmer's hands.

Mark Thornton

Posts: 275
Nickname: mthornton
Registered: Oct, 2005

Re: What Do You Consider "Readable" Code? Posted: Mar 20, 2009 2:36 PM
Reply to this message Reply
> read. And it does map to an interception in American
> football. It catches the ball and runs it back and hands
> it to you. Not a perfect metaphor but that's where it came
> from.

The difficulty with that type of metaphor is that it has no meaning to many readers and is then no better than a nonsense word or APL!

Bill Venners

Posts: 2284
Nickname: bv
Registered: Jan, 2002

Re: What Do You Consider Posted: Mar 20, 2009 3:50 PM
Reply to this message Reply
> > read. And it does map to an interception in American
> > football. It catches the ball and runs it back and
> hands
> > it to you. Not a perfect metaphor but that's where it
> came
> > from.
>
> The difficulty with that type of metaphor is that it has
> no meaning to many readers and is then no better than a
> nonsense word or APL!
>
Yes, you're absolutely right. And I don't talk about football in the ScalaTest documentation of intercept. I was just giving you a bit of history.

Basically I struggled quite a bit on what to call this construct. The closest runner up was expectException, which is more obvious, but longer and has the problem of repeating the word "Exception" in most cases. For example, "Exception" shows up twice here:


expectException[IllegalArgumentException]


But one point in its favor is we also have an expect construct in ScalaTest assertions, so expectException might blend
in nicely with that.

Another word I considered was ensureThrows. That's what easyb uses and it is also more obvious, though again longer, than intercept. But it does get rid of the repeated "Exception" problem. However, easyb's ensureThrows does only ensure the exception is thrown and doesn't return it for further poking. So it didn't quite fit ScalaTest's construct as well as it does easyb's I felt.

And so at the time I was struggling with this naming problem I happened to be watching a Colts game with my Dad, and someone threw an interception in the game. It hit me that the word intercept captured well the concept of what was going on with that exception, and this isn't just limiting it to the word's meaning in football. The regular English meaning of the word intercept fits well. And it was short and didn't require a capital letter because of camel case. So I ended up going with that. It isn't as obvious to complete first timers as expectException, but my hope is that intercept can be quickly learned and then will be very clear when looking at the code.

robert young

Posts: 361
Nickname: funbunny
Registered: Sep, 2003

Re: What Do You Consider "Readable" Code? Posted: Mar 20, 2009 7:29 PM
Reply to this message Reply
> I think Scala's on the right track in that it steers you
> to good long term approaches by making those approaches
> easier. I just think Scala may be a little more complex
> than it really needs to be for most purposes.

Point taken.

My comment was aimed at this:

Klocs Kill - the amount of code you ships becomes the tax on future development.

Neither Ruby nor Python climbs enough apparently. Even in those languages, frameworks are created. Frameworks are just <language + X>GLs, of course. And competing frameworks, save Rails since it has managed to keep the field to itself, incite religious wars.

saurav sarkar

Posts: 1
Nickname: saurav26
Registered: Mar, 2009

Re: What Do You Consider "Readable" Code? Posted: Mar 23, 2009 3:31 AM
Reply to this message Reply
Very well written blog.
I feel there is flip side of everything.If i reduce the code lines it might increase the readibility.But if the intent is lost or the total logic of the code is lost then i think its a not good bet to make.

Suppose

methA().methB().getC().

against

A a =methA();
B b=a.methB();
C c=b.getC();

The first approach is much easier to read and does not increase the code lines.But the second approach to my view would give much more understanding to the logic.

The second one would be useful for debugging also.

John Zabroski

Posts: 272
Nickname: zbo
Registered: Jan, 2007

Re: What Do You Consider "Readable" Code? Posted: Mar 23, 2009 8:00 AM
Reply to this message Reply
@Would you consider Perl's one-liners as readable code? :)

@So, it has nothing to do with the number of lines, but with their clarity?

I liked Ronald's Aristotlean responses.

When somebody asks, What Do You Consider "Readable" Code? The best response is to be a reflective psychologist like Karl Rogers: "I'm trying to figure out what to do" "What do you think you should do?" :-)

John Zabroski

Posts: 272
Nickname: zbo
Registered: Jan, 2007

Re: What Do You Consider Posted: Mar 23, 2009 8:13 AM
Reply to this message Reply
@Basically I struggled quite a bit on what to call this construct.

A common metaphor is "capture the flag". There is actually an open source patent that describes this and extends it will pre-emptive multi-tasking abilities: "seize the flag"

John Carter

Posts: 3
Nickname: cyent
Registered: Dec, 2005

Good Design is all about how little you have to read.... Posted: Mar 26, 2009 7:35 PM
Reply to this message Reply
Good Design is all about how little you have to read to understand what you need.

This is NOT about terseness. It is about controlling causality.

You don't have to read the rest of the system to understand how X works, because you KNOW that there is no way the rest of the system can effect X.

Anyhoo, ruby does terseness quite nicely... For example the test/unit for the example you give is...
array=[1,2,3]
assert_raises( IndexError) { array.fetch(8)}

Note in ruby array[-1] would return 3 and array[8] returns nil

Flat View: This topic has 34 replies on 3 pages [ « | 1  2  3 | » ]
Topic: What I learned at Java Posse Roundup '09 Previous Topic   Next Topic Topic: Mixins considered harmful/1

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use