On Sun, 28 Jan 2001, Brian F. Feldman wrote:

> <ale / crimson.propagation.net> wrote:
> > Anyway, this bug doesn't bite too often by accident. If you adopt
> > "right" style to write code (include operator or dot as a hint of
> > continuation to the same line) it's very rare event you need
> > '\'. During my sufficiently short Ruby career I can't remember using
> > this notation more than two times.
> > 
> > Usually when a statement grows over line there's something in your
> > code which uses it's last way of signalling it should be fixed.
> 
> I disagree with that, since it is in the style of functional programming to 
> have a large "chain" of methods acting upon a series of lists (or, in Ruby's 
> case, Arrays).  For example:
> 
>     def CDDB.from_sql(res)
>         unsubber = lambda {|s|
>             s.scan(/[^\\]("([^"\\]|\\.)*")/).
>               collect {|e| e[0][1..-2].gsub(/\\(.)/, '\1')}
>         }
>         CDDBStruct.new(unsubber.call(res[0]), res[1], unsubber.call(res[2]),
>           res[3], unsubber.call(res[4]),
>           res[5][1..-2].split(',').collect {|x| x.to_i})
>     end
> 
> You'll probably see even longer chains than that all the time, and in those 
> cases I think that when a statement is more than a line because of this, 
> it's specifically doing things right!

While I agree with you that there's a certain tendency to produce
chains of calls, I have to keep staying behind my opinion. My very
argument against this style of coding is the fact that it's painful to
read above code, and even more painful to change it.

I like call chaining, even to the point I really like to get away with
most method! anomalities (returning nil sometimes; actually I fixed
one of these from someone else's code which didn't work for me).

Simultaneously when you reorganize the above code there's an effect
that you give name to a thing you handle; be it a command chain,
a parameter or a helper variable.

     def CDDB.from_sql(res)
         quoted_string_re = /[^\\]("([^"\\]|\\.)*")/
         unsubber = lambda do |s|
             s.scan(quoted_string_re).collect do |e| 
                 e[0][1..-2].gsub(/\\(.)/, '\1')}
             end
         end
         listed_numbers = res[5][1..-2].split(',').collect {|x| x.to_i}
         CDDBStruct.new(unsubber.call(res[0]), res[1],
                        unsubber.call(res[2]), res[3], 
                        unsubber.call(res[4]), listed_numbers)
     end

I'm not claiming this example is in some way the ultimate, most
readable version, but I find my version easier to read and mess
around.

Still I'd like to exploit the possible rule of "unsub every second
parameter", name the mystical range of 1..-2, give better names to
variables in unsubber, maybe split the long line of listed_numbers
definition into two lines and call collect! on the latter.

Anyway, I guess you get my point. I think it's quite rare event that
you really have to have over 75 character (or some limit) lines. I
hear the exceeding line length as a cry requesting some code massage.

There are some simple cases where the change is easy to do, like
spreading inlined blocks to multiple lines ({..} notation to do..end),
and with parameter passing I feel no guilty having couple of lines
between opposing parentheses (as long as the content doesn't contain
too much of executed code).

Do we still disagree ?)

    - Aleksi