Bug 19982 – padLeft usability issues

Status
RESOLVED
Resolution
INVALID
Severity
normal
Priority
P1
Component
phobos
Product
D
Version
D2
Platform
All
OS
All
Creation time
2019-06-18T21:02:55Z
Last change time
2019-07-06T00:53:55Z
Assigned to
No Owner
Creator
Stephen Grammer

Comments

Comment #0 by sgrammer — 2019-06-18T21:02:55Z
padLeft appears to be implicitly converting the input string into an array of uints. The documentation mentions using byGrapheme, but the compiler can't handle it. --------------------------------------------------- import std.range : padLeft; import std.stdio : writeln; import std.uni : byGrapheme; import std.array : array; void main() { string s = "a string"; writeln(s.padLeft('0', 10)); // [48, 48, 97, 32, 115, 116, 114, 105, 110, 103] writeln("a string".padLeft('0', 10)); // [48, 48, 97, 32, 115, 116, 114, 105, 110, 103] writeln("a string".padLeft(dchar('0'), 10)); // "00a string" (correct!) // example directly from the documentation writeln("abc".padLeft('_', 6)); // [95, 95, 95, 97, 98, 99] // Error: template std.range.padLeft cannot deduce function from argument types !()(Result!string, char, int) // writeln(byGrapheme("abc").padLeft('_', 6)); // Error: template std.range.padLeft cannot deduce function from argument types !()(Grapheme[], char, int), // writeln(byGrapheme("abc").array.padLeft('_', 6)); }
Comment #1 by shove — 2019-06-19T05:25:30Z
I think the function you want is: std.string.leftJustify(), std.string. rightJustify(). -------------------------------- std.range.padLeft() is normal, and it returns a range. The assert in the source file and the four lines I added are as follows: -------------------------------- import std.algorithm.comparison : equal; assert([1, 2, 3, 4].padLeft(0, 6).equal([0, 0, 1, 2, 3, 4])); assert([1, 2, 3, 4].padLeft(0, 3).equal([1, 2, 3, 4])); assert("abc".padLeft('_', 6).equal("___abc")); assert("a string".padLeft('0', 10).equal("00a string")); assert("a string".padLeft('0', 10).equal([48, 48, 97, 32, 115, 116, 114, 105, 110, 103])); assert("a string".padLeft(dchar('0'), 10).equal("00a string")); assert("a string".padLeft(dchar('0'), 10).equal([48, 48, 97, 32, 115, 116, 114, 105, 110, 103]));
Comment #2 by sgrammer — 2019-06-19T16:21:10Z
Thanks! I missed leftJustify. That is exactly what I need. If you are planning to add more asserts to document the behavior of padLeft, maybe consider adding: ------------------------------------------------------- // implicitly converts to a range of uint when padding dchar[] with char static assert(is(ElementType!(typeof("string".padLeft('0', 10))) == uint)); static assert(is(ElementType!(typeof("string".padLeft(dchar('0'), 10))) == dchar));
Comment #3 by shove — 2019-06-20T00:13:23Z
Thanks, I see. There's something unreasonable here.
Comment #4 by shove — 2019-06-20T02:32:35Z
The final step in the internal implementation of padLeft is chain() , and chain() converts multiple different types into a single type that can be accommodated via CommonType. alias X = CommonType!(int, long, short); assert(is(X == long)); alias Y = CommonType!(int, char[], short); assert(is(Y == void)); -------------------------- static assert(is(ElementType!(typeof("string".padLeft('0', 10))) == uint)); static assert(is(ElementType!(typeof("string".padLeft(dchar('0'), 10))) == dchar)); The corresponding types of these two sentences are transformed as follows: alias Z1 = CommonType!(char, dchar); static assert(is(Z1 == uint)); alias Z2 = CommonType!(dchar, dchar); static assert(is(Z2 == dchar)); So there is no problem with the design here, we can use it flexibly after mastering this feature.
Comment #5 by sgrammer — 2019-06-20T17:29:15Z
I didn't realize chain was so presumptuous. This makes me want to go check all of my code that uses chain and make sure I'm using it correctly. It IS documented though, which is comforting: "Due to safe type promotion in D, chaining together different character ranges results in a uint range." Should we resolve this issue, or use it to improve documentation of some of these behaviors?