http://www.perlmonks.org?node_id=615107


in reply to Re^4: Programming *is* much more than "just writing code".
in thread Programming *is* much more than "just writing code".

The answer to the problem of encountering code you do not understand, is to educate yourself.

Look it up or ask someone!

A code example, including some comments I have used:

# add attributes to object my @fields = (keys %{ $attributes }); @{ $self }{ @fields } = @{ $attributes }{ @fields }; # hash slice

The first comment gives someone skimming the code a hint about what's happening here (that they can figure it out by close study may be likely, but making them engage in that study just to find out if this is the part of code they care about is at best inconsiderate).

The second comment, "hash slice", is the sort of thing a beginning programmer would need in order to have a hope of looking up the technique in use.

The fact that the level of knowledge of the audience is uncertain does not obviate the need to address the audience at a certain level. Would you argue against explanatory subroutine and variable names because a really good programmer doesn't need those hints?

Replies are listed 'Best First'.
Re^6: Programming *is* much more than "just writing code".
by BrowserUk (Patriarch) on May 13, 2007 at 10:07 UTC

    I've been thinking about those comments overnight, and I don't have any particular objection to them. Certainly not the second one anyway. I think that one could easily fall under the auspices of my statement from the OP:

    ... used sparingly where they clarify things that the notation ... fails to convey.

    That said, context is everything, and your snippet in isolation of the code (and further commenting) around it, makes it hard to decide if these are really warrented or not. For example, here is a possible context for your snippet:

    package Junk1; sub new { my( $class, $attributes ) = @_; my $self = bless {}, $class; # add attributes to object my @fields = (keys %{ $attributes }); @{ $self }{ @fields } = @{ $attributes }{ @fields }; # hash sli +ce return $self; } package main; my $obj1 = Junk1->new( { a=>1 , b=>2, c=>3 } );

    And here are 4 more that, in the absence of further information, achieve the same thing. And all of which I think are preferable, and clearer to a lesser or greater extent

    This one avoids the hash slice, and the (potentially confusing) intermediate array (called @fields) to hold the names of the keys, that are referred to in the comment as attributes. (Not to be confused attributes of course, which are something quite different!)

    And by using %{ $ref } on both sides of the assigment, it makes it clear, even to a beginnner, that we are doing something with hashes:

    package Junk2; sub new { my( $class, $attributes ) = @_; my $self = bless {}, $class; %{ $self } = %{ $attributes }; return $self; } package main; my $obj2 = Junk2->new( { a=>1 , b=>2, c=>3 } );

    This takes it a step further and does away with the separate assignment completely. Of course, that may or may not be possible depending upon if and how you choose to validate the arguments to the constructor.

    package Junk3; sub new { my( $class, $attributes ) = @_; my $self = bless { %{ $attributes } }, $class; return $self; } package main; my $obj3 = Junk3->new( { a=>1 , b=>2, c=>3 } );

    This one goes a step further, and probably a step too far for safety. It avoids naming the object reference completely, and also avoids copying the data. This latter step is potentially dangerous if you pass anything other than an anonymous hash to the constructor, and I would avoid it for that reason.

    package Junk4; sub new { my( $class, $attributes ) = @_; return bless $attributes, $class; } my $obj4 = Junk4->new( { a=>1 , b=>2, c=>3 } );

    Finally, my preferred option. Pass the arguments as a simple list, accumulate them into a hash when unpacking them from @_, and bless a reference to that as the object:

    package Junk5; sub new { my( $class, %attributes ) = @_; return bless \%attributes, $class; } my $obj5 = Junk5->new( a=>1 , b=>2, c=>3 );

    To my mind this is the clearest, cleanest and most maintianable option and is, perhaps, less likely to confuse a "beginner". As such, I don't see scope for clarification via comments. But that is still making an assumption about the knowledge level of those that will follow, and that's my beef.

    The fact that the level of knowledge of the audience is uncertain does not obviate the need to address the audience at a certain level.

    But that's the problem. At what level?

    The idea that everytime any Perl programmer uses a hash slice, he should annotate that usage with # hash slice, still feels faintly ludicrous to me. Or to quote some of those I found on the net

    # Ooooh, hash-slice. :) # woo, hash slice # A slice of Hash # Aren't hash slices lovely? # Hash ref slice
    • But should we also annotate array slices with # array slice?
    • How about dereferencing code refs: $code->(); # Call the code?
    • Or creating them: thread->new( \&thread ); # pass a reference to the code?
    • How about the ternary operator: my $var = $x < 2 ? 2 : $x; # Lower bound for $var is 2?

    Where is that line to be drawn?

    Would you argue against explanatory subroutine and variable names because a really good programmer doesn't need those hints?

    Absolutely not, but the sting in the tail of the question is not the reason. It's because they do not create a maintenance problem. Nothing is duplicated; no couplings are created; they can't lie; they are tested.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      I've been thinking about those comments overnight, and I don't have any particular objection to them. Certainly not the second one anyway. I think that one could easily fall under the auspices of my statement from the OP

      Cool. It could eaisly be that I've gotten an exaggerated impression of how sparse you think comments need to be -- and by the way, I agree that it's certainly possible to have a surplus of comments that just become inane (most would agree that every line is too many, for example). Unlike what some people here are saying, though, I find that problem to be tremendously rare. Far more common is the "it was hard to write, it should be hard to understand" attitude.

      That said, context is everything, and your snippet in isolation of the code (and further commenting) around it, makes it hard to decide if these are really warrented or not.

      I think we're wandering afield, but the context is, of course, href-based objects, in this case using a seperation of instantiation from initialization. I'm playing with a simple "new" routine (inherited from Class::Base) which calls an "init" sub. I've used a version of init (generated by template) that looks something like this:

      sub init { my $self = shift; my $args = shift; unlock_keys( %{ $self } ); # $self->SUPER::init( $args ); # uncomment if this is a child class # define new attributes my $attributes = { ### fill-in name/value pairs of attributes here # name => $args->{ name }, attribute => $args->{ attribute }, objectdata => $args->{ objectdata } || 23, parameter => $args->{ parameter } || 'bupkes', }; # add attributes to object my @fields = (keys %{ $attributes }); @{ $self }{ @fields } = @{ $attributes }{ @fields }; # hash slice lock_keys( %{ $self } ); return $self; }

      Note: some of the comments there are intended to be deleted as the code goes from template form toward production use.

      In general, the reason I think we're wandering afield is that I make no claims that these constructs are the best way of doing things. The question at hand is that if you are going to do something like this (e.g. use a mildly obscure feature such as a hash slice) is there something heinous about labeling it as such in a comment.

        The question at hand is that if you are going to do something like this (e.g. use a mildly obscure feature such as a hash slice) is there something heinous about labeling it as such in a comment.

        No. But now we have come full circle. I set out in the OP to refute the idea that "... programmers who do not extensively comment their code are lazy, or bad, or otherwise detrimental to the world of programmer-kind.".

        Ie. to refute the idea that not commenting the use of those features that an original programmer thinks that some of those that follow him might consider mildy obscure, is heinous.

        The purpose of the node was to point out that commenting is a double edged sword, with definite costs and ethereal benefits.

        So, I think that we are almost agreeing here. We just seem to be at opposite ends of the middle ground between those that appear to consider code incomplete unless it is possible to get a pretty complete idea of what the code is doing from reading the comments alone; and those that think that comments have no value at all. Though I must admit that a) I've never seen anyone who actually vermently advocated the latter position; b) I'm much closer to that end than you are to the other it seems.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
      The fact that the level of knowledge of the audience is uncertain does not obviate the need to address the audience at a certain level.
      But that's the problem. At what level?

      It's certainly a knotty problem all right, and like most such difficult problems there's one all encompassing solution: make a guess.

      You can't just wish the problem away because you'd like the world to be a simpler place.

      The idea that everytime any Perl programmer uses a hash slice, he should annotate that usage with # hash slice, still feels faintly ludicrous to me.

      And who says that you should? My guess would be that the first usage in a module is probably where it's needed.

      Or to quote some of those I found on the net ...
      None of which strike me as "ludricous": they're just jokes. Small human touches that give you some sense of the way the programmer was thinking about the code. Even if you don't think that a hash slice is particularly fancy, it can be useful to know that the original programmer did.

      (I suggest that the central difficulty here is that you're trying to find some way to make code into some sort of pure mathematical construct, and my own opinion is that it definitely isn't.)

      Would you argue against explanatory subroutine and variable names because a really good programmer doesn't need those hints?
      Absolutely not, but the sting in the tail of the question is not the reason. It's because they do not create a maintenance problem. Nothing is duplicated; no couplings are created; they can't lie; they are tested.

      Sorry, but this is just wrong. As code evolves, the function of a routine can easily drift away from what you would assume from the name of the routine. If you don't refactor the names of your routines when that happens, you can easily end up with a misleading name. (Note: you can help cover these problems with appropriate comments.)