Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

I don't use printf enough

by dreadpiratepeter (Priest)
on Oct 22, 2003 at 16:09 UTC ( #301264=perlmeditation: print w/ replies, xml ) Need Help??

I often find myself writing code like the following:
print "text text " . $obj->method1() . " more text " . $obj->method2() . " blah blah " . $obj->method3() . "\n";
A lot of concatenation, and it's not really easy to read. I could interpolate the method calls into the string using @{[]} tricks, but I find that to be ugly.
For some reason, I never remember the simple elegant solution, printf.
printf "text text %s more text %s blah blah %s\n", $obj->method1(),$obj->method2(),$obj->method3();
It's straight-forward, easy to read, and it lends itself much more easily to future localization, rewording, etc.

Probably obvious to most, but not all meditations need to be grand.


-pete
"Worry is like a rocking chair. It gives you something to do, but it doesn't get you anywhere."

Comment on I don't use printf enough
Select or Download Code
Re: I don't use printf enough
by Plankton (Priest) on Oct 22, 2003 at 16:57 UTC
    I find it kinda of ironic that in C++ the "preferred" way of writting to STDOUT is like so:
    cout << "text text " << obj->method1() << " more text " << endl;

    Plankton: 1% Evil, 99% Hot Gas.

      I assume you mean:

      cout << "text text " << obj.method1() << " more text " << endl;

      And would you explain why you find this ironic?

        Presumably, he/she finds it ironic beacuse
        cout << "text text " << obj.method1() << " more text " << end1;
        is like using string concatenation in Perl. The root node says to use printf sometimes. printf is a C function, yet it would not be the preferred way of doing things in C.

        So to prefer printf in Perl when something like the above (preferred) C snippet exists, is ironic.

        His c++ syntax is just fine, his obj can be understood as a pointer to an object:

        #include <iostream.h> class aclass { public: int first_perfect_number(void); }; int aclass::first_perfect_number(void) { return 6; } int main() { aclass * ap = new aclass(); cout << "first perfect number is: " << ap->first_perfect_number() +<< endl; }
Re: I don't use printf enough
by gjb (Vicar) on Oct 22, 2003 at 16:57 UTC

    Definitely worth to mention sprintf as well.

    Just my 2 cents, -gjb-

Re: I don't use printf enough
by BrowserUk (Pope) on Oct 22, 2003 at 17:40 UTC

    Funnily enough, I think for many cases I would write that as

    print 'text text ', $obj->method1(), ' more text ', $obj->method2(), ' blah blah ', $obj->method3();

    I would only use printf if I needed to apply special formatting to the method returns.

    My main reasons for this choice are that

    1. It is easy to extend.

      Adding 'and more text', $obj->method2.5 is easy, and commenting out one part likewise.

    2. As the length of the format string increases, it becomes unweildy and need to be split across 2 or 3 lines anyway.
    3. I find this formatting easier to see what text applies to which method.

    The absence of a newline, is because i always have -l enabled.


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail
    Hooray!

      The absence of a newline, is because i always have -l enabled.

      I like -l but wish that there was a way to selectively counter-act it, as I occasionally (but not often) want to print a newline-less line. How do you handle these situations?

      bbfu
      Black flowers blossom
      Fearless on my breath

        That's when I use printf:)

        With -L enabled, print 'Prompt: '; adds the newline but printf 'Prompt: '; $resp = <STDIN>; doesn't. The distinction is very useful.


        Examine what is said, not who speaks.
        "Efficiency is intelligent laziness." -David Dunham
        "Think for yourself!" - Abigail
        Hooray!


        I like -l but wish that there was a way to selectively counter-act it

        Here is one way:

        #!/usr/bin/perl -wl print "aaa"; { local $\; print "bbb"; } print "bbb"; print "ccc"; __END__ Prints: aaa bbbbbb ccc

        --
        John.

        I like -l but wish that there was a way to selectively counter-act it, as I occasionally (but not often) want to print a newline-less line. How do you handle these situations?
        Localize $\.
        $\ = "\n"; # as perl -l print "before"; { local $\; print "continued"; } print "after"; print "heh!";
        which prints
        before
        continuedafter
        heh!
        
        In fact, you can set $\ to anything, and with local, it's safe — or at least, as safe as using $\.

        IMO, every module that uses print in a hidden fashion, should use

        local $\;
        and not rely on $\ being empty at the time its functions are called.

        Note that printf ignores the settings of $\.

Re: I don't use printf enough
by antirice (Priest) on Oct 22, 2003 at 17:55 UTC

    TIMTOWTDI

    print "text text ${\ $obj->method1() } more text ${\ $obj->method2() } + blah blah ${\ $obj->method3() }\n";

    :)

    antirice    
    The first rule of Perl club is - use Perl
    The
    ith rule of Perl club is - follow rule i - 1 for i > 1

      Ignoring any sort of performance issues, I find that almost impossible to read. *shrugs* TMTOWTDI ... I guess ...

      ------
      We are the carpenters and bricklayers of the Information Age.

      The idea is a little like C++ templates, except not quite so brain-meltingly complicated. -- TheDamian, Exegesis 6

      ... strings and arrays will suffice. As they are easily available as native data types in any sane language, ... - blokhead, speaking on evolutionary algorithms

      Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

        I agree. I brought it up merely as interesting syntax to do the same thing.

        antirice    
        The first rule of Perl club is - use Perl
        The
        ith rule of Perl club is - follow rule i - 1 for i > 1

      I'm amazed.

      I've long seen @{[stuff]} used for interpolation, but that saves only one character over interpolation (5 vs 6 chars), is unclear, and puts stuff into the wrong context.

      By contrast what you've pointed out takes 4 characters, is unclear, but puts things in the right context. However it is a bit fragile.

      I wonder why I haven't seen this pointed out before?

      I'll definitely be remembering this, if for no reason than golf. But while I prefer it to the @{[...]} interpolation method, I still prefer concatenation over both.

      UPDATE: Reminder to self, always test assumptions...

        I'm not sure I understand your comments about @{[ $o->m() ]} putting things in the "wrong" context and ${\ $o->m() } putting things in the "right" context. The method is called in list context in both cases, right? What am I missing?

        I thought, that if you needed scalar context, you had to use scalar(). Perhaps ~~ if you are golfing and can get away with it. (I.e. your method isn't returning a reference or a floating point number.)

        Heh . . . ${\~~$o->m} . . . Ick! :-)

        Edit: Added the text "or a floating point number."

        -sauoq
        "My two cents aren't worth a dime.";
        
