Bug 17269 – formattedWrite of struct with Nullable string fails

Status
RESOLVED
Resolution
FIXED
Severity
normal
Priority
P1
Component
phobos
Product
D
Version
D2
Platform
x86_64
OS
Linux
Creation time
2017-03-21T10:33:53Z
Last change time
2021-02-05T11:01:33Z
Keywords
pull
Assigned to
RazvanN
Creator
Tomáš Chaloupka

Comments

Comment #0 by chalucha — 2017-03-21T10:33:53Z
This code fails (dmd-2.072.2): import std.stdio; import std.array; import std.format; import std.typecons; struct Foo { Nullable!string bar; } void main() { Foo f; auto ap = appender!string; formattedWrite(ap, "%s", f); writeln(ap.data); } core.exception.AssertError@/usr/include/dmd/phobos/std/typecons.d(2309): Called `get' on null Nullable!string. ---------------- ??:? _d_assert_msg [0x4503a6] ??:? std.typecons.Nullable!(immutable(char)[]).Nullable.getinout(pure nothrow ref @property @nogc @safe inout(immutable(char)[]) function()) [0x4443a1] ??:? pure @safe void std.format.formatElement!(std.array.Appender!(immutable(char)[]).Appender, std.typecons.Nullable!(immutable(char)[]).Nullable, char).formatElement(std.array.Appender!(immutable(char)[]).Appender, std.typecons.Nullable!(immutable(char)[]).Nullable, ref std.format.FormatSpec!(char).FormatSpec) [0x445bbc] ??:? pure @safe void std.format.formatValue!(std.array.Appender!(immutable(char)[]).Appender, nullableformat.Foo, char).formatValue(std.array.Appender!(immutable(char)[]).Appender, ref nullableformat.Foo, ref std.format.FormatSpec!(char).FormatSpec) [0x444d08] ??:? pure void std.format.formatGeneric!(std.array.Appender!(immutable(char)[]).Appender, nullableformat.Foo, char).formatGeneric(std.array.Appender!(immutable(char)[]).Appender, const(void)*, ref std.format.FormatSpec!(char).FormatSpec) [0x444ca0] ??:? pure @safe uint std.format.formattedWrite!(std.array.Appender!(immutable(char)[]).Appender, char, nullableformat.Foo).formattedWrite(std.array.Appender!(immutable(char)[]).Appender, const(char[]), nullableformat.Foo) [0x444c3f] ??:? _Dmain [0x44427d] ??:? _D2rt6dmain211_d_run_mainUiPPaPUAAaZiZ6runAllMFZ9__lambda1MFZv [0x451277] ??:? void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).tryExec(scope void delegate()) [0x4511a3] ??:? void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).runAll() [0x45121c] ??:? void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).tryExec(scope void delegate()) [0x4511a3] ??:? _d_run_main [0x451107] ??:? main [0x44ef57] ??:? __libc_start_main [0xe4ccf400]
Comment #1 by razvan.nitu1305 — 2017-03-28T07:42:32Z
I think we're in a dilemma here since whatever choice we make there will be inconsistencies. Nullable's get should throw (and it does) when you try to fetch the value (1); on the other hand, formattedWrite should print nulls (2) but when it tries to fetch the nullable (by calling get) an exception is thrown due to statement (1). As I see it, there are 2 possibilities: either we make Nullable's get method return null if the value is unassigned or we specialize formattedWrite for Nullable's (which is not a valid measure). In my opinion, it should be on the user's account to check if the Nullable is assigned before printing it, thus making this error a user error.
Comment #2 by chalucha — 2017-03-28T08:15:32Z
It's easy to handle this with just one value to print, but when it is used in some more complex structure for example just for the simple debugging purposes, it becames PITA to workaround it while otherwise all fields of the structure are printed just fine. Nullable.get can't return null as it is meant to return the value type. For example Nullable!int(42).get can't return null. So in my opinion only specialized formattedWrite can be considered. For example in C# this is not the problem: http://www.tutorialspoint.com/csharp/csharp_nullables.htm I think that Nullable should be as user friendly as it is possible. See for example issue #13017 which was finally fixed recently.
Comment #3 by chalucha — 2017-03-28T08:19:44Z
One more thing. Nullable!int foo; writefln("%s", foo); outputs Nullable.null So it is at least inconsistent here.
Comment #4 by andre — 2017-06-15T16:56:15Z
This issue is also reproducible with std.conv: text import std.conv: text; import std.typecons; struct Foo { Nullable!string bar; } void main() { string s = Foo().text; }
Comment #5 by cromfr — 2017-10-19T17:05:53Z
struct TestInt { Nullable!int value; } writeln(TestInt());//Print: Nullable.null struct TestString { Nullable!string value; } writeln(TestString());//Raise exception Nullable!string is implicitly convertible to a string, thus calling the following std.format.formatElement overloading: ``` void formatElement(Writer, T, Char)(auto ref Writer w, T val, const ref FormatSpec!Char f) if (is(StringTypeOf!T) && !is(T == enum)) ``` that generates the exception when trying to store the string value in a variable here: https://github.com/dlang/phobos/blob/05e65e6086d8d5ebdd1b95350cb6a79a1198e7d0/std/format.d#L3072 The correct called overloading should be: ``` void formatElement(Writer, T, Char)(auto ref Writer w, auto ref T val, const ref FormatSpec!Char f) if (!is(StringTypeOf!T) && !is(CharTypeOf!T) || is(T == enum)) ``` that forwards to a formatValue call. I am currently working on a pull request
Comment #6 by bugzilla — 2019-12-07T13:53:29Z
*** Issue 19435 has been marked as a duplicate of this issue. ***
Comment #7 by schveiguy — 2020-01-10T18:25:45Z
Ran into this today. I may work on a PR to fix it. Any ideas if this is in progress? Very annoying when it happens, especially when you print a Nullable!string directly, it works.
Comment #8 by cromfr — 2020-01-11T12:00:26Z
I already opened a PR for this: https://github.com/dlang/phobos/pull/5797 But it never got merged due to a compiler bug having some interactions with the bug fix.
Comment #9 by dlang-bot — 2021-01-31T15:41:54Z
@CromFr updated dlang/phobos pull request #5797 "Issue 17269: formattedWrite of struct with Nullable value fails" fixing this issue: - Fix Issue 17269 - Use toString if available instead of implicitly converting to string - Add code from issue 17269 as unittest https://github.com/dlang/phobos/pull/5797
Comment #10 by dlang-bot — 2021-02-05T11:01:33Z
dlang/phobos pull request #5797 "Issue 17269: formattedWrite of struct with Nullable value fails" was merged into master: - f1ff0097abd10bb420e61920fcc4efb0d678a0a7 by Crom (Thibaut CHARLES): Fix Issue 17269 - Use toString if available instead of implicitly converting to string - 06689a6b506ea25f6388bfc8cccea4a6ec050ee3 by Sebastian Wilzbach: Add code from issue 17269 as unittest https://github.com/dlang/phobos/pull/5797