digitalmars.D.learn - Purity of delegate-style toString
- Per =?UTF-8?B?Tm9yZGzDtnc=?= (9/9) May 01 2018 In which cases (if any) is it possible to make a delegate-style
- ag0aep6g (27/38) May 01 2018 You have to mark `sink` as pure, too:
- Per =?UTF-8?B?Tm9yZGzDtnc=?= (2/4) May 01 2018 Thanks
- Q. Schroll (36/76) May 06 2018 I had similar issue for opApply.
In which cases (if any) is it possible to make a delegate-style implementation of toString such as void toString(scope void delegate(const(char)[]) sink) const trusted pure { // sink("..."); // sink.formattedWrite!"..."(...); } pure?
May 01 2018
On 05/01/2018 01:44 PM, Per Nordlöw wrote:In which cases (if any) is it possible to make a delegate-style implementation of toString such as void toString(scope void delegate(const(char)[]) sink) const trusted pure { // sink("..."); // sink.formattedWrite!"..."(...); } pure?You have to mark `sink` as pure, too: void toString(scope void delegate (const(char)[]) pure sink) const trusted pure Then the toString method itself works, but it may not be callable by other code that wants to use an impure sink. For example, `format` works, but `writeln` doesn't: ---- struct S { void toString(scope void delegate(const(char)[]) pure sink) const trusted pure { import std.format: formattedWrite; sink("..."); sink.formattedWrite!"%s"(" ..."); } } void main() { import std.format: format; import std.stdio: writeln; writeln(format("%s", S())); /* Ok. Prints "... ...". */ writeln(S()); /* Nope. writeln would like to use an impure sink. */ } ---- By the way, you shouldn't mark toString as trusted when `sink` is system.
May 01 2018
On Tuesday, 1 May 2018 at 12:03:15 UTC, ag0aep6g wrote:By the way, you shouldn't mark toString as trusted when `sink` is system.Thanks
May 01 2018
On Tuesday, 1 May 2018 at 12:03:15 UTC, ag0aep6g wrote:On 05/01/2018 01:44 PM, Per Nordlöw wrote:I had similar issue for opApply. The generalized problem is, the attributes (pure, nothrow, safe, nogc) are too strong on functionals (i.e. functions taking function/delegate arguments). We could (and IMO should) weaken the attributes to mean: the same as always, *assuming all function/delegate arguments have it*. Concrete example, say your `toString(scope void delegate(const(char)[]))` is conceptually pure, i.e. if `sink` is a pure function (by static typing), `toString(sink)` acts pure, and for impure `sink`, `toString(sink)` possibly impure. So purity of the functional `toString` depends on the purity of its arguments; that is very natural as most functionals call their parameters. The current state makes attributes virtually useless for functionals. Often, toString can be templetized without drawback (except virtual functions), but opApply cannot. opApply must not be a template to enable type deduction for the variable.[1] Making attributes act structurally has almost no consequences in terms of breakage; just more functions can be pure/nothrow/ nogc/ safe. It would make functionals impure/unsafe/.. that do not call their argument. The question is, in which contexts are they used and is it an issue -- is it a greater issue than this. Complete example what the change would do: Say you have void toString(scope void delegate(const(char)[]) sink) pure { sink("Example"); } toString is a pure functional, so calling it is pure iff the argument itself is. The compiler statically knows if the argument is pure and can infer the purity of the expression. [1] https://dlang.org/spec/statement.html#foreach_over_struct_and_classes (We could define very general special cases where type deduction can be archived, e.g. opApply(DG : int delegate(Args))(DG).)In which cases (if any) is it possible to make a delegate-style implementation of toString such as void toString(scope void delegate(const(char)[]) sink) const trusted pure { // sink("..."); // sink.formattedWrite!"..."(...); } pure?You have to mark `sink` as pure, too: void toString(scope void delegate (const(char)[]) pure sink) const trusted pure Then the toString method itself works, but it may not be callable by other code that wants to use an impure sink. For example, `format` works, but `writeln` doesn't: ---- struct S { void toString(scope void delegate(const(char)[]) pure sink) const trusted pure { import std.format: formattedWrite; sink("..."); sink.formattedWrite!"%s"(" ..."); } } void main() { import std.format: format; import std.stdio: writeln; writeln(format("%s", S())); /* Ok. Prints "... ...". */ writeln(S()); /* Nope. writeln would like to use an impure sink. */ } ---- By the way, you shouldn't mark toString as trusted when `sink` is system.
May 06 2018