# repeat

Definition: | sequence s = repeat(object x, integer n, bool allow_strings=true)
Description: | Create a sequence of length n where each element is x.
pwa/p2js: | Prior to version 1.0.0 the repeat function would perform a bulk refcount update and rely on subsequent copy-on-write semantics. For example, `repeat(repeat(0,100),100)` would use 800ish bytes and an internal refcount of 100, whereas JavaScript and other programming languages, and in fact Phix itself in probably fairly short order, would use 40,000 bytes. While that was a nice idea, and occasionally might improve startup times a tiny fraction, on deeper reflection it is a completely fake saving, and probably reduces overall performance, especially if anything needs reloading to cache just for the clone, as well as being wholly and utterly incompatible with the pass-by-sharing semantics of JavaScript, and therefore pwa/p2js. It now performs a deep_copy(x) when needed, and I have yet to notice any significant performance loss. For more details see the Incompatibilities section of the p2js documentation. The optional third parameter was introduced in 1.0.2 to help alleviate a significant performance issue when using a binary string to create IupImage() pixel data, for more details see comments.
Comments: | When you repeat a string or a floating-point number the interpreter does not actually make multiple copies in memory, instead a single copy is "pointed to" a number of times, though as above nested sequence elements are now deep_copy()’d. For efficiency reasons, if the item to be repeated appears to be a character, ie is an integer in the range 7 to 255, a string is created, otherwise a dword-sequence is created. Better overall performance was also observed by making repeat(0,n) create a dword-sequence rather than a string of nulls which was very likely to be auto-expanded to a dword sequence in the near future. Generally speaking, all further handling of the result is completely transparent whether a string or dword-sequence is created, with the following exceptions: performance gains, explicit tests with the string() builtin, #isginfo directives, accessing it using inline assembly, and lastly holding raw binary can be done in a string as one byte per element, rather than 4 or 8, which might need a secondary poke() before use. In JavaScript, strings are "immutable", and hence pwa/p2js.js/$repe() performs `s[1..i-1] & ch & s[i+1..$]` aka `t = t.substring(0,idx-1) + String.fromCodePoint(x) + t.substring(idx);` which for a 500x500 IupImage() pixel data could mean copying 250,000 bytes to set each pixel (this problem was only first noticed after some 18 months of using p2js). No such penalty occurs for dword-sequences aka JavaScript Arrays. For that reason, repeat() now [1.0.2+] has an optional third parameter to prevent it from creating (binary) strings. Compatibility note: Euphoria allows an atom length/count, whereas Phix requires an integer, since I believe that deliberately trapping say 11.99 (which Euphoria truncates to 11) may help expose the occasional programming error at source, rather than ten minutes later when the sequence turns out to be one element too short.
Example 1: |
    repeat(0, 10)       -- {0,0,0,0,0,0,0,0,0,0}
Example 2: |
    repeat("JOHN", 4)   -- {"JOHN", "JOHN", "JOHN", "JOHN"}
    -- The interpreter creates only one copy of "JOHN" in memory,
    --  and increases the reference count of that one item by 4.
Example 3: |
    repeat('=', 10)     -- "=========="  (a string)
Implementation: | See builtins\repeat.e (an autoinclude) for details of the actual implementation. [Moved from VM\pRepeatN.e in 1.0.0] There is also a different hand-crafted version in p2js.js which obviously uses native JavaScript functions instead of %:pAllocSeq, etc.
See Also: | append, prepend, sequence-formation operator
Technicalia | Internally, when the compiler spots an obvious character, it maps repeat() to repeatch(), which can be called explicitly and has the advantage of yielding type string, rather than sequence (string|dword_sequence), and in so doing may permit subsequent optimisations, via type inference. There are in fact a couple of places in the compiler itself that take advantage of the fact that repeat(0,n) and repeat(‘\0’,n) are treated differently, and specifically there are #isginfo{code/data_section,T_String..} directives to ensure that interpretation can use them in-situ rather than allocate and poke every time we run anything. Note that explicitly calling repeatch, which is not available on Euphoria, performs an implicit "non-integer agnostic" low-level and_bits(x,#FF), and hence yields incorrect results if x is not an integer or outside the range 0..255, rather than an error, so if you must use repeatch(), do so sparingly and carefully. Of course repeating a unicode character/code point of #100 or perhaps more realistically #80 and above would require a dword-sequence rather than a "string", and the equivalent UTF-8 string would be constructed either by applying utf32_to_utf8() to said or perhaps applying join() to several multi-byte strings, but in either case repeatch() would be wholly inapplicable. repeatch() has an optional third parameter, nFrames, for the benefit of repeat(), so that the runtime error message "repeat count must not be negative" always points at user code rather than within builtins/repeat.e itself.