how to store a range transformed by a range function?

H. S. Teoh via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Thu Jun 19 13:38:56 PDT 2014


On Thu, Jun 19, 2014 at 08:02:39PM +0000, Vlad Levenfeld via Digitalmars-d-learn wrote:
[...]
> For example, lets say I had a couple of managed arrays of doubles, and
> I had some computational path that, at some point, took these two
> ranges and zipped them before passing them along. At that node (where
> the zip is performed) I'd like to save a struct that, upon request,
> returns a Tuple!(double, double) range populated with the current
> values of the source double[]s. Then anything which uses that struct
> is only exposed to a range of ordered pairs, which fell from the sky
> as far as anything on the client-side of the interface is concerned.
> 
> Of course I can't, not right off the bat, because storage requires
> specifying a type to store, and the actual type of a lazy-evaluated
> functional result depends on how it was constructed ("Voldemort types"
> as I've heard them called), so there's no way to, say, keep an array
> of these (unless they all have the same source types and underwent the
> same transformations). So even if I could create such a "midway node"
> struct, I wouldn't have any feasible way to store a set of them.

I've run into this before. The solution is to use a class-based wrapper
from std.range to wrap around the range and expose a uniform external
type:

	// Original version (doesn't compile):
	auto func(R)(R inputRange) {
		if (someCondition)
			return inputRange.map!((x)=>x+1);
		else
			return inputRange.filter!((x) => x > 10);

		// Compile error: map() and filter() don't return the
		// same type, so the return type of func() cannot be
		// determined!
	}

	// Solution:
	import std.range : inputRangeObject;

	InputRange!E func(R,E)(R inputRange)
	{
		if (someCondition)
			return inputRangeObject(inputRange.map!((x)=>x+1));
			// N.B. the object returned by inputRangeObject
			// implements the InputRange!E interface.
		else
			return inputRangeObject(inputRange
				.filter!((x) => x > 10));
			// N.B.: this object also implements the same
			// InputRange!E interface.

		// Since both branches implement the InputRange!E
		// interface, we can use that as the uniform external
		// type to represent either returned range.
	}

This example, of course, illustrates the functional solution to the
problem; in your case, you can just store the InputRange!E interfaces in
your nodes, and you can assign different kinds of ranges to it, as long
as they have a common element type. Exactly which concrete type is
behind the InputRange!E interface reference can be determined at
runtime; it doesn't have to be known at compile-time.


T

-- 
We are in class, we are supposed to be learning, we have a teacher... Is it too much that I expect him to teach me??? -- RL


More information about the Digitalmars-d-learn mailing list