Skip to content

Debug escaping is confusingly inconsistent #107035

Open
@dfoxfranke

Description

@dfoxfranke

The behaviors of char::escape_debug, str::escape_debug, and <str as Debug>::fmt are confusingly inconsistent with each other, and the inconsistencies are poorly documented.

fn main() {
    let wat = "a\u{301}'";

    println!("{:?}", wat);
    println!("\"{}\"", wat.escape_debug());
    println!(
        "\"{}\"",
        wat.chars()
            .flat_map(|ch| ch.escape_debug())
            .collect::<String>()
    );
}
"a\u{301}'"
"á\'"
"a\u{301}\'"

It seems defensible that char::escape_debug escapes single-quotes while <str as Debug>::fmt doesn't, since char_escape_debug doesn't know whether it's being used to escape a character literal or a string literal. But if a difference is going to exist, it's less defensible that str::escape_debug should follow the behavior of char::escape_debug rather than the behavior of <str as Debug>::fmt.

str::escape_debug and <str as Debug>::fmt's differing behavior on grapheme extenders makes no sense at all. Furthermore, if the escaping of grapheme extenders is going to be position-dependent (a bad idea IMO), then the rule should be that they are unescaped only if they are preceded by an unescaped character. The current rule gives absurd results in cases like

fn main() {
    println!("{}", "\u{301}\u{301}".escape_debug());
}
\u{301}́

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-UnicodeArea: UnicodeT-libsRelevant to the library team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions