www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Format

reply newbie <newbie no.com> writes:
I am following 
https://wiki.dlang.org/Defining_custom_print_format_specifiers, 
why sink and formatValue are not  safe? What are the best 
practice for toString in safe code? Thank you
May 21 2021
parent reply drug <drug2004 bk.ru> writes:
21.05.2021 16:45, newbie пишет:
 I am following 
 https://wiki.dlang.org/Defining_custom_print_format_specifiers, why sink 
 and formatValue are not  safe? What are the best practice for toString 
 in safe code? Thank you
sink is obsolete now, use W(riter) ```D import std.range : isOutputRange; void toString(W)(ref W writer) const if (isOutputRange!(W, char)) { // your stuff } ``` writer can be safe, nogc, nothrow etc like you want
May 21 2021
parent reply newbie <newbie no.com> writes:
On Friday, 21 May 2021 at 13:59:13 UTC, drug wrote:
 21.05.2021 16:45, newbie пишет:
 I am following 
 https://wiki.dlang.org/Defining_custom_print_format_specifiers, why sink and
formatValue are not  safe? What are the best practice for toString in safe
code? Thank you
sink is obsolete now, use W(riter) ```D import std.range : isOutputRange; void toString(W)(ref W writer) const if (isOutputRange!(W, char)) { // your stuff } ``` writer can be safe, nogc, nothrow etc like you want
Thank you, and formatValue?
May 21 2021
parent reply cc <cc nevernet.com> writes:
On Friday, 21 May 2021 at 14:19:03 UTC, newbie wrote:
 Thank you, and formatValue?
formattedWrite should handle this. ```d safe struct Foo { int x = 3; void toString(W)(ref W writer) if (isOutputRange!(W, char)) { writer.formattedWrite("Foo(%s)", x); } } Foo foo; writeln(foo); ``` Oddly enough this form of toString works from safe code even if it's not marked safe, or even marked system...
May 21 2021
parent reply drug <drug2004 bk.ru> writes:
21.05.2021 18:28, cc пишет:
 On Friday, 21 May 2021 at 14:19:03 UTC, newbie wrote:
 Thank you, and formatValue?
formattedWrite should handle this. ```d safe struct Foo {     int x = 3;     void toString(W)(ref W writer) if (isOutputRange!(W, char)) {         writer.formattedWrite("Foo(%s)", x);     } } Foo foo; writeln(foo); ``` Oddly enough this form of toString works from safe code even if it's not marked safe, or even marked system...
I guess that because it is a template so the compiler is able to deduce its attributes. What about the case when it is marked system - in this case compiler ignore that method due to the fact that it is system and generate the default one. Because your implementation of the method is equal to the default implementation you didn't see the difference but it exists. Try to make your implementation of `toString` different and you'll see.
May 21 2021
parent reply cc <cc nevernet.com> writes:
On Friday, 21 May 2021 at 16:53:48 UTC, drug wrote:
 21.05.2021 18:28, cc пишет:
 On Friday, 21 May 2021 at 14:19:03 UTC, newbie wrote:
 Thank you, and formatValue?
formattedWrite should handle this. ```d safe struct Foo {     int x = 3;     void toString(W)(ref W writer) if (isOutputRange!(W, char)) {         writer.formattedWrite("Foo(%s)", x);     } } Foo foo; writeln(foo); ``` Oddly enough this form of toString works from safe code even if it's not marked safe, or even marked system...
I guess that because it is a template so the compiler is able to deduce its attributes. What about the case when it is marked system - in this case compiler ignore that method due to the fact that it is system and generate the default one. Because your implementation of the method is equal to the default implementation you didn't see the difference but it exists. Try to make your implementation of `toString` different and you'll see.
Ahh, in that case it would appear formattedWrite isn't safe at all. Looks like you have to stick with put()? ```d safe void toString(W)(ref W writer) if (isOutputRange!(W, char)) { //writer.formattedWrite!("FOO:%s", x); // fails import std.conv; put(writer, "FOO:"); put(writer, x.to!string); } ```
May 21 2021
parent reply cc <cc nevernet.com> writes:
On Saturday, 22 May 2021 at 03:07:10 UTC, cc wrote:
 Ahh, in that case it would appear formattedWrite isn't  safe at 
 all.  Looks like you have to stick with put()?
 ```d
  safe void toString(W)(ref W writer) if (isOutputRange!(W, 
 char)) {
 	//writer.formattedWrite!("FOO:%s", x); // fails
 	import std.conv;
 	put(writer, "FOO:");
 	put(writer, x.to!string);
 }
 ```
Oops, disregard this. I had an error in my imports.😓 It does in fact work in safe.
May 21 2021
parent reply cc <cc nevernet.com> writes:
On Saturday, 22 May 2021 at 03:14:35 UTC, cc wrote:
 Oops, disregard this.  I had an error in my imports.😓
 It does in fact work in  safe.
I should add as an aside then that there is an issue of errors from the body of a toString template not being displayed, and instead the template being silently skipped, e.g.: ```d safe void toString(W)(ref W writer) if (isOutputRange!(W, char)) { writer.formattedWrite("FOO:%s", x); syntactically correct; // Program will compile without error, but this function will now never be called } ``` I ran into a similar challenge with opDispatch some time ago: https://forum.dlang.org/post/axgwhzzawncbpcvqqrur forum.dlang.org In this case I assume it's some consequence of NOT wanting to emit a warning or error for every single class or struct that doesn't have a templated toString when the various output writers go looking for one. Something like this can help reveal errors, not sure if there's an easier way: ```d unittest { struct DebugWriter { void put(C)(C c) {} } DebugWriter wr; Foo foo; foo.toString(wr); } ``` `Error: undefined identifier 'syntactically'` `Error: template instance 'amemfailuretest.Foo.toString!(DebugWriter)' error instantiating`
May 21 2021
parent drug <drug2004 bk.ru> writes:
22.05.2021 06:07, cc пишет:
 Looks like you have to stick with put()?
yes, OutputRange assumes put(). If put() does not support string (accepts char only) I use std.algorithm.copy. 22.05.2021 07:58, cc пишет:
 On Saturday, 22 May 2021 at 03:14:35 UTC, cc wrote:
 Oops, disregard this.  I had an error in my imports.😓
 It does in fact work in  safe.
I should add as an aside then that there is an issue of errors from the body of a toString template not being displayed, and instead the template being silently skipped, e.g.:
yes, it's really annoying because you need to write additional code to reveal the error like you do:
 
 Something like this can help reveal errors, not sure if there's an 
 easier way:
 ```d
 unittest {
      struct DebugWriter {
          void put(C)(C c) {}
      }
      DebugWriter wr;
      Foo foo;
      foo.toString(wr);
 }
 ```
 `Error: undefined identifier 'syntactically'`
 `Error: template instance 'amemfailuretest.Foo.toString!(DebugWriter)' 
 error instantiating`
May 22 2021