Re: I don't use printf enough
by jdtoronto (Prior) on Oct 22, 2003 at 18:14 UTC
    Which, for me, raises an interesting point.

    I have NEVER used printf in Perl! I think that I cam to hate them with such vehemence, ferocity and vitriol in C that my brain now fails to admint their very existence. Do you get the idea that I didn't enjoy my experience writing 'C'? I was actually brainless enough to write a lot of stuff in 'C' during the 80's. I think I know why I have a full head of grey hair now. In fact, it may have been easier to do it in Z80 assembler (I was working with Micromation multi-processor machines with Z-80's, MC6809's or 80186's!)

    Maybe I might look at them in Perl? But then maybe not, I like concatenation operators :)

    jdtoronto

      I agree completely. The only reason I ever use printf and sprintf in Perl is to create fixed-width files, especially ones with left-padding.

      ------
      We are the carpenters and bricklayers of the Information Age.

      The idea is a little like C++ templates, except not quite so brain-meltingly complicated. -- TheDamian, Exegesis 6

      ... strings and arrays will suffice. As they are easily available as native data types in any sane language, ... - blokhead, speaking on evolutionary algorithms

      Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

      I find sprintf is still the best way to convert numbers into hex format, and printf is a good way to get columns of text that all line up.

      Other than that, print is just as good, and you don't have to remember all those format letters to use it.

Re: I don't use printf enough
by herveus (Parson) on Oct 22, 2003 at 18:44 UTC
    Howdy!

    print "text text ", $obj->method1(), " more text ", $obj->method2(), " blah blah ", $obj->method3(), "\n";

    yours,
    Michael
Re: I don't use printf enough
by DentArthurDent (Monk) on Oct 22, 2003 at 19:23 UTC
    Neither one is better than the other really in a syntactical sense. They're about the same length. I've found with printf that it's easy to lose track of what is printing in which part of the format, whereas the print one has all of them embedded where they go.

    I generally use print, but I do use sprintf a lot to generate strings if operations are then done with or on them.

    I'm a C programmer who uses perl sometimes, so take my opinions as worth a large grain of NaCl. However, there are a lot of True Believers (tm) on here who would have you think that anything that looks like C is evil. That is worth an equivalent amount of NaCl.

    If chemistry wasn't your best subject, NaCl is the chemical formula for table salt.
    ----
    May your tongue cleave to the roof of your mouth with the force of a thousand caramels.
Re: I don't use printf enough
by Abigail-II (Bishop) on Oct 22, 2003 at 20:53 UTC
    Sometimes I prefer to use some extra variables to make things more readable. This might be such a case:
    my $method1 = $obj -> method1; my $method2 = $obj -> method2; my $method3 = $obj -> method3; print "text text $method1 more text $method2 blah blah $method3\n" +;

    Abigail

