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 |