RFC: naming for FrontTransversal and Transversal ranges

Andrei Alexandrescu SeeWebsiteForEmail at erdani.org
Thu Apr 30 17:37:40 PDT 2009


Joel C. Salomon wrote:
> Andrei Alexandrescu wrote:
>> A design that has one container type and several slice types that crawl
>> it in various ways is very compelling, and I think it will be a huge
>> selling point for D. It would be odd, not natural, to have arrays as a
>> singularly distinct container that is in fact its own range. We get away
>> with container == range for arrays partly because arrays are a simple
>> structure, but that only blurs thinking and understanding of more
>> complex containers. In fact, ranges do predict that any attempt to grow
>> a range will cause topological issues in the owning container; that's
>> why SList wisely (IMHO :o)) includes a template parameter that tells
>> whether its topology is fixed or flexible.
> 
> It sounds like you’re suggesting that arrays become like all containers,
> and that slices become a kind of range over the array.

Yes. I think that that would be a good design.

> Functions that now take arrays (which are possibly slices) and write to
> them but don’t shrink or append to them, should therefore be rewritten
> to take the range that covers the array.

To clarify: T[] is a slice. It has one array testis in the form of the 
infamous ~=. And it has the problems that I described because of that 
gender ambiguity.

Most functions manipulate ranges (and therefore slices), not full array 
objects. So the addition of arrays would not be disruptive.

> B.T.W.:  What’s the syntax for a range that accesses the entire
> container in index order?

To get the "default" range for a container c, you write c[]. foreach 
automatically calls it. For a T[], asking a = b[] is an identity 
function. For a T[5], it happens to do the right thing.

Allow me to bring the std.range.SListRange example again, because it's a 
very good example outside of arrays. An approach used e.g. in LISP is to 
conflate lists as containers with lists as iterators in containers. So 
when you pass a list into a function it could not only look and change 
at the elements that the list contains, but it could rewire the nodes in 
the list any way it wants. The root of the list itself is a bit special 
because it is usually passed "by value" so the caller will hold the root 
even if the callee would want to even change that. This is not a huge 
trouble for LISP as lists are the focal data structure, but the behavior 
comes off as a bit odd for someone who'd like to manipulate lists and 
other structures in uniform ways.

So there comes the notion that the container is concerned with topology: 
how slots "sit" in memory, how they are arranged with respect to each 
other etc. The exact ways to manipulate topology and the tradeoffs 
involved are container-specific (for example it's cheap to prepend to a 
list but not an array). Ranges, on the other hand, do not allow 
topological changes - they only have uniform primitives for accessing 
the elements in containers, whereas they prevent any topological changes.

So a SListRange!(int, Topology.flexible) would be a container and offer 
topological changes such as insertAfter. When such a list is asked for a 
range (via c[]) it will return a SListRange!(int, Topology.fixed). That 
guy will know how to move about the host list, but would be unable to 
exact any changes to its topology. As such, SListRange!(int, 
Topology.fixed) is as useable as any other forward range.

Does any of this make sense? :o)


Andrei



More information about the Digitalmars-d mailing list