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