terjek has asked for the wisdom of the Perl Monks concerning the following question:

Hey fellow monks

Take a look of the following three perl samples, and ask yourself what you think the output will be before you try them.

perl -wle 'my @a=1..9; printf"$a[%d]\n", 4' perl -wle 'my @a=1..9; printf"$a[%2d]\n", 4' perl -wle 'my @a=1..9; printf"\$a[%d]\n", 4'

I know that putting the $a[] in the sprintf in this way is not a common use of sprintf and i could easily do this and it would work :

perl -wle 'my @a=1..9; printf"%d\n", $a[4]'

I'm just curiuos to why perl behaves this way. When i use \$a, then %d is interpreted as a printf conversion as it should, but when i'm using just $a, then it interpret %d as an hash.

Terje

Replies are listed 'Best First'.
Re: Weird ? behavior of printf / sprintf
by ysth (Canon) on Jul 12, 2007 at 08:45 UTC
    First what's in the "" is combined into a format string, then printf interprets it.

    In the first step, an element of @a is being interpolated into the string. That element's index is given as %d (in your first example), which is a valid expression that produces 0, since it's an empty hash in scalar context. In the second example, the expression given as the index is invalid and produces a syntax error. In the third, the \ makes the $ literal, so no interpolation is attempted.

    Some people find it easier to think of strings as being compiled rather than interpolated at runtime. So you can think of your first two examples as compiling to concatenated literals and variables:

    perl -wle 'my @a=1..9; printf $a[%d] . "\n", 4' perl -wle 'my @a=1..9; printf $a[%2d] . "\n", 4'
    Does your problem seem more obvious there?
Re: Weird ? behavior of printf / sprintf
by Anno (Deacon) on Jul 12, 2007 at 09:06 UTC
    The "weird behavior" you observe has nothing to do with sprintf, it's just interpolation in double-quoted strings.

    Seeing "$a[%d]", the interpolation rules require that $a[...] interpolates an element of @a in the string. That means that the part inside [...] is interpreted as Perl code, not as part of the string. Thus %d is evaluated as an undeclared hash in scalar context (it can because you are running without strict), which is 0. The result is the same as "$a[0]", which is "1".

    For similar reasons, "$a[%2d]" is a syntax error.

    In "\$a[%d]" the dollar sigil is escaped, so the part in [...] is a plain string and the result is $a[%d].

    If something is weird about the behavior, it's string interpolation itself. Mainly your example serves as an object lesson on the importance of strictures.

    Anno

Re: Weird ? behavior of printf / sprintf
by citromatik (Curate) on Jul 12, 2007 at 08:42 UTC

    My interpretation is that printf makes variable substitution before format the output. This means that in:

    printf"$a[%d]\n", 4

    $a[%d] is interpreted before %d, then warns. The same happens in the second example

    In the last one:

    perl -wle 'my @a=1..9; printf"\$a[%d]\n", 4'

    Because the $ is scaped, there is no variable substitution and the format process behaves normally

    citromatik

      My interpretation is that printf makes variable substitution before format the output. This means that in:

      Nope, it's not printf: it just takes a qq|| string, which in turn does variable interpolation as usual.

Re: Weird ? behavior of printf / sprintf
by ikegami (Patriarch) on Jul 12, 2007 at 13:48 UTC

    "foo $a[%d] bar"
    is converted to
    "foo " . $a[%d] . " bar"
    when the double-quoted string is compiled. This is called "interpolation".

    printf("$a[%d]\n", 4);
    is therefore the same thing as
    printf($a[%d] . "\n", 4);
    which is definitely not what you want.

    Single-quotes avoid interpolation, and so does escaping the characters ($ and @) that would cause interpolation
    printf('$a[%d]'."\n", 4);
    printf("\$a[%d]\n", 4);

Re: Weird ? behavior of printf / sprintf
by atemon (Chaplain) on Jul 12, 2007 at 10:01 UTC

    "print behavior" is a very recent discussion on behavior of "print" ( not printf ). I thought it worth these two threads linked together.


    Obfuscation is NOT the only measure of expertise.

Re: Weird ? behavior of printf / sprintf
by dsheroh (Monsignor) on Jul 12, 2007 at 15:36 UTC
    If $var in a double-quoted string is replaced by the value of $var, then I would fully expect %hash in a double-quoted string to be replaced by the value of %hash. These results, then, are exactly as I would expect.

    To do otherwise would be inconsistent.

    To do otherwise, but only in the specific case of sprintf format strings (or other contexts where $, @, or % have special meanings), is to enter a morass of special-case rules which will surely lead to madness.