let's talk about output ranges

Adam D. Ruppe destructionator at gmail.com
Thu Feb 6 08:21:51 PST 2014


splitting from the ARC thread

On Thursday, 6 February 2014 at 15:47:48 UTC, Johannes Pfau wrote:
> As they do not keep references there's no need for ARC or GC,
> we just need a way to tell every function how it should 
> allocate.

yea. I think it is time we hashed out output ranges the same way 
we've done with input ranges. Right now, output ranges just have 
put(T). I think it would be useful to add extensions similarly to 
random access ranges, infinite ranges, etc..


What I want to see work is:
char[3] buffer;
char[] got = toLowerWithRange(buffer, "FOO"); // if we allow it 
w/o slicing
assert(got.ptr is buffer.ptr);
assert(got == "foo");

char[] got = toLowerWithRange(buffer, "FOOL"); // throws, out no 
more space

char[] got = toLowerWithRange(buffer[], "FOO"); // same result as 
above
char[] got = toLowerWithRange(buffer[], "FOOL"); // MAyBE 
reallocates

(I call it toLowerWithRange just to avoid any overloading 
ambiguities when reusing the toLower name. Names aren't important 
to me though.)


What do we have here? When passed a static array, it must not 
grow beyond its length - the only allocation allowed is the 
exception it throws.

When passed a slice though, things are a bit more interesting. I 
think then it should try to put it directly in the slice, but if 
that isn't possible, go ahead and reallocate.

Though that's not necessarily sane either. Maybe slice should 
also throw if there isn't enough room.


toLower would prolly just call put(), with std.array or std.range 
defining it for static vs dynamic arrays.


With user defined types, this behavior would be tweakable, 
similarly to how input ranges might hasLength!T. Other 
similarities:

* A slice should also be a random access output range. Not all 
values are generated in order, one char at a time.

* Allocators should *offer* output ranges, but not necessarily 
*be* output ranges, similarly to the relationship between 
containers and input ranges (a view into the container). This 
could argue that passing a static buffer without slicing it is 
wrong

* We want this stuff to just work without a bajillion explicit 
wrappers, again, like input ranges.

* Output ranges would probably make the most sense to pass places 
by ref (as is the case with them most the time right now).



Eh, I gotta go, but let's start talking about this.

BTW for the growable thing, I wrote this little array thingy:
http://arsdnet.net/dcode/array2.d

it uses a static buffer up to an estimated size, then switches to 
GC. The idea being it can use infinite length, but for the 
majority of the input, uses stack space and thus avoids 
allocating at all. I'd like to see this thing be easy to use with 
phobos functions (perhaps with some additions but the same basic 
idea) as I find this pattern of guessing with a prealloced stack 
buffer very useful.


> Exceptions currently can't work on a system without GC cause we 
> always use 'throw new' and nobody ever explicitly frees 
> Exceptions.

Exceptions only come in exceptional circumstances anyway, so I 
think they are ok to be an... exception. LOL

but seriously, the exception path is rarely fully optimized in 
the first place. If you want to avoid them, use nothrow or 
preallocate them or something.


More information about the Digitalmars-d mailing list