projectfluent / fluent-rs

Rust implementation of Project Fluent
https://projectfluent.org
Apache License 2.0
1.07k stars 96 forks source link

Add support for adding resources with overrides #143

Closed zbraniecki closed 4 years ago

zbraniecki commented 4 years ago

Fixes #142.

Stas, I'd like to get your r? mostly for the API decisions, in an effort to bring fluent-rs more into Fluent core realm.

The JS API relies heavily on default argument values for API ergonomics and in Rust we don't have the same luxury.

There are three options I can see using:

1) Required arguments:

impl FluentBundle {
    fn add_resource(&mut self, r: R, allow_overrides: bool) -> Result<()>;
}

2) Separate API:

impl FluentBundle {
    fn add_resource(&mut self, r: R, allow_overrides: bool) -> Result<()>;
    fn add_resource_with_overrides(&mut self, r: R);
}

3) Options bag with defaults:

#[derive(Default)]
struct FluentBundleAddResourceOptions {
    allow_overrides: bool
}

impl FluentBundle {
    fn add_resource(&mut self, r: R, options: FluentBundleAddResourceOptions) -> Result<()>;
}

allowing for:

bundle.add_resource(&res, FluentBundleAddResourceOptions::default());

or maybe even Option<FluentBundleAddResourceOptions> to allow for add_resource(&res, None)

or maybe even:

impl FluentBundle {
    fn add_resource(&mut self, r: R, options: FluentBundleAddResourcOptions) -> Result<()>;
    fn add_resource_with_defaults(&mut self, r: R) -> Result<()>;
}

========

My current approach, which is based on observation of how stdlib APIs are designed, but not really confirmed and may be just my interpretation is that I want to use (1) very rarely and only in cases where I believe the decision should be consciously made each and every time the API is used. I use (2) for most cases where the defaults are sane and I expect them to be used most of the time, but I want to allow for alternative behavior.

I have never seen anyone doing (3) but it may be because we are still fairly early in the high-level APIs design, so maybe no standard model emerged yet.

One nice thing about (2) in this particular case is that it allows me to drop Result because the method becomes infallible, but for general design decisions that shouldn't be a main factor.

stasm commented 4 years ago

Here are my general thoughts on the design of such APIs:

zbraniecki commented 4 years ago

There are some differences in result of how Rust impl treats the constructor options - for example in Rust you can turn isolating on/off without having to recreate an instance. That's fixable and we can in the future consider adding setIsolating to FluentBundle in JS. Just mentioning.