String.prototype.repeat

# Devin Samarin (14 years ago)

I was looking at strawman:string_dup and I thought I would come up with an implementation that would be suitable. Something that I think would be appropriate IMO.

String.prototype.repeat = function(times) {        // Let str be the result of calling ToString passing thethis value as the argument.        var str = ""+this;

// Let amount be the result of calling ToNumber passingtimes as the argument.        amount = +times;

// If amount is NaN, returnstr.        if (isNaN(amount)) return str;

// If ToUint32(amount) is not equal toamount, throw a RangeError.        if (amount >>> 0 !== amount) throw new RangeError("invalid

repeat argument");

// If `amount is zero, return the empty String.        if (amount === 0) return "";

// Let `k be 1.        var k = 1;

// Let R equalstr.        var R = str;

// Repeat, while k is less thanamount.        while (k < amount) {                // Let R be a String value produced by concatenating R and str.                // (Using arrays might be faster, but it is written like this for clarity)                R += str; // (Throw some internal error if `R is too large)

// Increase `k by 1.                k++;        }

// Return `R.        return R; };

I might have changes to my idea here: eboyjr.homelinux.org:8080/testing/js/?pp=repeat.js

-- ,

Devin Samarin <eboyjr14 at gmail.com>

# Jorge (14 years ago)

Or perhaps to overload * ?

'a' * 5 -> "aaaaa"

?

# Jeff Walden (14 years ago)

On 01/09/2011 06:02 AM, Jorge wrote:

Or perhaps to overload * ?

'a' * 5 -> "aaaaa"

?

Probably a bridge too far. Operator overloading this way results in all those weird implicit conversion behaviors we all know and love (not), true. But at this point there's the matter of compatibility:

'3' * 5 -> better produce 15

That sort of conversion isn't an entirely unreasonable thing to do, in all honesty, given that implicit conversion is here to stay at this point.

I'm not opposed to making it easier to get a repeated string. Yet I admit I'm not so concerned about it that adding to the language itself seems warranted, when (as demonstrated) it's easy for the developer to do so himself. Aside from possibly a very small increase in performance if the repetition factor is large (depending on the implementation), and the functionality being built-in and thus more convenient, I'm not sure what a repeat method in the specification buys you over what you can do for yourself.

# Devin Samarin (14 years ago)

Honestly though, I think the repeat function is good enough. Someone said that there should be a cap of String.repeat at 255, but I don't think that is a good idea, or else:

"*".repeat(256);

will not work. I think it should only throw a range error if it's not NaN or a positive 32-bit integer. And then it should throw an implementation-defined internal memory error when the string is too long.

On Sun, Jan 9, 2011 at 5:47 AM, Jeff Walden <jwalden+es at mit.edu> wrote:

On 01/09/2011 06:02 AM, Jorge wrote:

Or perhaps to overload * ?

'a' * 5 ->  "aaaaa"

?

Probably a bridge too far.  Operator overloading this way results in all those weird implicit conversion behaviors we all know and love (not), true.  But at this point there's the matter of compatibility:

'3' * 5 -> better produce 15

Unless we introduce the pragma: use python; =)

# Felipe Gasper (14 years ago)

On 1/9/11 6:02 AM, Jorge wrote:

Or perhaps to overload * ?

'a' * 5 -> "aaaaa"

Perl has the “x” operator for things like that...

# Jason Orendorff (14 years ago)

On Sat, Jan 8, 2011 at 8:21 PM, Devin Samarin <eboyjr14 at gmail.com> wrote:

// Let str be the result of calling ToString passing thethis value as the argument.        var str = ""+this;

Trivia: ""+obj is not the same thing as ToString(obj). They differ if obj has a .valueOf method.

js> ""+({valueOf: function(){return 1;}}) "1" js> String({valueOf: function(){return 1;}}) "[object Object]"

I find Note 1 in ES5 11.9.3 a bit misleading in this regard.

Also trivia: For what it's worth, you can use Array(+n+1).join(s) as a rough approximation of s.repeat(n). It even has pretty reasonable error behavior (throwing a RangeError for most nonsensical values of n, though not all).

# Dmitry A. Soshnikov (14 years ago)

On 22.03.2011 23:42, David Bruant wrote:

Hi,

