Discussion Thread: DIP 1042--ProtoObject--Community Review Round 1

Adam D Ruppe destructionator at gmail.com
Thu Jan 13 18:10:21 UTC 2022

So let's think about stringify a little.

First, just like with the other things, this isn't a real world 
problem. You can always tighten constraints in subclasses right 
now. You can also add overloads to take a sink, like Throwable 
does, right now. This DIP is worse than nothing.

But let's think about how to do it with virtual functions. Among 
the options:

1) string toString(); You can override this today with @nogc 
etc., but it is tricky to actually implement since it returns a 
string, which is assumed to have no owner. You potentially could 
return a buffer inside the object, or a malloc'd thing or 
whatever too, just this goes against the expected conventions and 
users are liable to misuse it anyway.

I think realistically this signature must either return static 
data or GC'd data. Of course, it can be `pure nothrow @safe` etc. 
today with zero trouble, again subclasses are free to add that 

But let's look at the others for nogc options.

2) Throwable adds an overload `void toString(void delegate(in 
char[]) sink)`

The tricky bit is that sink. Since it isn't labeled @nogc at top 
level, the implementation has to assume it can be passed a gc 
func which means the toString itself also can't be @nogc.

This is very similar to opApply right now - you have to add a 
combination of overloads, and then overriding the right virtual 
slot in subclasses is tricky. Which one do you override? Which 
one do you call on the outside?

Of course, this doesn't need to be known by the implementation! 
Just like `inout`, the implementation could be treated as the 
most restrictive set, and the actual application at the call site 
depends on what is actually passed to you.

DIP 1041 discussed exactly this (at significant length):


It is postponed.... waiting for an answer from our glorious 

Note that any stringify interface is going to face these same 
1042, again, *misidentifies the problem* meaning it cannot fix 
anything, even if its solutions were sound (and they aren't).

Without something like dip 1041 - not necessarily that exact 
text, but something along those lines, since it identifies a 
*real* problem - we're in trouble regardless of if it is on 
Object, Throwable, ProtoObject Stringify, or anything else.

3) Maybe we could do some kind of return of a builder 
interface.... something like returning a stringify range that the 
user must iterate over. If it is turned inside out, it can pass a 
temporary as `front` and then the user is able to copy it out as 

struct StringBuilderRange {
	int delegate (int position, scope char[] buffer) @nogc pure 
nothrow @safe fillBuffer;
	int position;

	@nogc pure nothrow @safe:

	this(typeof(fillBuffer) fb) {
		fillBuffer = fb;

	void popFront() {
		auto got = fillBuffer(position, buffer[]);
		position += got;
		bufferUsed = got;

	char[] front() return {
		return buffer[0 .. bufferUsed];

	bool empty() const {
		return bufferUsed == 0;

	char[16] buffer;
	int bufferUsed;

interface Stringify {
	StringBuilderRange stringify();

class Foo : Stringify {
	StringBuilderRange stringify() @nogc nothrow pure @safe return {
		return StringBuilderRange(&this.fillBuffer);

	int fillBuffer(int position, scope char[] buffer) @nogc nothrow 
pure @safe {
		if(position == 0 && buffer.length >= 5) {
			buffer[0 .. 5] = "hello";
			return 5;

		return 0;

void main() @nogc @safe nothrow pure {
	import std.stdio;
	scope foo = new Foo();
	foreach(item; foo.stringify())
		debug writeln(item); // debug just to allow it past nogc pure 
on main in writeln

But you can see it is a bit of a pain to implement in the class 
and this doesn't actually compile with the dip1000. But I don't 
know how to use that at all so I'm probably just doing it wrong.

Just this kind of turn inside out lets you be very restrictive on 
the inside without necessarily forcing things to be restrictive 
on the outside.

This kind of thing MIGHT work with a bit more fleshing out 
without limiting end users too much. But eeek.

I prefer option #2 here. But that'd dip 1041, not dip 1042.

More information about the Digitalmars-d mailing list