8

The docs say that fmt

Returns a string where each element in the list has been formatted according to $format [the first argument] and where each element is separated by $separator [the second argument].

Based on that description, I expected to be able to call .fmt on a List of Lists, and then pass a printf-style format string containing a % directive for each element in the inner list. But that doesn't work.

If you'd told me that I was wrong about ^^^^, I'd have expected that .fmt was auto-flattening its arguments and thus that each argument would be formatted and separated by the $separator. But that's also not what happens.

Instead, running this code


say (<a b c>, <1 2 3>, <X Y Z>).fmt('→%03s|', "\n=================\n");

produces this output:

→00a| →00b| →00c|
=================
→001| →002| →003|
=================
→00X| →00Y| →00Z|

That is, the format string is applied to each element in the inner lists, those lists are then stringified (without using the format string; note the between each | and character), and then the separator is inserted between each outer list.

That leaves me with three questions:

  1. Have I correctly described/understood the current behavior? [edit: nope. See below]
  2. Is this behavior intentional or an odd bug? (I checked Roast, but didn't see anything either way)
  3. Assuming this is intentional, why? Is there some way that this is consistent with Raku's general approach to handling lists that I'm missing? Or some other reason for this (imo) surprising behavior?

Edit:

After further investigation, I've realized that the behavior I observed above only occurs if the format string contains a width directive. Changing the →%03s| format string from above to →%s| produces the following output:

→a b c|
=================
→1 2 3|
=================
→X Y Z|

That is, without a width, the format string is applied after the list is stringified rather than before.

So I'm back to being confused/thinking at least some of this behavior must be buggy.

Elizabeth Mattijsen
  • 25,654
  • 3
  • 75
  • 105
codesections
  • 8,900
  • 16
  • 50
  • 1
    "(imo) surprising". Imo surprise is always relative to surmise, whether intellectual due to intellectual surmise or bodily due to bodily surmise. Surmise is always subjective, due to one's personal wiring, knowledge, and so forth. So surprise is also always subjective. If your surmise alters such that some erstwhile surprise is no longer an intellectual surprise, your experience of surprise will eventually go away, though it'll take a while for your body to catch up, whether the change in surmise is due to an intellectual "Ahhh" (it is a bug) or "Ohhh" (it's not a bug). Now, what was the Q? – raiph Sep 10 '21 at 20:45
  • 1
    That condition is intended to be a cheap way to check if it really only has a single `%s` in the string: then, but only then, a short-cut is taken that will just interpolate the element as a `.Str` without having to invoke the relatively expensive `sprintf` handling. – Elizabeth Mattijsen Sep 11 '21 at 14:08

1 Answers1

8

Ok, it looks like there were at least two bugs here. This should be fixed with https://github.com/rakudo/rakudo/commit/a86ec91e36 . Writing spectests for these situations, would be appreciated :-)

Elizabeth Mattijsen
  • 25,654
  • 3
  • 75
  • 105
  • 2
    Thanks – both for the answer and the fix! Just for the record, what _is_ the correct behavior/what will it be once that patch lands? – codesections Sep 11 '21 at 22:39
  • "I'd have expected that .fmt was auto-flattening its arguments and thus that each argument would be formatted and separated by the $separator. " That is the behaviour it should have had in the first place. The patch has landed already, all it now needs is someone to write some tests :-) – Elizabeth Mattijsen Sep 12 '21 at 08:48