A proposal to add String.prototype.format

Brendan Eich brendan at mozilla.com
Wed Mar 9 15:39:00 PST 2011


One thought, I had to share after laying it on dherman in person:

We sure could use a pure-JS implementation of the proposal, on github, so people can *use* it. A lot of the arguments here should be settled by beating on the anvil of an open-source, forkable implementation, and may the sharpest fork, er, sword, win.

I'd hate to be on a committee that had to pick the winner prematurely, or really, without user testing and feedback -- and yes, even forking that led to greater user testing and eventual consolidation.

Separately I think TC39 does agree that injection-attack safety is a goal, and for this reason quasis are still on our agenda. Can we combine forces or at least make proposals combine well?

/be

On Mar 9, 2011, at 3:35 PM, Shanjian Li wrote:

> That part is for sure, ie. we won't have gratuitously different pattern formats and styles of operation. As to how the internationalized one will be designed and implemented, two possibilities.
> 1. I18n feature (locale specific behavior) will be implemented through extend the existing mechanism (like bob's idea, to pass formatting responsibility to object's toFormat() method). 
> 2. I18n feature will be implemented on top of the generic form, using it as a foundation.
> 
> shanjian
> 
> On Wed, Mar 9, 2011 at 3:14 PM, Gillam, Richard <gillam at lab126.com> wrote:
> If we're going to ultimately have two APIs that do the same thing-- a generic one and an internationalized one-- can we at least avoid having them have gratuitously different pattern formats and styles of operation?
> 
> --Rich Gillam
>   Lab126
> 
> On Mar 9, 2011, at 3:01 PM, Nebojša Ćirić wrote:
> 
>> This proposal intentionally avoids i18n issues and focuses on general formatting. One can still use i18n features from our API like so:
>> 
>> var locale = new LocaleInfo();
>> var df = locale.dateTimeFormat();
>> 
>> "I got married on {0}".format(df.("12/03/2001")); 
>> 
>> MessageFormat was focusing on plurals and gender, and we couldn't reach consensus on actual message format and scope, so we postponed it. Also, we aim to avoid adding i18n API objects into core language at this moment.
>> 
>> 09. март 2011. 14.53, Shawn Steele <Shawn.Steele at microsoft.com> је написао/ла:
>> I would postpone any formatting stuff until the i18n stuff was better understood.
>> 
>> 
>> - Shawn
>> 
>>  
>> http://blogs.msdn.com/shawnste
>> 
>> 
>> -----Original Message-----
>> From: es-discuss-bounces at mozilla.org [mailto:es-discuss-bounces at mozilla.org] On Behalf Of Gillam, Richard
>> Sent: Wednesday, March 09, 2011 2:46 PM
>> To: es-discuss at mozilla.org
>> Subject: Re: A proposal to add String.prototype.format
>> 
>> It seems worth mentioning that this functionality sounds an awful lot like what MessageFormat does, and MessageFormat was in the i18n strawman (and I have it in my own i18n implementation).  It doesn't seem like we need two different "formatted string" APIs.
>> 
>> --Rich Gillam
>>  Lab126
>> 
>> On Mar 9, 2011, at 2:36 PM, Adam Shannon wrote:
>> 
>> > I rather like the idea of having this syntax for string formatting:
>> >
>> > "name: {name:first} {name.last}".format(name)
>> >
>> > It allows for more complex operations
>> >
>> > "name: {person.firstName} \nstart:
>> > {myEvent.startTime}".format(myEvent, person)
>> >
>> > Also, it doesn't require mundane fixes later on and keeps things
>> > simple for the developer. (No needed knowledge or maintenance of
>> > things based on position.)
>> >
>> > On Wed, Mar 9, 2011 at 15:36, Shanjian Li <shanjian at google.com> wrote:
>> >> I like this idea.  I thought a lot about how to support those locale
>> >> specific stuff like plural and gender. Your suggestion provide an
>> >> elegant way to transfer the responsibility to a more appropriate party.
>> >>
>> >> shanjian
>> >>
>> >> On Wed, Mar 9, 2011 at 1:18 PM, Bob Nystrom <rnystrom at google.com> wrote:
>> >>>>>
>> >>>>> 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
>> >>>>
>> >>>
>> >>
>> >>
>> >> _______________________________________________
>> >> es-discuss mailing list
>> >> es-discuss at mozilla.org
>> >> https://mail.mozilla.org/listinfo/es-discuss
>> >>
>> >>
>> >
>> >
>> >
>> > --
>> > Adam Shannon
>> > UNI Freshman
>> > Web Developer
>> > ashannon.us
>> > _______________________________________________
>> > es-discuss mailing list
>> > es-discuss at mozilla.org
>> > https://mail.mozilla.org/listinfo/es-discuss
>> 
>> _______________________________________________
>> es-discuss mailing list
>> es-discuss at mozilla.org
>> https://mail.mozilla.org/listinfo/es-discuss
>> 
>> _______________________________________________
>> es-discuss mailing list
>> es-discuss at mozilla.org
>> https://mail.mozilla.org/listinfo/es-discuss
>> 
>> 
>> 
>> -- 
>> Nebojša Ćirić
> 
> 
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
> 
> 
> _______________________________________________
> 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/0a2e59ca/attachment-0001.html>


More information about the es-discuss mailing list