Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Language features affect style

by tilly (Archbishop)
on Jun 08, 2009 at 06:03 UTC ( #769387=perlmeditation: print w/replies, xml ) Need Help??

While I was reading Refactoring by Martin Fowler I noticed something interesting. Different language features between Perl and Java make, in my opinion, some of his recommendations be not as good for Perl as they are in Java. This struck me as interesting, hence this meditation.

For those who are not familiar with the book, the idea is to create a set of fairly mechanical refactoring operations you can do to existing code. These refactorings leave the code doing the same thing, but being in some way improved. The idea is that you can take bad code, apply trivial refactorings, and wind up with better code. The improvements make the code easier to understand and work with.

Two of the refactorings are Extract Method and Introduce Explaining Variable. Both refactorings are appropriate when you have a complicated expression whose purpose is not obvious, and are particularly useful if said expression is calculated more than once. In Extract Method you encapsulate the computation into a method that returns the computation. In Introduce Explaining Variable you perform the computation once, and assign the result to a well-named temporary variable.

So far this is language agnostic. You can use either approach in either Java or Perl.

The interesting difference is that Fowler advocates using Extract Method in Java, while I'd be much more inclined to Introduce Explaining Variable in Perl.

His reasoning is straightforward. In general it is no harder to extract methods than to introduce temporary variables. The performance difference is generally negligible. And once you've extracted a method, it is then available to be used anywhere you want in the object. Which makes it easier to apply other refactorings that may break a long function into many smaller ones.

My reasoning is also straightforward. Writing methods means writing more boilerplate. Typos in method names are not caught by strict.pm, while typos in variable names are. Furthermore I worry about accidentally choosing clashing names. The wider visibility of a method makes mistakes more likely than with a temp.

All of my reasons are a bigger issue in Perl than Java. Java's syntax for methods has less boilerplate than Perl's. Java's type system lets typos in method names be caught. He addresses the method clashing issue by using private methods, which Perl doesn't have. (Warning for fans of other dynamic languages, private methods in Java are different than, say, what Ruby calls private methods.)

This lead me to accept his reasoning for his Java style, even though in Perl I'll continue to choose differently. As a result when faced with completely equivalent code in the two languages and the choice of completely equivalent straightforward modifications, in many cases I would choose differently. My sense of good programming style is therefore not language agnostic. The difference may seem minor, but it surprised me that it exists at all.

Replies are listed 'Best First'.
Re: Language features affect style
by JavaFan (Canon) on Jun 08, 2009 at 07:59 UTC
    Note that Perl also has closures, which Java doesn't have. In some refactoring cases, you might want to use a closure instead of a method - it gives you some of the benefits private methods give you in Java.

    But for me, there's a large difference between storing something in a temporary variable, and using a method. Assuming the temporary variable isn't tied, once you put a value in there, you get back the same value each and every time. With a method, that's less clear, certainly when seen from the caller's perspective. For instance:

    my $v1 = $v2 + $v2; my $v3 = $self->m1 + $self->m1;
    The first is equivalent to 2 * $v2, but it's not clear whether the latter is equivalent to 2 * $self->m1, until you know what m1 does.

    And that's a language agnostic issue.

      When different languages can express different things, it makes sense to me that good coding style would be different. On methods that mutate data, it strikes me as extremely bad style for a method to mutate data under the hood and not make that clear in the name. If you assume that quality bar has been passed, the difference you're talking about disappears.

      I'd prefer to deal with code that has passed that quality bar. :-)

        Yes, but a method name is usually only a handful of lines; you cannot expect you can deduce everything that happens from the name of a method. And what will be obvious for one, may not be clear for someone else.

        And code doesn't have to mutate data to return something else. Perl has iterators called 'keys' and 'each' whose name doesn't suggest at all it's modifying something.

        I'd prefer to deal with code that has passed that quality bar. :-)

        Well, wouldn't we all? :-)

        However, I thought that one of the motivations for refactoring was making it easier to deal with code that has not passed the quality bar. Or knocked the quality bar off and left it lying in pieces on the floor...

        --
        use JAPH;
        print JAPH::asString();

Re: Language features affect style
by Arunbear (Prior) on Jun 08, 2009 at 12:36 UTC
    A contrived example showing that private methods can be simulated with lexical coderefs:
    use strict; use warnings; package Foo; sub new { bless {salary => 100} } my $private_method = sub { my $self = shift; my $factor = shift || 2; $self->{salary} *= $factor; }; sub get_salary { my $self = shift; $self->$private_method(10); return $self->{salary}; } package main; my $foo = Foo->new; printf "salary is %s\n", $foo->get_salary;
    Admittedly the boilerplate issue is still there.
      Indeed, which is why we've gotten rid of most of Perl 5's (not so) beloved boilerplate in Perl 6. Here's the same code (more or less) in Perl 6:
      class Foo { has $!salary; method !private_method ($factor = 2) { $!salary *= $factor } method salary { self!private_method(10); $!salary } } my Foo $foo .= new(:salary(100)); say "salary is ", $foo.salary;
      This may or may not tweak the refactoring knob back toward methods; Perl 6 is still not Java, after all.
        method salary { self!private_method(10); $!salary }
        Doesn't $!salary have to be called with an object? self!salary. Or has this been changed to figure that out for itself (implies self or $_ ?) now? I found it:
        For a call on your own private method, you may also use the attribute-ish form:
        $!think($pinky) # short for $(self!think($pinky))
        I'm guessing you put this in after you got STD in fine enough shape and knew that could actually be made to work?

        With analogous meaning for the other sigils (that's not stated in S12)?

        —John

        Perl 6 is still not Java, after all.

        Is it gasoline? No, perl is Camelia :)

Re: Language features affect style
by tsee (Curate) on Jun 10, 2009 at 15:13 UTC

    Thanks for the interesting meditation.

    I actually like the idea of the "introduce explaining variable" feature a lot. It's not something I can see people use all over the place, but I tend to get quite a bit of bad code that computes long parameterizations as a single expression, so it would be useful to have.

    Therefore, I just implemented the feature as "introduce temporary variable" in the Padre editor. I would expect it to be part of the next release.

    Cheers,
    Steffen

      If you're looking for other potentially useful refactorings, I highly recommend picking up Refactoring by Martin Fowler. Most of the book is a catalog of refactorings that he has found useful.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://769387]
Approved by Corion
Front-paged by Arunbear
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others scrutinizing the Monastery: (6)
As of 2021-12-02 23:03 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    R or B?



    Results (27 votes). Check out past polls.

    Notices?