output ranges: by ref or by value?

Michel Fortin michel.fortin at michelf.com
Sun Jan 3 05:17:57 PST 2010


On 2010-01-03 00:51:46 -0500, Andrei Alexandrescu 
<SeeWebsiteForEmail at erdani.org> said:

>> First, opening files silently whenever an algorithm feels the need to 
>> save its state is just madness. What if the operating system decide to 
>> pop a security window when opening a restricted file? What if the file 
>> has been deleted or replaced in its directory while your program is 
>> still hanging on the old inode?
>> 
>> One might want to save the position in a file in order to be able to 
>> return there later, but when you return there the last thing you 
>> actually want to do is to open the file a second time: what you might 
>> realistically want is to set the position to what it was before, 
>> calling fseek. So perhaps it would be more useful to have both save() 
>> to save the current state (the position in a file), and restore() which 
>> would restore the saved state (returning to the saved position in a 
>> file).
> 
> These are implementation matters. save() could lazily save information, 
> duplicate the file handle (cheap on many OSs), etc.




>> For ranges with reference semantics -- please call them streams! -- 
>> save() and restore() would work just as fpos and fseek for files, but 
>> they might also not be available like in a TCP stream or in a 
>> communication channel between threads.
>> 
>> For ranges such as array slices, save and restore would just copy the 
>> range in one or the other direction. The only reason to have them is so 
>> they can be used as streams.
> 
> This I don't understand. Array slices' save is:
> 
> T[] save(T[] array) { return array; }

The idea is that you would use save and restore like this:

	auto state = range.save();
	// ...
	range.restore(state);

For array slices, save doesn't really have to change, just define restore:

	T[] save(T[] array) { return array; }
	void restore(ref T[] array, T[] state) { array = state; }

But with file handles:

	size_t save(FILE handle) { return fpos(handle); }
	void restore(FILE handle, size_t state) { fseek(handle, state); }

And for a range interface to be used in a class hierarchy:

	interface Range {
		Variant save();
		void restore(Variant state);
	}

This way you don't have to create a new range every time you need to 
start from a previously saved state, you can reuse the existing one 
which is much more efficient.

Also, the saved state can be anything, of any type, and doesn't need to 
be a range. So when implementing a non-trivial range you don't need to 
implement lazy initialization logic and all sort of complicated stuff 
just in case someone might save the state.

Note that with save defined like this you can't really duplicate the 
range in the general case. I'm not sure if this is good or bad. How 
many algorithms really require you to duplicate a range?

-- 
Michel Fortin
michel.fortin at michelf.com
http://michelf.com/




More information about the Digitalmars-d mailing list