The demise of T[new]

Denis Koroskin 2korden at gmail.com
Mon Oct 19 04:43:36 PDT 2009


On Mon, 19 Oct 2009 05:16:45 +0400, Andrei Alexandrescu  
<SeeWebsiteForEmail at erdani.org> wrote:

> dsimcha wrote:
>> == Quote from Andrei Alexandrescu (SeeWebsiteForEmail at erdani.org)'s  
>> article
>>>> 3.  A T[new] should be implicitly convertible to a slice.  For  
>>>> example:
>>>>
>>>> auto foo = someFunctionThatReturnsTnew();
>>>> // foo is a T[new].
>>>> T[] bar = someFunctionThatReturnsTnew();
>>>> // Works.  bar is a T[].  The T[new] went into oblivion.
>>>>
>>>> This solves the problem of slices not being closed over .dup and ~.
>>> Check.
>>  So then why is slices not being closed over .dup, ~, etc. still a  
>> problem?  With
>> implicit conversion, they for all practical purposes are.
>
> The problems are with auto and template argument deduction.
>

Could you please bring any example? You talk a lot about corner cases and  
inconsistencies, but didn't bring a single example.

>>  This begs the question:  Why?  Walter's post on the subject was rather  
>> brief and I
>> can't understand for the life of me why you guys would throw away such  
>> an elegant
>> solution.
>
> Here's what I wrote to Walter:
>
> ====================
> I'm going to suggest something terrible - let's get rid of T[new]. I  
> know it's difficult to throw away work you've already done, but really  
> things with T[new] start to look like a Pyrrhic victory. Here are some  
> issues:
>
> * The abstraction doesn't seem to come off as crisp and clean as we both  
> wanted;
>
> * There are efficiency issues, such as the two allocations that you  
> valiantly tried to eliminate in a subset of cases;
>
> * Explaining two very similar but subtly different types to newcomers is  
> excruciatingly difficult (I'll send you a draft of the chapter - it  
> looks like a burn victim who didn't make it);
>
> * Furthermore, explaining people when to use one vs. the other is much  
> more difficult than it seems. On the surface, it goes like this: "If you  
> need to append stuff, use T[new]. If not, use T[]." Reality is much more  
> subtle. For one thing, T[new] does not allow contraction from the left,  
> whereas T[] does. That puts T[] at an advantage. So if you want to  
> append stuff and also contract from the left, there's nothing our  
> abstractions can help you with.
>

An Array!(T) is really just a different name to a T[new]. You'll have the  
same problem explaining difference between Array!(T) and T[].

But you are also creating a nightmare for CTFE. Since you can't use "a ~=  
b;" anymore, you'll have to use "a = a ~ b;" which *always* allocates. Not  
only it is syntactically less pleasant, this way you render this function  
useless at run-time - who in the sane mind will use such an inefficient  
stuff?

> Instead of all T[new] stuff, I suggest the following:
>
> 1. We stay with T[] and we define a struct ArrayBuilder that replaces  
> T[new] with a much more clear name and charter. Phobos already has  
> Appender which works very well. We can beef that up to allow array-like  
> primitives.
>
> 2. Assigning to a slice's .length allocates a new slice if growth is  
> needed.
>
> 3. Disallow ~= for slices. ArrayBuilder will define it.
>
> 4. That's it.
>
> Java got away with a similar approach using StringBuilder:
>
> http://java.sun.com/j2se/1.5.0/docs/api/java/lang/StringBuilder.html
>
> Scala has something very similar called ArrayBuffer:
>
> http://www.nabble.com/ArrayList-and-ArrayBuffer-td15448842.html
>
> And guess what, C# stole Java's StringBuilder as well:
>
> http://msdn.microsoft.com/en-us/library/2839d5h5%28VS.71%29.aspx
>

This is not a fair comparison. StringBuilders only exists because strings  
are immutable and any operation on them create a new object. They are just  
a performance optimization, nothing else. StringBuilder is great, but its  
functionality doesn't really overlap with a general-purpose array.

> So it looks like many programmers coming from other languages will  
> already be familiar with the idea that you use a "builder" to grow an  
> array, and then you use a non-growable array. One thing that Appender  
> has and is really cool is that it can grow an already-existing slice. So  
> you can grow a slice, play with it for a while, and then grow it again  
> at low cost. I don't think the other languages allow that.
>
> I understand how you must feel about having implemented T[new] and all,  
> but really please please try to detach for a minute and think back. Does  
> what we've got now with T[new] make D a much better place? Between the  
> increase of the language, the difficulty to explain the minute  
> subtleties, and the annoying corner cases and oddities, I think it might  
> be good to reconsider.
> ================
>
>> Given that we already agree that a T[new] can be implicitly cast to a
>> T[], the lack of closure under ~, .dup, etc. seems like a non-issue.   
>> When I was a
>> beginner, before I got into templates, a major attraction to D was that  
>> it was a
>> fast, compiled language where basic things like arrays (mostly) just  
>> worked.  To
>> take away all the syntactic sugar for appending and lengthening from  
>> arrays and
>> push this into a separate library type that doesn't feel like a first  
>> class object
>> or (I assume) even support most array semantics would be a massive,  
>> massive kludge
>> no matter how well-implemented that library type was.
>
> I think the language will be in considerably better shape without T[new]  
> than with it. I understand this is a subjective point. You can argue  
> against on virtually every one of my objections.
>
>

It is a shame that D will have built-in associative arrays and no dynamic  
arrays. After all, which one of them do you use more frequently?



More information about the Digitalmars-d mailing list