# Meta-proposal: Towards common ECMA 402 API surface for Rust

[fmil@google.com](mailto:fmil@google.com)

2020-05-21

See [README.md](README.md) for the full index of proposals.


## Motivation

_Usable text internationalization for Rust, **today**._

### Why now?

[ECMA402][ecma402] is a state-of-the-art Intl API, Rust needs Intl API,
designing trait-set for ecma402 surface is the logical next step.

[ecma402]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl

## Goal

_Validate the concept of a common ECMA 402 API, or fail quickly._


## Landscape

Rust's support for internationalized text handling is "[still very immature and
unstable, with most libraries being only weeks old and not used in production
yet](https://www.arewewebyet.org/topics/i18n/)".  The [ECMA-402 support feature
request for Rust](https://github.com/rust-lang/rfcs/issues/858) has been open
for 5 years, with currently no resolution.

Two factors could have contributed:

*   **The enormous barrier to entry.**

	Writing internationalized text support requires specific knowledge of
	internationalization, as well as the many corner cases of particular
	languages.  Such knowledge typically exceeds the knowledge of any one
	person, making an organized team effort practically a requirement to make
	progress.

*   **Relatively niche interest.**

	Anecdotally it seems to me that, when it comes to internationalization,
	people are in general ready to scale down their aspirations if there is no
	canned solution to their problem.  But if you _really _need it, then there
	is no fallback solution for you.

So, the prophecy is self-fulfilling: we'd be glad to use a library if it
existed; but we are unwilling to contribute because it's expensive to make.
The status quo continues.

I'll present an assumption: **if robust text internationalization support were
available for Rust today, then people who need it would use it in their Rust
programs**.  I tested this assumption with
[`rust_icu`](https://github.com/google/rust_icu), a Rust wrapper for the
[Unicode's ICU library](https://icu.unicode.org/).  The `rust_icu`
library has so far seen no use outside of Fuchsia OS. But it **makes it cheap**
to contribute internationalized text support thanks to ICU providing the heavy
lifting.

To illustrate: it took me a morning and half an afternoon to provide [collation
(locale-sensitive sorting)](https://crates.io/crates/rust_icu_ucol) support for
Rust building on top of `rust_icu`.  There were no Rust collation libraries
prior to that afternoon.  In contrast, ICU4X is in early development phase, and
not ready for general use.


## Proposal

Given that thanks to `rust_icu` it is fairly cheap to provide some
functionality now, let's provide and advertise a functional implementation of
ECMA 402 **today**.  Once ICU4X is mature enough to support comparable
functionality, an ECMA 402 implementation could be switched to ICU4X.

**This will allow us to start benefiting from the functionality before ICU4X is
fully functional.**

Roughly the sequence of steps to make this happen is as follows:

1.  Design an ECMA 402 API for Rust.
1.  Implement the ECMA 402 API from (1) with `rust_icu`.
    a.  (Welcome any alternative implementations as well!)
1.  Publish the implementation (2) for use.
1.  Once ICU4X is ready, implement the API from (1) with ICU4X.
	a.  This does not preclude a "transitional" implementation where some
	functionality is partially provided by `rust_icu`, and partially by ICU4X.
	It may not be very efficient in that way, but allows for a smooth
	transition into the future.

**Why ECMA 402 (versus something else)?** ECMA 402 is a well understood API.
We can short-circuit a lot of the aspects of API design (neat, but not crucial)
and evolution (crucial, very time-consuming otherwise) by reusing that API
surface.

**What about functionality that is outside of ECMA 402?**  That functionality
is out of scope.

**Why tie ICU4X to `rust_icu`?**  Well, perhaps not.  But... *if* it is worth
doing, we should, because we get value out of it sooner.


## Requirements

*   **Conformance.**

	The API should conform to the ECMA 402 specification.

*   **Generality.**

	It should be possible to implement the API with `rust_icu`, as well as with
	ICU4X, as well as with another backing library.

	It seems like generality should go without saying.  However, I found
	practical problems with designing a general Rust API based on data
	structures that promote direct field access.


## Open Question(s)

1.  The main question I'm unsure about is **whether it is practical to require
	both `rust_icu` and ICU4X to admit an implementation of exactly the same
	ECMA 402 API surface.**

	The practicality in this case means, how large the adaptors from `rust_icu`
	to ECMA 402, and from ICU4X to ECMA 402 would be.  For example, if the
	extensive repackaging of data is needed to adapt ECMA 402 to the
	implementation API, then perhaps it is more cost efficient to expend that
	effort into developing the underlying libraries. Perhaps it is easier to
	allow them to have different API surfaces, which, if you hold them
	correctly, give you the ECMA 402 functionality as a result; but if you as a
	user wanted to migrate from one to the other, you'd need to migrate the
	code.

	I made some previous attempts to make a uniform strongly typed Rust API
	which would be able to use both the ICU4X Locale, and `rust_icu`'s `ULoc`,
	and I think that was a failure: the data access to the structs is different
	enough that a lot of adaptation work is needed.

1.  Another question is, assuming that the approach is sufficiently practical,
	**whether it is acceptable to weaken the API compile-time guarantees to be
	able to have thin adaptors to the underlying implementation**.  This would,
	for example, promote an API surface which uses types that are as general as
	possible, e.g a ["stringly typed"](https://wiki.c2.com/?StringlyTyped) API.

1.  Finally, at **which point should we conclude whether this is a practical
	effort**. It seems very hard to answer the above questions without having
	specific examples to look at.  I intend to do the work needed to present
	examples for public scrutiny.


## Approach

If any of the steps in the sequence fails, later steps become unnecessary and
we decide that the common API approach is not valid. (Each respective project
of course remains relevant, but their unification not so much.)

1.  **Identify a small part of the ECMA 402 API surface (for example
	`Intl.ListFormat`).**

	The result of this step will be a narrowly scoped piece of functionality
	that we can examine closely.

	Since the ECMA 402 API methods are generally very similar (each has a
	constructor taking locales and options, for example), it should be possible
	to look at a minimal example, and generalize from there.

1.  **Write up a proposed Rust API for that functionality and submit for public
	comments in ICU4X.**

	The result of this step would be a sample API surface that we can actually
	implement,

	This will allow us to get a rough idea how ergonomic the API is, as
	compared to:
        1.  General ideas on API usability
        1.  Specific constraints of idiomatic API design in Rust

1.  **Expose `rust_icu` functionality needed to implement this API surface.**

	There's a practical gotcha here: `rust_icu` covers a smallish percentage of
	the ICU4C API surface, so depending on the outcome of (1) work may be
	necessary to expose any functionality that is missing for a functional
	implementation.

1.  **Implement the API from (2) in terms of (3) as a proof of concept.**

    This will show us how much adaptation work is needed.

1.  **Implement the API from (2) in terms of ICU4X.**

	To the extent that ICU4X is ready.  A fake implementation (conforming
	interface, but bogus result) would in my opinion be acceptable here.