About the string_repeat strawman (strawman:string_repeat), one alternative solution could be a two argument constructor. Something like: String(n, pattern). So, for the example in the strawman, it would be String(3, '*').

A little bit off-topic, but not so big off-topic. Recently on Twitter there was a question why it's not an array of zeros:

Array(100).map(function() { return 0; }); // not the array of zeros

the answer is known of course (there's no any property in the created array), but similary to your String(n, '*'), there can be also Array.fill(100, 0); or Array.init(100, 0);

P.S.: though, of course all these can be done manually in ES itself.

Dmitry.

# David Bruant (14 years ago)

About the string_repeat strawman (strawman:string_repeat), one alternative solution could be a two argument constructor. Something like: String(n, pattern). So, for the example in the strawman, it would be String(3, '*'). In ES5, the String constructors (String and new String) both are expected to be used with zero or one argument, so using a two argument constructor should not break the web or people's expectations.

# David Bruant (14 years ago)

Le 22/03/2011 21:42, David Bruant a écrit :

Hi,

About the string_repeat strawman (strawman:string_repeat), one alternative solution could be a two argument constructor. Something like: String(n, pattern). So, for the example in the strawman, it would be String(3, '*'). In ES5, the String constructors (String and new String) both are expected to be used with zero or one argument, so using a two argument constructor should not break the web or people's expectations.

David

I have faced the problem of generating a string with length n while thinking on the problem of "for a given object, how to generate a string which isn't the name of one of its own properties?" (ecmascript#33). One solution was to use a Cantor-diagonal-like strategy. The other solution I've come up with is to take all property names, take the maximum length of it and generate a string with this length + 1. Since it's a problem I have faced and there is a strawman for it, I thought it could be interesting to discuss how to solve the "string generation" problem, even though not really frequent.

# David Bruant (14 years ago)

Le 22/03/2011 02:39, Dmitry A. Soshnikov a écrit :

On 22.03.2011 23:42, David Bruant wrote:

Hi,

About the string_repeat strawman (strawman:string_repeat), one alternative solution could be a two argument constructor. Something like: String(n, pattern). So, for the example in the strawman, it would be String(3, '*').

A little bit off-topic, but not so big off-topic. Recently on Twitter there was a question why it's not an array of zeros:

Array(100).map(function() { return 0; }); // not the array of zeros

It's not that much off-topic. I have made the mistake myself facing this issue :-) (ecmascript#33#c6)

the answer is known of course (there's no any property in the created array), but similary to your String(n, '*'), there can be also Array.fill(100, 0); or Array.init(100, 0);

P.S.: though, of course all these can be done manually in ES itself.

Of course and these cases do not happen once a day. However, when they happen, it's convenient if the language offers a native construct.

# Peter van der Zee (14 years ago)

On Tue, Mar 22, 2011 at 2:39 AM, Dmitry A. Soshnikov < dmitry.soshnikov at gmail.com> wrote:

On 22.03.2011 23:42, David Bruant wrote:

Hi,

About the string_repeat strawman ( strawman:string_repeat), one alternative solution could be a two argument constructor. Something like: String(n, pattern). So, for the example in the strawman, it would be String(3, '*').

A little bit off-topic, but not so big off-topic. Recently on Twitter there was a question why it's not an array of zeros:

Actually I think Array.fill or Array#fill should be added for one of the reasons for repeat: it is very likely that the host environment can iterate (or even optimize) a repeat/fill much much faster than the es interpreter could possibly achieve through looping. Especially with larger numbers.

(I'm happy once we can use a native String#repeat :)

Otoh, I don't think the second problem David points out (generate unique property names) should become part of the spec. Seems to me to be a rather obscure use case.

# David Bruant (14 years ago)

Le 22/03/2011 22:29, Peter van der Zee a écrit :

On Tue, Mar 22, 2011 at 2:39 AM, Dmitry A. Soshnikov <dmitry.soshnikov at gmail.com <mailto:dmitry.soshnikov at gmail.com>> wrote:

On 22.03.2011 23:42, David Bruant wrote:
Hi,

About the string_repeat strawman
(http://wiki.ecmascript.org/doku.php?id=strawman:string_repeat),
one alternative solution could be a two argument constructor.
Something like: String(n, pattern). So, for the example in the
strawman, it would be String(3, '*').
A little bit off-topic, but not so big off-topic. Recently on
Twitter there was a question why it's not an array of zeros:

Actually I think Array.fill or Array#fill should be added for one of the reasons for repeat: it is very likely that the host environment can iterate (or even optimize) a repeat/fill much much faster than the es interpreter could possibly achieve through looping. Especially with larger numbers.

(I'm happy once we can use a native String#repeat :)

Otoh, I don't think the second problem David points out (generate unique property names) should become part of the spec. Seems to me to be a rather obscure use case.

I agree. I solved that problem for testing purposes. Sorry if I was unclear; I didn't mean to standardize this one. Just the string (and array?) generation.

# Dmitry A. Soshnikov (14 years ago)

On 23.03.2011 0:18, David Bruant wrote:

Le 22/03/2011 02:39, Dmitry A. Soshnikov a écrit :

On 22.03.2011 23:42, David Bruant wrote:

Hi,

About the string_repeat strawman (strawman:string_repeat), one alternative solution could be a two argument constructor. Something like: String(n, pattern). So, for the example in the strawman, it would be String(3, '*').

A little bit off-topic, but not so big off-topic. Recently on Twitter there was a question why it's not an array of zeros:

Array(100).map(function() { return 0; }); // not the array of zeros It's not that much off-topic. I have made the mistake myself facing this issue :-) (ecmascript#33#c6)

Yep, I see. Btw, JFTR: such a mistake currently is in this strawman strawman:shorter_function_syntax:

let randomArray = Array(10).map(#{Math.random()});

it's better to fix the doc.

Dmitry.

# Brendan Eich (14 years ago)

On Mar 23, 2011, at 12:57 PM, Dmitry A. Soshnikov wrote:

Yep, I see. Btw, JFTR: such a mistake currently is in this strawman strawman:shorter_function_syntax:

let randomArray = Array(10).map(#{Math.random()});

Fixed, in a cheezy but I hope clear fashion.

# Dmitry A. Soshnikov (14 years ago)

On 24.03.2011 0:44, Brendan Eich wrote:

On Mar 23, 2011, at 12:57 PM, Dmitry A. Soshnikov wrote:

Yep, I see. Btw, JFTR: such a mistake currently is in this strawman strawman:shorter_function_syntax:

let randomArray = Array(10).map(#{Math.random()});

Fixed, in a cheezy but I hope clear fashion.

Yep, it's OK now; and this NonHoleyArray abstraction is also interesting. Meanwhile it's an abstraction, such a thing can be needed. And from this viewpoint I can imagine the same fill or init method, but which can accept not only the number of elements and the direct value for each element, but also a fill-function (indirect value). Then the user can do it in one pass then. E.g.:

Array.fill(5, 0); // [0, 0, 0, 0]

Array.fill(5, #{Math.random()}); [0.1, 0.3, 0.5, 1, 0]

Dmitry.

# Dmitry A. Soshnikov (14 years ago)

On 24.03.2011 0:44, Brendan Eich wrote:

On Mar 23, 2011, at 12:57 PM, Dmitry A. Soshnikov wrote:

Yep, I see. Btw, JFTR: such a mistake currently is in this strawman strawman:shorter_function_syntax:

let randomArray = Array(10).map(#{Math.random()});

Fixed, in a cheezy but I hope clear fashion.

There are other the same examples (with alternative syntax) in the strawman.

let randomArray = Array(10).map(fn{Math.random()});

etc.

Since # syntax is already (almost completely?) accepted, probably there's no a big need in mentioning all alternative which anyway won't be accepted. Though, it's of course good for the history.

Dmitry.

# David Bruant (14 years ago)

This is purely an editing issue, but for String.prototype.repeat, Number is passed as an argument while String isn't. Following the idea of correctness that Mark Miller used in [1], I propose to pass neither Number nor String and just to the Object.defineProperty.

David

[1] : esdiscuss/2011-April/013654

# Allen Wirfs-Brock (14 years ago)

Do sweat it...this will eventually be completely recast in terms of the ES spec. language and any necessary coercions will be specified in terms of the specification's abstract operations.

# Brendan Eich (14 years ago)

Good catch, I fixed. Thanks,