Skip to content

String.fromCharCode and String.fromCharCodes should be const constructors #49407

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
rakudrama opened this issue Jul 6, 2022 · 4 comments
Open
Labels
area-core-library SDK core library issues (core, async, ...); use area-vm or area-web for platform specific libraries. library-core type-enhancement A request for a change that isn't a bug

Comments

@rakudrama
Copy link
Member

I have needed to construct constant expression strings from their code points.
This usually happens in programs that do some string processing with code points.
Sometimes it is desired to define named constants for both the code unit and the String.

This is currently impossible to construct a constant String form a code point, and impossible construct a const code point from a String. This leads to constants that are not obviously consistent:

const codeA = 0x41;
const charA = 'A`;

These could be correct by construction:

const codeA = 0x41;
const charA = String.fromCharCode(codeA);

dart-lang/language#2219 proposes making aString.codeUnitAt(anInt) a potentially constant expression, permitting

const codeA = charA.codeUnitAt(0);
const charA = 'A';

However, using String.codeUnitAt has a UTF-16 pitfall. The following is correct

const codePerson = 0x1F9D1;
const charPerson = String.fromCharCode(codePerson);

whereas this not:

const codePerson = charPerson.codeUnitAt(0);
const charPerson = '🧑';

This request is broken out from dart-lang/language#2219 (comment)

@rakudrama rakudrama added area-core-library SDK core library issues (core, async, ...); use area-vm or area-web for platform specific libraries. library-core labels Jul 6, 2022
@lrhn lrhn added the type-enhancement A request for a change that isn't a bug label Jul 7, 2022
@lrhn
Copy link
Member

lrhn commented Jul 7, 2022

Making String.fromCharCodes a const constructor is a lie. It takes an iterable, and there is no constant way to iterate an iterable. Even if we require the argument to be the result of a constant list literal, there is still no in-language way to iterate a constant list.

Doesn't mean we can't do it, it just requires special-casing in the compilers, the magic doesn't happen in the constructor,
and we likely need to mention the restriction (argument must be result of const list literal expression) in the language specification.

How about:

  • Introduce a view on positive integers that are Unicode scalar values. Call it char.
  • Give that view a toString() which is the string containing that code point.
  • Allow constant interpolations to contain expressions of type char.
  • Profit!

Then you do

const codePerson = char(0x1f9d1);
const charPerson = "$codePerson";

(Hmm, that does mean that views need to have const constructors. Might be an issue.)

@rakudrama
Copy link
Member Author

@lrhn Some questions:

Q1: So can String.fromCharCode can be const? I don't want String.fromCharCode to be delayed because of some issue with String.fromCharCodes.

Q2: I don't get why making String.fromCharCodes a const constructor.is a 'lie'. We have other const constructors that are only const if the argument is const.

class Foo {
  final Iterable<int> ints;
  const Foo(this.ints);
}

const aFoo = Foo([1,2,3]);

As far as evaluation goes, if we can spread constant Iterables, there must be a mechanism in the compiler for accessing the elements of the constant operand.

@lrhn
Copy link
Member

lrhn commented Jul 8, 2022

The String.fromCharCode also needs compiler cooperation. We can't write it in pure Dart code. The only way to allocate a string in constant Dart code is a string literal, and as you recognized, there is no way to go from code point to string, or vice versa, in constant (or potentially-constant) code.

A plain generative Dart const constructor is limited in what it can do. It can create an instance of the class it's on, and it can fill in (necessarily final) fields by evaluating only potentially constant expressions.
The String.fromCharCode/String.fromCharCodes factory constructors do more than that.

There is no way to write a generative String constructor in plain Dart. Therefore there is no way to write a const constructor in plain Dart, because it must either be generative or be redirecting to another const constructor.

To have const String.fromCharCode(42) or const String.fromCharCodes([42]) requires the compilers (and analyzer) to recognize the calls, extract the arguments, and create a constant string instance from it without calling a String constructor, like it does for string literals.

That's not impossible. We do it for const Symbol already.
It's just not a simple library change. It's not just a simple const constructor like other const constructors (that's why I say we "lie".)

It might be possible to handle it entirely in the front-end, effectively rewriting const String.fromCharCode(42) or const String.fromCharCodes([42]) into the string literal "\u002a".
And we don't even need to make the constructors const to enable this rewrite, we can do it on any invocation to those constructors with suitable constant arguments. (Still need the const to allow the invocation in a constant context, though.)

So, this is a front-end request more than a library request.

@eernstg
Copy link
Member

eernstg commented Jul 8, 2022

this is a front-end request

I suggested at some point that this should be an SDK issue with 'area-library' (rather than a language repo issue) because I would not expect the language specification to mention it, not because I thought that it could be implemented without going outside the language. This is similar to, e.g., bool.hasEnvironment.

Maybe, if adopted and scheduled for implementation, it's an 'area-meta' with sub-issues in 'area-library' and in 'area-front-end'?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-core-library SDK core library issues (core, async, ...); use area-vm or area-web for platform specific libraries. library-core type-enhancement A request for a change that isn't a bug
Projects
None yet
Development

No branches or pull requests

3 participants