A proposal to add String.prototype.format

Bob Nystrom rnystrom at google.com
Wed Mar 9 13:18:34 PST 2011


>
> It doesn't specify how to print objects, except for %s, which says that if
>> the argument is not
>> a string, convert it to string using .toString().
>>
>
> If the format specifier does not apply to the argument given, it should
> raise exceptions. Except string conversion, no other conversion will be
> done.
>

I like your first six points, but the formatting string stuff feels odd to
me: neither dynamic nor object-oriented. C needs format specifiers because
it doesn't otherwise know now to interpret the bits you give. ES doesn't
have that problem.

At the same time, baking a rigid set of formatting instructions into
string.format() feels like a poor separation of concerns. string.format()'s
just is to compose a string out of smaller pieces. Why should it need to
know anything about numbers or dates?

Could we just say that this:

    "hi, {0:blah}.".format(someObj);

Is (conceptually) desugared to:

    ("hi, " + someObj.toFormat("blah") + ".")

So anything after the ":" in an argument (the format string) gets passed to
the object itself by way of a call to toFormat() (or some other method name)
on it. Then each object can decide what format strings are appropriate for
it.

This keeps the responsibilities separate: string.format() does composition,
and the composed object own their own formatting. It's also extensible: you
can define your own formatting capabilities for your types and use them with
string.format() by defining toFormat(). (By default, I would assume that
Object.prototype.toFormat() just calls toString()).

This, I think, helps with locale issues too. Types like Date that care about
locale will be able to handle it themselves in their call to toFormat()without
string.format() needing to deal with it.

- bob


>
>
>> The string conversion should probably use the internal ToString function
>> instead (which works for null
>> and undefined too).
>>
>
> Agree.
>
>
>> For formats expecting numbers, it should convert the argument to a number
>> using ToNumber.
>>
>
> Probably not. As string is the thing being constructed, it make sense to
> offer "hidden" string conversion. In my experience using this feature in
> Python, it is within expectation and offer some convenience. Any further
> "hidden" conversion should really be avoided.
>
>
>>
>> Rounding is specified as "math.round(n - 0.5)" (capital M in Math?).
>>
>
> Right, thanks.
>
>
>> This leaves it open whether overwriting Math.round should change the
>> behavior of format. It probably
>> shouldn't (i.e., again it would be better to specify in terms of internal,
>> non-use-modifiable functions).
>>
>
> Agree.
>
>
>> The rounding is equivalent to Math.floor(n) (aka round towards -Infinity),
>> if I'm not mistaken, so why
>> not just use that?
>>
>
> In this example, 8 / (3 - 8 / 3) , the display will be 23.99999999999999.
> So the internal representation could be a little bit more or a little bit
> less than the theoretical value due to float precision. Math.round might
> generate less surprise results than Math.floor.  Of cause, the internal
> implementation shouldn't rely on either of these two.
>
>
>
>> (Personally I would prefer truncation (round towards zero), if conversion
>> to integer is necessary).
>>
>> Why can octal, binary and hexidecimal forms only be used on integers?
>> Number.prototype.toString with
>> an argument works on fractions too (try Math.PI.toString(13) for laughs
>> :).
>>
>
>
>> Why only fixed bases (2,8,10,16)? How about adding an optional base
>> parameter to number display (with
>> x, d, o, b as shorthands for the more standard bases)? Again,
>> Number.prototype.toString means that it's
>> already in the language. (I know that step 7 says copy the format of other
>> languages, but that seems
>> shortsighted since ECMAScript is not those languages, and only copying
>> functionality from C verbatim
>> seems like tying your shoelaces together before the race).
>>
>> The question for both questions is how useful is that. If it is only
> needed in one or few rare occasions, it is probably not a good idea to
> complicate the language.
>
>
>
>>
>> "Placeholder used in format specifier part can not have format specifier.
>> This prevent the replacement
>> from embedding more than one level."
>> Should that be "... can not have a placeholder."?
>>
> No.   The former prevent any format specifier (including embedded
> placeholder). Refer to the Python specification, it does make sense.
>
>
>
>> If the placeholder value is not a string, it should be converted to a
>> string.
>> If it is not a valid format, what happens then?
>>
>
> Raise exception?
>
>
>>
>>
>> Is the following valid:
>>  "{x} and {1[y]}".format({x:42},{y:37})
>> I.e., can object property shorthands ({x} instead of {0[x]}) be used if
>> there are more than one argument?
>>
>
> Good points. Possible choices:
> 1. {x} always refer to the first object given.
> 2. {x} only works when there is one and only one object argument.
> 3. {x} will be replaced by the first object that has property x, ie. the
> following should work too.
>     "{x}, {z} and {1[y]}".format({x:42}, {z:43, y:37})
>
> I prefer 1.
>
>
>>
>>
>> And some arbitrary ideas for extension:
>>
>> How about a boolean test that checks for falsy-ness of the argument and
>> acts as one of two other
>> formats or literals?
>> E.g.
>>  "{0:s} drew {1:?his|her} gun.".format(person.name, person.isMale)
>>  "Please press return{0:?.|{1}}".format(notCritical, " and run!")
>>
>
> Interesting. In example 1, the issue is literal get into the placeholder,
> that could make things messy.
>
>
>
>>
>>
>> Or allow computed indices?
>>  "{0[{1}][he]} drew {0[{1}][his]} gun.".format({male:{he:"He",his:"his"},
>> female:{he:"She",his:"her"}}, "female");
>>
>
> Allow embedded placeholder inside the field part (not the format specifier
> part) of a placeholder is something that I will be very cautious about.
>
> shanjian
>
>
>>
>>
>> /L
>> --
>> Lasse Reichstein - reichsteinatwork at gmail.com
>>
>
>
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20110309/6888b33d/attachment.html>


More information about the es-discuss mailing list