Immutable separator to join() doesn't work

Jonathan M Davis jmdavisProg at gmx.com
Mon Jul 11 11:15:10 PDT 2011


On 2011-07-11 09:06, Timon Gehr wrote:
> Jonathan M Davis wrote:
> > On Sunday 10 July 2011 21:09:27 Mehrdad wrote:
> >> I noticed that the code below doesn't work, and I was wondering if it's
> >> 
> >> by design (hopefully not):
> >> immutable SEP = ", ";
> >> ["a", "b"].join(SEP);
> >> 
> >> The fact that SEP is immutable(char[]) instead of immutable(char)[]
> >> shouldn't break the function.
> > 
> > It most definitely breaks the function, and it's a limitation of
> > templates. Templates are instantiated with the exact type that they're
> > given, so the compiler tries to instantiate join with immutable(char[]),
> > but join _can't_ work with immutable(char[]), because it needs a mutable
> > range. immutable ranges are worthless. If the compiler were smart enough
> > to realize that it could instantiate join with immutable(char)[] and it
> > would work, then you could use immutable(char[]), but since it isn't
> > that smart, it doesn't work. The same problem happens with static
> > arrays. They can't be used as ranges, so even though they'd work if the
> > compiler picked a dynamic range as the type for the function, they don't
> > work, because the compiler isn't that smart.
> > 
> > The problem may be fixed at some point, but as it stands, it just doesn't
> > work to use immutable arrays with range-based functions.
> > 
> > - Jonathan M Davis
> 
> There is no such thing as an immutable range because the range abstraction
> is based on mutation.
> This does not make sense, because intuitively, immutable(char[]) is a range
> type just as immutable(char)[] or char[] is a range type.
> It is quite odd that a data structure can only be a D range if it may be
> modified...
> 
> It is not really a compiler issue, but one of library design. Maybe adding
> a wrapper range to Phobos to iterate over immutable 'ranges' would be an
> improvement to the current situation.

??? A range is only of any value if you can process it. That generally 
requires calling popFront on it. That mutates it. So, sure, you can an 
immutable range, but it's useless, because you can't process it. And why 
should that be surprising? There are plenty of things that are essentially 
useless if they're immutable. Take a stream for instance. Like a range, it's 
altered as you use. So, you can't have an immutable stream - or if you did, it 
would be useless. Immutability can be very useful, but not being able to 
mutate something can really get in the way of doing anything with it. The same 
goes for const.

There has been some discussion in the past of trying to find a way to convert 
an immutable or const range to a tail-immutable or tail-const range (similar 
to how you can pass immutable(char[]) to a function which takes 
immutable(char)[] and have it work), but the language doesn't currently 
provide any way to do that, and it wouldn't necessarily make sense for all 
range types anyway. It's highly dependent on how their implemented and what 
they're actually iterating over.

It's definitely true that the template situation could use some improvement to 
better deal with immutable arrays, and an improvement to the type system to 
better handle tail-const for ranges where applicable would be desirable, but 
the fact remains that not everything can be fully const or immutable and be 
useful. It's just a fact of how const and immutable work. There's stuff that 
needs to be mutable, and when you make it so that you can't mutate them, 
they're useless.

- Jonathan M Davis


More information about the Digitalmars-d mailing list