Definitely need to add some updates to the docs. Long story:

D provides an iterable interface called a Range. There are two base forms, inputRange and outputRange.

Dynamic Arrays have the privilege of being, a inputRange, outputRange, and a container.

An array however doesn't operate as you might expect, especially when using a function called append on it.

An output range consists of the ability call put for Range and Element (defined in std.range) for a dynamic array this means you can assign to front.

ubyte[] buffer;
buffer.append!ubyte(42);

The append function takes an outputRange, if we drill down the call that would be made (ignoring my value isn't correct)

buffer.front = 42;
buffer.popFront();

Thus when using an array as an outputRange it
1) Must have a size (hence the error: "Attempting to fetch the front of an empty array of ubyte") 2) Starts at the beginning (hence the observation: "instead of appending it behaves like write()")
3) Is consumed (You didn't run into this)

That is why arrays are awkward and the example makes use of appender (a more traditional form of an outputRange)

------------

The write function seems a little odd as it uses random access (indexing).

Instead of assigning to front like append does it assigns at index buffer[0]...

------------

The implementation of append is what you will find more in idiomatic D. In fact if the module was written today write wouldn't exist and append would probably have been named write.

-------------
-------------

"Error: __overloadset isn't a template"

That needs fixed, it usually does a better job of specifying conflicting modules across modules.

------------
------------

"It seems to me as importing std.bitmanip somehow adds new properties"

D provides UFCS (Uniform Function Call Syntax). For a given type A, foo(A a) is callable in both foo(a) and a.foo().

(Historical note: UFCS is recent addition, a bug allowed it to work with dynamic arrays like you see in these docs)

Reply via email to