Does D have too many features?

Jonathan M Davis jmdavisProg at gmx.com
Sat Apr 28 16:56:52 PDT 2012


On Saturday, April 28, 2012 11:47:31 Walter Bright wrote:
> Andrei and I had a fun discussion last night about this question. The idea
> was which features in D are redundant and/or do not add significant value?
> 
> A couple already agreed upon ones are typedef and the cfloat, cdouble and
> creal types.
> 
> What's your list?

Well, that's a hard one. There isn't much in the language that I'd remove even 
if we were doing a complete redesign without caring about backwards 
compatibility. Most of the stuff that I'd change is already being (or has been) 
changed. And while D isn't exactly big, it doesn't tend to have dark corners 
like C++ does. I'm sure that I don't fully grasp everything in D, but it's 
fairly rare that I run into something that surprises me or that I thought that 
I understood but don't (though it still does happen sometimes). With C++, it 
always feels like there's some new detail that pops up that I didn't have a 
clue about - or that maybe I _did_ know about but had forgotten because of the 
insane number of little details that C++ has.

One _big_ difference between D and C++ as far as complexity goes is that in 
C++, a _lot_ of the complexity comes from weird things in the language and 
knowing about how certain things can go horribly wrong (e.g. I can never 
remember all of the details on how horribly broken multiple inheritence is). 
It's frequently not an issue of knowing how to do things in the language but 
rather an issue of knowing what weird side effects an problems happen with 
certain stuff. With D, on the other hand, the complexity tends to be in just 
knowing what all of the features are and what they can do.

The only feature that comes to mind as probably being overly complex is is 
expressions, but that complexity can really come in handy sometimes. 
std.traits should probably do more to alleviate the need for is expressions 
though so that odds of needing some of the more complicated stuff are lessened.

* As for redundant features, the first one that really comes to mind is WYSIWYG 
string literals. There are what, 4 different types of delimiters for string 
literals? I don't even remember all of the options. I just always use ` if I 
don't want any escaping in string literal and " if I do. The others may be 
valuable enough to have in some contexts, but I _never_ use them.

* version vs static if seems kind of redundant, but it isn't really. version 
is used for a very specific subset of conditional code compilation, and you can 
define versions on the command line, whereas static if generally checks code 
properties (like if a type meets certain conditions). So, I think that they 
should probably be left as is. There would be some value in allowing a list of 
versions to be given (rather than using logical operators) in order to avoid 
duplicate code - e.g.

version(linux, FreeBSD)
{}
else version(MacOSX)
{}
else version(Windows)
{}
else
    static assert(0);

but that's about the only thing that I'd change with version. And I wouldn't 
want to get rid of it.

* foreach_reverse is essentially redudant at this point (not to mention 
confusing if combined with delegates), since we have retro. But we might 
already be planning to get rid of that. I'm not sure though.

* I hate C style struct initializers and would really like to see them go, but 
for reasons that I don't understand, people actually use them rather than 
using a proper constructor call, so I doubt that we could get rid of them 
without a fair bit of complaining. I think that they're completely redundant 
and very _un_D.

* There seem to be too many ways to do variadic functions. We have to allow C 
style variadics for extern(C), but having 3 of our own seems like a bit much. 
Variadic templates are generally all that we need. The others don't seem 
necessary for the most part. But unfortunately, they should probably be left 
in so that classes can use them with virtual functions, since they can't use 
templates.


* As for features that add little value, the first one that comes to mind is 
with. I think that I've used it all of once, and I don't think that I've seen 
it in other people's code very often. It's hard to grep for (since with is 
used in comments quite often), but it wouldn't surprise me at all if Phobos 
doesn't use it at all. Also, I fear that not only does it add little value but 
that it has a tendency to make code less readable.

* Increasingly, I don't like UFCS. I think that in most cases, it complicates 
code for little value. And I _really_ don't like how it results in people 
flipping chains of a(b(c(d(5)))) calls into something like d(5).c().b.().a(). I 
think that it makes the code way harder to read. The code is completely 
backwards. But I appear to be in the minority with that opinion. I also don't 
like how it creates so many ways to write exactly the same code. It harms 
readibility. But as much as I dislike many of the applications of UFCS, it 
_does_ appear to be quite popular. And upon occasion, it may be useful, but I 
_am_ wishing that we hadn't added it.

There are definitely features that I never use (e.g. opDispatch), but for the 
most part, I think that they're stuff that adds real value for certain types of 
stuff that I just don't do, so removing them wouldn't really make any sense.

Overall, I think that D's feature set is fairly solid. It's mostly just the 
implementation of said features which is a problem - though some minor tweaks 
are probably in order (e.g. as Bearophile suggests, make it so that adjacent 
string literals don't concatenate).

- Jonathan M Davis


More information about the Digitalmars-d mailing list