I think so far there’s been five serious alternatives if this does get returned for revision, so I figured it’s worth summarizing the pros, cons, and implications of each so we can settle on a design moving forward.
1. 'a'.ascii, callable member
let codepoint:Unicode.Scalar = 'a'
return codepoint.ascii
| Single quoted literals default to | Unicode.Scalar |
| Implementation difficulty | Easy |
| Compile-time validation? | No |
Summary:
The Unicode.Scalar type will get an .ascii computed property, which provides its value with the trapping precondition that value < 0x80.
Pros:
- Readable, concise, and clearly indicates encoding used.
- Has high discoverability as a callable member.
- No new compiler or language features needed.
- No new syntax or semantics.
Cons:
Characterliterals will continue to require type context.Characterliterals either cannot be expressed with single quotes, or would result in ambiguous expressions like'é' as Character.- Impossible to provide compile-time validation guarantees. (The best we can do is a warning heuristic.)
- Member
.asciiwould be available on allUnicode.Scalarvalues, including run-time values (foo.ascii), which doesn’t seem appropriate from an API standpoint. - Exposes users to run-time trapping.
- Privileges ASCII subset of
Unicode.Scalar. - Overloads on return type.
- Strongly ABI-coupled.
2. 'a'.ascii, “literal-bound” member
return 'a'.ascii
| Single quoted literals default to | Character |
| Implementation difficulty | Hard |
| Compile-time validation? | Yes |
Summary:
Swift will support a new method attribute @literalself, essentially a more restrictive version of @constexpression on self. The Character type will get an .ascii computed property which is @literalself, and provides its ASCII value subject to the compile-time condition that it consists of a single codepoint within the ASCII range. Note that this would still be vulnerable to '\r\n' folding.
Pros:
- Readable, concise, and clearly indicates encoding used.
- Provides compile-time validation guarantee.
- Decoupled from ABI.
Cons:
- Extremely magical, could be considered an abuse of dot
.notation. - Effectively introduces entire new kind of instance method to the language, depends on
@constexpressionto generalize into a language feature. - Very low discoverability.
- Privileges ASCII subset of
Unicode.Scalar. - Overloads on return type.
3. 'a' as UInt8
return 'a' as UInt8
| Single quoted literals default to | Character |
| Implementation difficulty | Hard |
| Compile-time validation? | Yes |
Summary:
Swift will introduce the concept of non-expressible literal coercions, which would allow “opt-in” literal coercions through the use of the as operator. (Note that this is not an overload on the as operator, it merely makes this operator mandatory if requested.) Contrast with Swift’s existing expressible literal coercions, which are “opt-out”, and make the as operator optional. All FixedWidthInteger types would receive a non-expressible literal conformance to unicode scalar literals. This is essentially identical to the proposal as written, except it requires an explicit as (U)Int8 everywhere a codepoint literal→ASCII coercion takes place.
Pros:
- Readable (though not as concise).
- Makes it obvious that a literal coercion is taking place.
- Provides compile-time validation guarantee.
- Decoupled from ABI.
Cons:
- Does not indicate ASCII as the specific encoding used.
- Effectively adds a new feature to the literals system (see this post), depends on
@constexpressionto generalize into a language feature.
4. a'a'
return a'a'
| Single quoted literals default to | Character (u'a' defaults to Unicode.Scalar) |
| Implementation difficulty | Medium |
| Compile-time validation? | Yes |
Summary:
Single-quoted literals will be subdivided into multiple prefixed literal sorts. Unprefixed tokens will be parsed as character literals, u-prefixed tokens will be parsed as unicode scalar literals, and a-prefixed tokens will be parsed as integer literals, constrained to the ASCII-range.
Pros:
- Readable, highly concise, indicates encoding used.
- Very few compiler modifications needed, no new language features needed.
- Provides compile-time validation guarantee.
- Decoupled from ABI.
- Easily extensible to provide unambiguous syntaxes for
Unicode.Scalar(u'a') andCharacter('a') literals, as well as alternative character encodings. - No new semantics.
Cons:
- Introduces new syntax to the language. (As opposed to 2 and 3, which only introduce new semantics.)
- Users need to remember single-character abbreviations for each prefix (“
afor ascii”, “ufor unicode scalar”, etc). - Low discoverability.
5. Full ASCII struct
return ('a' as ASCII).value
| Single quoted literals default to | Character |
| Implementation difficulty | Medium |
| Compile-time validation? | Yes |
Summary:
The standard library will gain a full 7-bit ASCII type which is expressible by unicode scalar literals. Compile-time validation will be performed in the compiler in a semi-magical fashion, just like the current proposal as written.
Pros:
- The most conservative and strongly-typed design.
- Few compiler modifications needed, no new language features needed.
- Provides compile-time validation guarantee.
- No new syntax or semantics.
- Mid–high discoverability.
Cons:
- Limited utility. (Useful for generating outputs, but useless for processing input bytestrings.)
- May encourage users to bind raw buffers to this type, which is incorrect. (An arbitrary
(U)Int8cannot be safely reinterpreted as 7-bitASCIIvalue.) - Member
.valueeffectively overloads on return type. - Strongly ABI-coupled.