Ever since fail and assert got turned into macros, failing with a string message has become quite line-noisy:

fail!(~"cause")

And including additional informations in the fail message makes the line quite heavy, even though it should be encouraged for better failure messages:

fail!(fmt!("failed because of %?", cause))

For context: fail takes a ~str because it needs to own the string, so that it can be send to the platform thread and displayed during task failure. assert has the same requirement for its optional second argument, but currently accepts a &str because it performs a copy internally.

A discussion on IRC resulted in these possible options:
1. Rewrite fail!() and assert!() to accept both ~str or &'static str:
fail!(): unchanged
fail!(~"cause"): unchanged
(not possible now) -> fail!("cause")
fail!(fmt!("failed because of %?", cause)): unchanged
...etc

Pro: No unnecessary copy, 100% backwards compatible.
Con: Kinda hard to implement, fail!(fmt!()) still heavy.

2. Turn fail and assert into diverging functions:
fail!() -> fail()
fail!(~"cause") -> fail_owned(~"cause")
(not possible now) -> fail_static("cause")
fail!(fmt!("failed because of %?", cause)) -> fail_owned(fmt!("failed because of %?", cause))
...etc

Pro: No macros necessary.
Con: Users need to remember different function signatures for failing, fail_owned(fmt!()) even more heavy.

3. Rewrite fail!() and assert!() to pass arguments to fmt!():
fail!(): unchanged
fail!(~"cause") -> fail!("s", ~"cause")
(not possible now) -> fail!("cause")
fail!(fmt!("failed because of %?, cause)) -> fail!("failed because of %?", cause)
...etc

Pro: Easy formatted message per default, common case fail!("static str") needs no '~' sigil, failure macros work similar to logging macros.
Con: Heavier syntax if you have a ~str already, always copies string.
(however, fmt!() could get an optimisation so that fmt!("...") expands to ~"...", and fmt!("s", s) to s)

4. (1 + 3) Rewrite fail!() and assert!() to accept ~str and &'static str if 1 argument, pass arguments to fmt!() if more than 1:
fail!(): unchanged
fail!(~"cause"): unchanged
(not possible now) -> fail!("cause")
fail!(fmt!("failed because of %?, cause)) -> fail!("failed because of %?", cause)

Pro: All of 1 and 3.
Con: Even harder to implement than 1, quite complex.

Personally I think 3 is the easiest to implement option, and nice even without the fmt! optimisation. I already locally implemented the necessary changes that would allow switching to it after an snapshot, but I wanted to ask what others think.



_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to