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