Is mimicking a reference type with a struct reliable?

Denis Koroskin 2korden at gmail.com
Sat Oct 16 08:52:29 PDT 2010


irst I'd like to say that I don't really like (or rather use) Appender  
because it always allocates (at least an internal Data instance) even when  
I provide my own buffer.
I mean, why would I use Appender if it still allocates? Okay, you have to  
store a reference to an internal representation so that Appender would  
feel like a reference type. I'm not sure it's worth the trade-off, and as  
such I defined and use my own set of primitives that don't allocate when a  
buffer is provided:

void put(T)(ref T[] array, ref size_t offset, const(T) value)
{
     ensureCapacity(array, offset + 1);
     array[offset++] = value;
}

void put(T)(ref T[] array, ref size_t offset, const(T)[] value)
{
     // Same but for an array
}

void ensureCapacity(ref char[] array, size_t minCapacity)
{
    // ...
}

And all that functions that use an optional buffer have a signature like  
this:

void foo(ubyte[] buffer = null);

Back to my original question, can we mimick a reference behavior with a  
struct? I thought why not until I hit this bug:

import std.array;
import std.stdio;

void append(Appender!(string) a, string s)
{
	a.put(s);
}

void main()
{
	Appender!(string) a;
	string s = "test";
	
	append(a, s); // <
	
	writeln(a.data);	
}

I'm passing an appender by value since it's supposed to have a reference  
type behavior and passing 4 bytes by reference is an overkill.

However, the code above doesn't work for a simple reason: structs lack  
default ctors. As such, an appender is initialized to null internally,  
when I call append a copy of it gets initialized (lazily), but the  
original one remains unchanged. Note that if you append to appender at  
least once before passing by value, it will work. But that's sad. Not only  
it allocates when it shouldn't, I also have to initialize it explicitly!

I think far better solution would be to make it non-copyable.

TL;DR Reference semantic mimicking with a struct without default ctors is  
unreliable since you must initialize your object lazily. Moreover, you  
have to check that you struct is not initialized yet every single function  
call, and that's error prone and bad for code clarity and performance. I'm  
opposed of that practice.


More information about the Digitalmars-d mailing list