in reply to Re: Re (tilly) 1: built-ins sometimes iterating over a list, sometimes not
in thread built-ins sometimes iterating over a list, sometimes not

Actually Code Complete does address this exact issue. I don't have it in front of you so I can't give page numbers, but they talk about the importance of not reducing lines of code by putting more on one line. I think it was talked about with particular reference to C's trinary operator.

As for the question of whether nesting logic helps or hurts, my experience is very strongly that it hurts my comprehension. What I find best for handling nested maps, greps, and sorts is to put them on separate lines, indented, to be read from bottom to top. That is the same strategy with any complex control logic. If it is a single "thought" in your program, make it into line-noise. If it is central to how your program works, break it visually along the lines of how it is to be understood.

I have seen similar styles from other programmers. Including both merlyn and TheDamian. Again, I sometimes break out logic, sometimes don't. But if it is central to what I am doing, I break it out. Likewise if I start getting multiple control statements on the same line and want to reach for && as a control statement, I break it out.

As for the question of whether other languages have the piping that Perl does, I disagree. Here is a Schwartzian sort of a pipe-delimited list on the 3'rd then 5'th columns (ascending then descending) in Perl:

my @sorted = map {join, "|", @$_} sort {$a->[2] cmp $b->[2] or $a->[4] cmp $b->[4]} map {[split /\|/, $_, -1]} @my_list;
Here is how you do the same thing in Ruby:
sorted = my_list.map { |i| [ i.split(/\|/)[2,4], i ] }.sort.map { |i| i[-1] }
Do you see? Chaining method calls achieves exactly the same effect as Perl's pipelining does, and it even has the benefit of reading more naturally left to right! So the formatting issue is hardly unique to Perl...

Replies are listed 'Best First'.
Re: Re (tilly) 3: built-ins sometimes iterating over a list, sometimes not
by demerphq (Chancellor) on Nov 08, 2001 at 23:27 UTC
    What I find best for handling nested maps, greps, and sorts is to put them on separate lines, indented, to be read from bottom to top.

    I do this as well, my only issue with it is where to put the listor array, on the same line as the last transformation or the line below? Also I can never quite decide how to deal with 'blockless' transforms such as sort.

    @list=map {substr($_,1)} sort map {pack("CA*",length($_),$_)} @words; #or @list=map {substr($_,1)} sort map {pack("CA*",length($_),$_)} @words;
    About your example from Ruby, are you allowed arbitray whitespace in between the transforms? ie could you write that as the following?
    sorted = my_list.map {|i| [ i.split(/\|/)[2,4],i ]}. sort. map { |i| i[-1] }
    ...even has the benefit of reading more naturally left to right!

    Well, while it wouldnt be difficult to write a class that supported this type of syntax, I have to say that i'm not so sure that this is more natural or not. In fact, while I dont think it would be that hard to get used to or even that it would bother me, I would actually argue that it is less natural than the perl notation, which I hasten to add does seem a little odd at first, seemingly going against the convention in a program that lines are executed in order from top to bottom. This I believe is because it is easy to think in terms of statement execution rather than what is really happening, list assignment, or function chaining.

    For the sake of clarity in my argument Id like to point out that normally values move from the right to left in statements. $x=$y; for instance involves evaluating the right side and placing its value in the container on the left side. With lists we extend the idea to that of 'pouring' values from the right side into the left side.

    Now when I see  @greets=map{"Hello $_!"}@names; the idea is extended so each value from the list at the right goes left, into the block and then left again into the array. And so on when we have longer chains. This also matches the way it would be written if these were all functions.

    @list=map(substr($_,1),sort(map(pack("CA*",length($_),$_),@words)));
    Whereas the method form would translate into a multistatement equivelent
    my @tmp = map { pack("CA*",length($_),$_) } @words; my @tmp2= sort @tmp; my @list= map { substr($_,1)} @tmp2;
    Which makes sense when written as multiple statements, but when written as one statement as you showed in ruby it actually seems to be unnatural. The result gets taken from the extreme right hand side and stuck in the container on the left side, which hardly seems more natural than the values flowing consistantly from right to left.

    Just my $0.02 :-)

    Yves / DeMerphq
    --
    Have you registered your Name Space?

      I vary on where the listor array goes.

      As for Ruby, yes you can arrange them that way. I don't code much Ruby, but when I do one of the decisions that I curse is making the semi-colon optional. Without it you need to give a hint that the line will continue. I hate having to remember what hints will work. So I don't. I remember that blocks span, and then stick to that. But the flip side is that I won't think of better spatial arrangements from time to time.

      As for whether right to left or left to right is best, well your eye tends to move left to right across the text because that is how the words are written, and how we read English. What that means is that any time your flow of logic goes right to left, your eye has to jerk back and forth in different directions between different spots on the page. Take out some code, read it, and you will see what I mean.

      Personally I would be happier if there was a left to right assignment operator, and I could read everything left to right, top to bottom. And it isn't so unreasonable to ask for that. Think about shell scripts. That is how the Unix pipeline goes, and I think it is much more intuitive for that design.