Re: I don't use printf enough
by atcroft (Monsignor) on Oct 22, 2003 at 21:07 UTC

    I can see using it or not as a decision depending on what circumstance allows. Would the following also work, though?

    print( join('', ('text text ', $obj->method1(), ' more text ', $obj->method2(), ' blah blah ', $obj->method3(), "\n") ) );

      Ummm. Unless $, is set to something besides undef, why join? print accepts a list just as easily as a single string.

      I often use a similar construct, like so:
      use constant DELIM => "\t"; my $fh = IO::File->new(">$filename") || die $!; print $fh join(DELIM, 'Col 1', 'Col 2', 'Col 3', ), $/; # And so forth

      Yes, I should use something like Text::xSV, but it currently doesn't do output.

      ------
      We are the carpenters and bricklayers of the Information Age.

      The idea is a little like C++ templates, except not quite so brain-meltingly complicated. -- TheDamian, Exegesis 6

      ... strings and arrays will suffice. As they are easily available as native data types in any sane language, ... - blokhead, speaking on evolutionary algorithms

      Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

Re: I don't use printf enough
by demerphq (Chancellor) on Oct 22, 2003 at 23:12 UTC

    I find that I often end up converting simple concatenation or interpolating print statements into (s)printfs. Especially as they get larger and more cumbersome I find the template-arg list approach more convenient and easier to manage. A useful trick is things like this:

    printf "Some string %s in the file %s for %s", map { defined $_ ? $_ : 'undef' } $arg1,$arg2,$arg3;

    Or if you are using ternaries in the output or whatever. Unlike BrowserUK and others I find printf a lot easier to manage. Also heres a cute trick (that I will eventually release as a CPAN module with more features)

    package _XSprintf; use overload '""' => sub { shift->() }; package main; sub xsprintf { my $fmt =shift; my $bind=\@_; return bless sub { sprintf $fmt,@_ ? @_ : @$bind },'_XSprintf'; } my ($char,$ord,$bits)=('A'); my $diag=xsprintf("%s : %3d => '%8s'\n",$char,$ord,$bits); for ($char='A';length($char)==1;$char++) { $ord=ord $char; $bits=unpack 'B*',$char; print $diag; } __END__ A : 65 => '01000001' B : 66 => '01000010' C : 67 => '01000011' D : 68 => '01000100' E : 69 => '01000101' ...

    Possibly not the most persuasive example, but on a number of occasions ive used this to greatly simplify diagnostics output inside of loops. Unfortunately it doesnt play nicely with for(LIST) because the iterator var is aliased, and accordingly it isn't in the bound argument array.


    ---
    demerphq

      First they ignore you, then they laugh at you, then they fight you, then you win.
      -- Gandhi


(Re: I don't use printf enough) Interpolation.pm
by bart (Canon) on Oct 23, 2003 at 00:42 UTC
    While we're at it, may I point you towards the module Interpolation too? MJD (who originally wrote and released it, it is now maintained by another person) originally thought of it as nothing but a joke, but it's actually quite a handy way to insert often used function calls of one parameter into doublequotish strings.

    The way it does it, is by tieing (most commonly) a hash to a function, making use of perl's remarkable feature that it always treats the index as code, and executes it before looking up the associated hash value. This function can simply pass its parameter along, allowing you simply insert a calculated scalar.

    I see basically two basic ways to use it. The first route, is using the official import interface, like this:

    # "Official" import mechanism use Interpolation commify => sub { local $_ = scalar reverse shift; s/(\d+\.)|(\d\d\d)(?=\d)/$1 || "$2,"/ge; return scalar reverse $_; }; $a = 12345.21; $b = 1357.98; print "$a*$b with commas inserted looks like '$commify{$a*$b}'.\n";
    which produces:
    12345.21*1357.98 with commas inserted looks like '16,764,548.2758'.
    Oh, yes. That does indeed perform a multiplication.

    Do you see the relationship between the parameter for use, the string "commify", and the global hash %commify? You do?!? Well I don't, that' why I like the tie approach better, as you can tie any hash, a global, a variable from another package, or a lexical. Incidently, this snippet does basically the same thing as the previous one:

    # Non-obfuscated form, using tie(): use Interpolation; my %commify; tie %commify, Interpolation => sub { local $_ = scalar reverse shift; s/(\d+\.)|(\d\d\d)(?=\d)/$1 || "$2,"/ge; return scalar reverse $_; }; $a = 12345.21; $b = 1357.98; print "$a*$b with commas inserted looks like '$commify{$a*$b}'.\n";
    It's lots less obscured how it does what it does, so scoping issues etc. will be much more on familiar terrain.

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others taking refuge in the Monastery: (6)
As of 2014-10-23 02:21 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    For retirement, I am banking on:










    Results (123 votes), past polls