On 05/03/2013 08:28 AM, Huon Wilson wrote:
Hi all,

Aatch, Kimundi and I (and maybe some others... sorry if I've forgotten
you) came up with a bit of proposal on IRC for handling fmt!. It's
possibly been considered already, but whatever, we'd like some
comments on it.

I'm glad you are thinking about this. fmt! is in desperate need of an overhaul, both in design and implementation.



There would one trait for each format specifier (probably excluding
`?'), e.g. FormatC for %c, FormatD for %d/%i, FormatF for %f, and
format would just require that the value for each format specifier
implements the correct trait. (Presumably this check can be done
"automatically" by attempting to call the appropriate method and
using the type checker.)

In code,


trait FormatC {
  fn format_c(&self, w: &Writer, flags: Flags);
}

impl FormatC for char {
  fn format_c(&self, w: &Writer, _: Flags) { w.write_char(*self) }
}

struct MyChar(char);
impl FormatC for MyChar {
  fn format_c(&self, w: &Writer, _: Flags) { w.write_char(**self) }
}

Good call using Writer here. This is one of the crucial changes that must be made.


fmt!("%c%c%c", 'a', MyChar('a'), ~"str")

// becomes

'a'.format_c(w, {});
MyChar('a').format_c(w, {});
~"str".format_c(w, {});


And the first two would resolve/type-check fine, but the last would
not. (`Flags' would contain the width and precision specifiers and all
that.)

For these pre-existing format specifiers this would allow arbitrary types to be formatted as i.e. characters. This may be overkill. What we *definitely* need though is for all types that are e.g. signed integers to implement `%i`.

`FormatC` I would probably prefer to be `FormatChar`, etc. for clarity.



This could then be extended to have a dynamic formatter, which allows
types to format for any specifier at runtime (i.e. get around compile
time restrictions). Our thoughts were to add an extra flag to indicate
this (e.g. !), so that it is entirely and explicitly opt-in. (Similar
to Python's __format__ and Go's fmt (I think).)


trait DynamicFormat {
  fn format_dynamic(&self, w: &Writer, spec: FormatSpec);
}

fmt!("%!s %!10.3f", a, b)

// becomes

a.format_dynamic(w, {flags: {}, type: 's'});
w.write_str(" ");
b.format_dynamic(w, {flags: {width: 10, prec: 3}, type: 'f'});


(Presumably this could also have a lint mode, to give an error or
warning if dynamic formatting is used.)

I don't understand the use case for this. I would understand (and want) a generic format specifier that defers to some trait, but without specifically using type 's' or 'f'. Something like "%!" that becomes `a.format(w, flags)`, but doesn't try to coerce arbitrary types to print as other arbitrary types.



There were also some other discussions about the fmt! syntax, e.g. it
was suggested that the following could be equivalent to each other

fmt!("%{2}[0].[1]f %{2}e", 10, 3, 1.01);
fmt!("%10.3f %e", 1.01, 1.01);

This is an explicit divergence from printf's slightly archane */'n$'
placeholder syntax. One could use `[*]`  to just refer to the next
argument, like * does by default. (Aatch has a format spec parser[1]
in the works that supports this syntax.)

I agree with reconsidering the inconsistent, underspecified printf syntax, but don't have any specific thoughts on this at this time.

Nice work. I look forward to seeing where this goes.
_______________________________________________
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to