You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
WFL should let a program choose byte-oriented or character-oriented semantics when
indexing and measuring Text. Today only character semantics exist, and there is no byte
counterpart to length of or substring of. Character semantics is the right default and
should stay the default — but a program that must reproduce another system's byte behaviour,
or that processes a byte-oriented format, currently has no way to ask for it.
This is a request for the choice. It is deliberately not a request to change what Text
already does.
Motivation — a concrete case, measured
Porting JShrink (a PHP JavaScript minifier) to WFL
produced a port that matches the original byte-for-byte on 47 of 48 differential test cases,
including the 609,574-byte jquery_ui.js. The single divergence is caused only by the
indexing model.
PHP indexes strings by byte, so the two bytes of π (CF 80) are classified separately.
WFL indexes by character, so π is one unit. Given var π = Math.PI, radians = π / 180:
One space. Both are valid, semantically identical JavaScript.
Worth being precise about the cause, because it is not the character class: the letter test
agrees in both models. preg_match('/^[\w\$\pL]$/', "\xCF") returns 1, since PCRE in non-UTF
mode reads 0xCF as Latin-1 Ï, a letter. The divergence comes purely from how the string
is divided into units.
To confirm that, I patched a copy of the PHP original to change exactly two things — index a
UTF-8 character array instead of bytes, and add /u to the letter test — and ran all 48 cases.
Exactly one output changed: the one above. That patched copy is a faithful model of WFL's
semantics, and the WFL port matches it on 48 of 48. So the port is provably correct for
character semantics; it simply cannot express the byte semantics the source had.
Current state
// "var π" is 5 characters but 6 bytes (π is CF 80 in UTF-8).
store src_text as "var π"
display "length of : " with length of src_text
display "char 4 : " with substring of src_text and 4 and 1
length of : 5
char 4 : π
Exit 0 — correct for character semantics. There is no byte-oriented counterpart to either
line: nothing in the stdlib reports the byte length of a Text, and nothing retrieves byte k. The only byte-named natives are secure_random_bytes (crypto) and content_bytes (web),
neither of which applies to a Text value.
Why the existing binary path does not serve this
Binary is not an escape hatch here — see #702. It reports a correct byte length but cannot
be indexed (Cannot index Binary with Number), iterated (Cannot iterate over Binary), or
sliced. The only working decode route found was inductive — trial-write each of 256 candidate
prefixes, read back, compare — measured at roughly 1.43 s/byte and O(n²), which extrapolates
to days for the 609 KB fixture above. For contrast the character-based port processes that
whole file in 17 seconds.
Binary also only comes from file reads, so it cannot answer a question about a Text value
already in hand.
This issue is therefore related to but distinct from #702: that one asks for Binary to be
inspectable; this one asks for Text to be addressable in bytes when a program needs it.
What "either or" might look like
Sketching shapes rather than prescribing one — the maintainer's call:
Byte-oriented counterparts alongside the existing functions, e.g. byte length of <text>, byte at <text> and <n>, byte substring of <text> and <start> and <count>. Additive, no
effect on existing programs, and reads in the existing natural-language style.
ord/chr equivalents (code of <char>, character from <code>), which would separately
remove the need for the lexicographic ch is less than " " idiom currently used to detect
control characters, and would make \x-style escapes expressible.
Whatever the shape, the properties that matter for this use case are: get the byte length of a Text; get the numeric value of byte k in O(1); and rebuild a Text from bytes losslessly.
Why character-by-default is right, and should not change
Character indexing is the correct default for a language whose first principle is
natural-language readability — length of "café" should be 4. Nothing here argues otherwise.
The gap is that byte semantics are currently unreachable, so a whole class of programs
(faithful ports, wire protocols, byte-exact tooling, anything reproducing a byte-oriented
system's observable behaviour) cannot be written correctly at all.
There is a No-Unlearning angle too: a beginner correctly learns that length of counts
characters, and today a production user who needs bytes has nowhere to grow into. An additive
byte vocabulary would give them that path without changing the beginner's form.
Environment
wfl --version: WebFirst Language (WFL) version 26.8.4
binary: system install C:\Program Files\wfl\bin\wfl.exe
Found while porting G:/repos/JShrink/src/JShrink/Minifier.php (738 lines of PHP) to WFL. The
port is complete, passes 77/77 behaviour tests and 48/48 differential parity, and was not
worked around — the divergence is documented in the port rather than papered over, and this
issue is the honest reason it exists. Related: #702 (Binary opaque).
Summary
WFL should let a program choose byte-oriented or character-oriented semantics when
indexing and measuring
Text. Today only character semantics exist, and there is no bytecounterpart to
length oforsubstring of. Character semantics is the right default andshould stay the default — but a program that must reproduce another system's byte behaviour,
or that processes a byte-oriented format, currently has no way to ask for it.
This is a request for the choice. It is deliberately not a request to change what
Textalready does.
Motivation — a concrete case, measured
Porting JShrink (a PHP JavaScript minifier) to WFL
produced a port that matches the original byte-for-byte on 47 of 48 differential test cases,
including the 609,574-byte
jquery_ui.js. The single divergence is caused only by theindexing model.
PHP indexes strings by byte, so the two bytes of
π(CF 80) are classified separately.WFL indexes by character, so
πis one unit. Givenvar π = Math.PI, radians = π / 180:One space. Both are valid, semantically identical JavaScript.
Worth being precise about the cause, because it is not the character class: the letter test
agrees in both models.
preg_match('/^[\w\$\pL]$/', "\xCF")returns 1, since PCRE in non-UTFmode reads
0xCFas Latin-1Ï, a letter. The divergence comes purely from how the stringis divided into units.
To confirm that, I patched a copy of the PHP original to change exactly two things — index a
UTF-8 character array instead of bytes, and add
/uto the letter test — and ran all 48 cases.Exactly one output changed: the one above. That patched copy is a faithful model of WFL's
semantics, and the WFL port matches it on 48 of 48. So the port is provably correct for
character semantics; it simply cannot express the byte semantics the source had.
Current state
Exit 0 — correct for character semantics. There is no byte-oriented counterpart to either
line: nothing in the stdlib reports the byte length of a
Text, and nothing retrieves bytek. The only byte-named natives are
secure_random_bytes(crypto) andcontent_bytes(web),neither of which applies to a
Textvalue.Why the existing binary path does not serve this
Binaryis not an escape hatch here — see #702. It reports a correct bytelengthbut cannotbe indexed (
Cannot index Binary with Number), iterated (Cannot iterate over Binary), orsliced. The only working decode route found was inductive — trial-write each of 256 candidate
prefixes, read back, compare — measured at roughly 1.43 s/byte and O(n²), which extrapolates
to days for the 609 KB fixture above. For contrast the character-based port processes that
whole file in 17 seconds.
Binaryalso only comes from file reads, so it cannot answer a question about aTextvaluealready in hand.
This issue is therefore related to but distinct from #702: that one asks for
Binaryto beinspectable; this one asks for
Textto be addressable in bytes when a program needs it.What "either or" might look like
Sketching shapes rather than prescribing one — the maintainer's call:
byte length of <text>,byte at <text> and <n>,byte substring of <text> and <start> and <count>. Additive, noeffect on existing programs, and reads in the existing natural-language style.
bytes of <text>returning an indexable list of numbers, plus atext from bytesinverse. This also closes most of No way to express byte-oriented processing: Text is char-indexed and Binary is opaque (length only, cannot index/iterate/slice) #702 ifBinarygained the sameconversion.
ord/chrequivalents (code of <char>,character from <code>), which would separatelyremove the need for the lexicographic
ch is less than " "idiom currently used to detectcontrol characters, and would make
\x-style escapes expressible.Whatever the shape, the properties that matter for this use case are: get the byte length of a
Text; get the numeric value of byte k in O(1); and rebuild aTextfrom bytes losslessly.Why character-by-default is right, and should not change
Character indexing is the correct default for a language whose first principle is
natural-language readability —
length of "café"should be 4. Nothing here argues otherwise.The gap is that byte semantics are currently unreachable, so a whole class of programs
(faithful ports, wire protocols, byte-exact tooling, anything reproducing a byte-oriented
system's observable behaviour) cannot be written correctly at all.
There is a No-Unlearning angle too: a beginner correctly learns that
length ofcountscharacters, and today a production user who needs bytes has nowhere to grow into. An additive
byte vocabulary would give them that path without changing the beginner's form.
Environment
WebFirst Language (WFL) version 26.8.4C:\Program Files\wfl\bin\wfl.exeContext
Found while porting
G:/repos/JShrink/src/JShrink/Minifier.php(738 lines of PHP) to WFL. Theport is complete, passes 77/77 behaviour tests and 48/48 differential parity, and was not
worked around — the divergence is documented in the port rather than papered over, and this
issue is the honest reason it exists. Related: #702 (
Binaryopaque).