Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I have recently been learning D and am starting to get some sort of familiarity with the language. I know what it offers, I don't yet know how to use everything, and I don't know much about D idioms and so on, but I am learning.

I like D. It is a nice language, being, in some sort of ways, a huge update to C, and done nicely. None of the features seem that "bolted on", but actually quite well thought-out and well-designed.

You will often hear that D is what C++ should have been (I leave the question whether or not that is true to each and everyone to decide themselves in order to avoid unnecessary flame wars). I have also heard from several C++ programmers that they enjoy D much more than C++.

Myself, while I know C, I can not say that I know C++. I would like to hear from someone knowing both C++ and D if they think there is something that C++ does better than D as a language (meaning not the usual "it has more third-party libraries" or "there are more resources" or "more jobs requiring C++ than D exists").

D was designed by some very skilled C++ programmers (Walter Bright and Andrei Alexandrescu, with the help of the D community) to fix many of the issues that C++ had, but was there something that actually didn't get better after all? Something he missed? Something you think wasn't a better solution?

Also, note that I am talking about D 2.0, not D 1.0.

share
15  
I made sure the D community does see this as I'm sure there are far more C++ devs than D devs around here. That way you'll have more interesting or at least varied answers. –  Klaim Jul 30 '11 at 9:44
7  
Also, D2 was designed by Walter Bright but with Alexandrescu too. You might want to fix that in your question. –  Klaim Jul 30 '11 at 10:44
2  
@Klaim: there was (and still is) a lot of community involvement in D and standard library too. –  Michal Minich Jul 30 '11 at 22:34
28  
@Anto As a language, C++ is a lot better than D in making you, the programmer, hate your life. –  Arlen Jul 30 '11 at 23:47
6  
@jokoon: Actually, yes, with very little work: digitalmars.com/d/2.0/interfaceToC.html –  Anto Jul 31 '11 at 17:31
show 3 more comments

locked by Thomas Owens Mar 18 at 20:24

This question exists because it has historical significance, but it is not considered a good, on-topic question for this site, so please do not use it as evidence that you can ask similar questions here. This question and its answers are frozen and cannot be changed. More info: help center.

8 Answers

up vote 126 down vote accepted

Most of the things C++ "does" better than D are meta things: C++ has better compilers, better tools, more mature libraries, more bindings, more experts, more tutorials etc. Basically it has more and better of all the external things that you would expect from a more mature language. This is inarguable.

As for the language itself, there are a few things that C++ does better than D in my opinion. There's probably more, but here's a few that I can list off the top of my head:

C++ has a better thought out type system
There are quite a few problems with the type system in D at the moment, which appear to be oversights in the design. For example, it is currently impossible to copy a const struct to a non-const struct if the struct contains class object references or pointers due to the transitivity of const and the way postblit constructors work on value types. Andrei says he knows how to solve this, but didn't give any details. The problem is certainly fixable (introducing C++-style copy constructors would be one fix), but it is a major problem in language at present.

Another problem that has bugged me is the lack of logical const (i.e. no mutable like in C++). This is great for writing thread-safe code, but makes it difficult (impossible?) to do lazy intialisation within const objects (think of a const 'get' function which constructs and caches the returned value on first call).

Finally, given these existing problems, I'm worried about how the rest of the type system (pure, shared, etc.) will interact with everything else in the language once they are put to use. The standard library (Phobos) currently makes very little use of D's advanced type system, so I think it is reasonable the question whether it will hold up under stress. I am skeptical, but optimistic.

Note that C++ has some type system warts (e.g. non-transitive const, requiring iterator as well as const_iterator) that make it quite ugly, but while C++'s type system is a little wrong at parts, it doesn't stop you from getting work done like D's sometimes does.

Edit: To clarify, I believe that C++ has a better thought out type system -- not necessarily a better one -- if that makes sense. Essentially, in D I feel that there is a risk involved in using all aspects of its type system that isn't present in C++.

D is sometimes a little too convenient
One criticism that you often hear of C++ is that it hides some low-level issues from you e.g. simple assignments like a = b; could be doing many things like calling conversion operators, calling overload assignment operators etc., which can be difficult to see from the code. Some people like this, some people don't. Either way, in D it is worse (better?) due to things like opDispatch, @property, opApply, lazy which have the potential to change innocent looking code into things that you don't expect.

I don't think this is a big issue personally, but some might find this off-putting.

D requires garbage-collection
This could be seen as controversial because it is possible to run D without the GC. However, just because it is possible doesn't mean it is practical. Without a GC, you lose a lot of D's features, and using the standard library would be like walking in a minefield (who knows which functions allocate memory?). Personally, I think it is totally impractical to use D without a GC, and if you aren't a fan of GCs (like I am) then this can be quite off-putting.

Naive array definitions in D allocate memory
This is a pet peeve of mine:

int[3] a = [1, 2, 3]; // in D, this allocates then copies
int a[3] = {1, 2, 3}; // in C++, this doesn't allocate

Apparently, to avoid the allocation in D, you must do:

static const int[3] staticA = [1, 2, 3]; // in data segment
int[3] a = staticA; // non-allocating copy

These little 'behind your back' allocations are good examples of my previous two points.

Edit: Note that this is a known issue that is being worked on.
Edit: This is now fixed. No allocation takes place.

Conclusion
I've focussed on the negatives of D vs C++ because that's what the question asked, but please don't see this post as a statement that C++ is better than D. I could easily make a larger post of places where D is better than C++. It's up to you to make the decision of which one to use.

share
    
I looked at D a few years ago (before 2.0). Garbage collection wasn't really required then - it was there by default, but you could opt out for low level code. The thing I thought was wrong about this is that I could find no way to opt back in. For example, in a tree based container, the library code can manage memory for the tree nodes itself. The tree as a whole can still be collectable, with IIRC a destructor that collects all those nodes. But objects referenced by the data in that container should be collectible too - there should be a hook to marks all data items in the tree for the GC. –  Steve314 Aug 1 '11 at 13:46
3  
You can still disable the GC for low-level code - Peter is saying that the language presently depends a lot on it. Also, you can tell the GC to scan ranges outside of its managed heap using its API: GC.addRange from core.memory‌​. –  CyberShadow Aug 2 '11 at 0:48
    
+1 for pointing out that the D standard library is garbage collected and that GC-off code is not a seamless interop. It's not something I've thought about it, but it does seem like a major hurdle to overcome. –  masonk Aug 16 '13 at 13:38
add comment

When I joined D development I was in the peculiar position of being one of the people who know most there is to know about C++. Now I'm in the even more peculiar position to also be one of the people who know most there is to know about D. I'm not saying this to appropriate credit or bragging rights as much as to remark I'm in a curiously advantaged position to reply to this question. The same applies to Walter.

By and large, asking what C++ (and by that I mean C++2011) does better than D is as self-contradictory as the question, "If you pay a professional to clean your house, what are the places they'll leave dirtier than before?" Whatever of value was that C++ could do that D couldn't, it has always stood like a sore thumb to me and Walter, so almost by definition there's nothing C++ can ever do that's not within D's reach.

One thing that is seldom understood in language design (because few people have the luck to actually do some) is that there are much fewer unforced errors than it may appear. Many of us language users look at some construct or another and say, "Ew! This is so wrong! What were they thinking?" The fact of the matter is that most awkward instances in a language are aftermath of a few fundamental decisions that are all sound and desirable but are fundamentally competing or contradicting each other (e.g. modularity and efficiency, terseness and control etc).

With all this in mind, I'll enumerate a few things that I can think of, and for each I'll explain how D's choice derives from a desire to fulfill some other, higher-level, charter.

  1. D assumes all objects are movable by bitwise copy. This leaves a minority of designs to C++, specifically those that use internal pointers, i.e. a class containing pointers inside itself. (Any such design can be translated at no or negligible efficiency cost into D, but there would be a translation effort involved.) We made this decision to greatly simplify the language, make object copying more efficient with no or minimal user intervention, and avoid the entire copy construction morass and the rvalue references feature altogether.

  2. D disallows ambiguous-gender types (that can't decide whether they're value or reference types). Such designs are unanimously shunned in C++ and almost always wrong, but some of them are technically correct. We made this choice because it disallows mostly incorrect code and only a tiny fraction correct code that can be redesigned. We believe it is a good tradeoff.

  3. D disallows multi-root hierarchies. A previous poster here got very excited about this particular topic, but this is well-trodden ground and there is no palpable advantage of rootless hierarchies over hierarchies that all have a common root.

  4. In D you can't throw e.g. an int. You must throw an object inheriting Throwable. No contest the state of affairs is better in D, but, well, it's one thing C++ can do that D can't.

  5. In C++ the unit of encapsulation is a class. In D it's a module (i.e. file). Walter made this decision for two reasons: to naturally map encapsulation to file system protection semantics, and to obviate the need for "friend". This choice integrates very well within D's overall modularity design. It would be possible to change things to be more like C++, but that would force things; C++'s encapsulation scope choices are good only for C++'s physical design.

There could be one or two smaller things, but overall this should be it.

share
6  
@DeadMG: For that to work in C++, the object being moved would need a back pointer to the object pointing to it (so that it could update during copy construction). If that's the case, in D you can use the postblit constructor to update the pointer anyway. Please do not argue against D if you only have a passing knowledge of it. –  Peter Alexander Jul 30 '11 at 15:35
13  
@Peter: It should be a reference even though it's lifetime is strictly scope-based? I should waste the overhead of dynamically allocating it and the indirection and cache and collection overheads because I want to alias it? Also, I hope that the collector can collect it deterministically, for equivalent semantics. That is quite clearly not being in control. –  DeadMG Jul 30 '11 at 17:07
3  
@sbi: The existence of a top class does not affect your choices at all. In the class type lattice, there is always a top and a bottom. The bottom is only explicit in a few languages. The top (i.e. Object etc.) is explicit in more languages. These types always exist in concept; when they are also accessible, they simply offer a few extra facilities to the language's user without making trouble. –  Andrei Alexandrescu Jul 31 '11 at 1:15
6  
@quant_dev: you'll be glad to hear there's a GSoC project already in a good shape focused on high performance linear algebra using BLAS. It also provides "naive" implementations of the appropriate primitives for testing and benchmarking purposes. To answer your second question, Java sets the bar quite low for comparing numeric libraries. It will always have the trouble of going over a JNI barrier for accessing high-performance algebra libs, and the syntax will be bad because Java lacks operator overloading. –  Andrei Alexandrescu Aug 1 '11 at 15:00
4  
@PeterAlexander: DeadMG is right on the point. "You shouldn't use pointers to value types" is clearly ignorant of the fact that pointers in any language are generally used with value types (do you really expect to see an Object* as widely used as an int*?) and D seems to be completely ignoring the performance penalty, or claiming it doesn't exist. That's obviously false -- the cache miss is quite noticeable in many cases, so C++ will always have that flexibility advantage over D. –  Mehrdad Dec 3 '11 at 8:32
show 24 more comments

I think that you're going to have a very hard time finding much in D which is objectively worse than C++. Most of the issues with D where you could objectively say it's worse are either quality of implementation issues (which are generally due to how young the language and implementation are and have been being fixed at a breakneck speed of late), or they're issues with a lack of 3rd party libraries (which will come with time). The language itself is generally better than C++, and the cases where C++, as a language, is better are generally either going to be where there's a tradeoff where C++ went one way and D went another, or where someone has subjective reasons for why they think that one is better than another. But the number of outright objective reasons why C++, as a language, is better are likely to be few and far between.

In fact, I have to really wrack my brain to come up with reasons why C++, as a language, is better than D. What generally comes to mind is a matter of tradeoffs.

  1. Because D's const is transitive, and because the language has immutable, it has far stronger guarantees than C++'s const, which means that D does not and cannot have mutable. It cannot have logical const. So, you get a huge gain with D's const system, but in some situations, you just can't use const like you would have in C++.

  2. D has only one cast operator, whereas C++ has 4 (5 if you count the C cast operator). This makes dealing with casts in D easier in the general case, but is problematic when you actually want the extra complications/benefits that const_cast and its brethren provide. But D is actually powerful enough that you could use templates to implement C++'s casts, so if you really want them, you can have them (and they may even end up in D's standard library at some point).

  3. D has far fewer implicit casts than C++ and is far more likely to declare that two functions are in conflict with one another (forcing you to be more specific about which of the functions that you mean - either with casts or by giving the full module path). At times, that can be annoying, but it prevents all kinds of function hijacking issues. You know that you're really calling the function that you mean to.

  4. D's module system is far cleaner than C++'s #includes (not to mention, way faster at compiling), but it lacks any kind of namespacing beyond the modules themselves. So, if you want a namespace within a module, you have to go the Java route and use static functions on a class or struct. It works, but if you really want namespacing, it's obviously not as clean as real namespacing. For most situations, however, the namespacing that the modules themselves provide you is plenty (and quite sophisticated when it comes to stuff like conflicts actually).

  5. Like Java and C#, D has single inheritance rather than multiple inheritance, but unlike Java and C#, it gives you some fantastic ways to get the same effect without all of the problems that C++'s multiple inheritance has (and C++'s multiple inheritance can get very messy at times). Not only does D have interfaces, but it has string mixins, template mixins, and alias this. So, the ultimate result is arguably more powerful and does not have all of the issues that C++'s multiple inheritance does.

  6. Similar to C#, D separates structs and classes. Classes are reference types which have inheritance and are derived from Object, whereas structs are value types without inheritance. This separation can be both good and bad. It gets rid of the classic slicing problem in C++ and it helps separate types which are really value types from those which are supposed to be polymorphic, but at first, at least, the distinction might be annoying to a C++ programmer. Ultimately, there are a number of benefits to it, but it does force you to deal with your types somewhat differently.

  7. Member functions of classes are polymorphic by default. You can't declare them non-virtual. It's up to the compiler to decide if they can be (which really is only the case if they're final and aren't overriding a function from a base class). So, that could be a performance problem in some cases. However, if you really don't need the polymorphism, then all you have to do is use structs, and it's not an issue.

  8. D has a built-in garbage collector. Many from C++ would consider that to be a serious downside, and truth be told, at present, its implementation could use some serious work. It has been improving, but it's definitely not on-par with Java's garbage collector yet. However, this is mitigated by two factors. One, if you're primarily using structs and other data types on the stack, then it's not a big issue. If your program is not constantly allocating and deallocating stuff on the heap, it'll be fine. And two, you can skip the garbage collector if you want to and just use C's malloc and free. There are some language features (such as array slicing) which you'll have to avoid or be careful with, and some of the standard library isn't really usable without at least some use of the GC (particularly string processing), but you can write in D without using the garbage collector if you really want to. The smart thing to do is probably to generally use it and then avoid it where profiling shows that it's causing problems for performance critical code, but you can avoid it completely if you want to. And the quality of the GC's implementation will improve over time, eliminating many of the concerns that using a GC may cause. So, ultimately, the GC won't be as big a problem, and unlike Java, you can avoid it if you want to.

There are probably others as well, but that's what I can come up with at the moment. And if you'll notice, they're all tradeoffs. D chose to do some things differently than C++ that have definite advantages over how C++ does them but also have some disadvantages. Which is better depends on what you're doing, and in many cases will probably only seem worse at first and then you won't have a problem with it once you get used to it. If anything, the problems in D are generally going to be new ones caused by new stuff that other languages haven't done before or haven't done in quite the way that D has. Overall, D has learned very well from C++'s mistakes.

And D, as a language, improves over C++ in so many ways that I think that it's generally the case that D is objectively better.

  1. D has conditional compilation. This is one of the features that I frequently miss when I'm programming in C++. If C++ would add it, then C++ would improve by leaps and bounds when it comes to stuff like templates.

  2. D has compile-time reflection.

  3. Variables are thread-local by default but can be shared if you want them to be. This makes dealing with threads far cleaner than in C++. You're in complete control. You can use immutable and message passing to communicate between threads, or you can make variables shared and do it the C++ way with mutexes and condition variables. Even that is improved over C++ with the introduction of synchronized (similar to C# and Java). So, D's threading situation is far better than C++'s.

  4. D's templates are far more powerful than C++'s templates, allowing you to do far more, far more easily. And with the addition of template constraints, the error messages are way better than they are in C++. D makes templates very powerful and usable. It's no coincidence that the author of Modern C++ Design is one of D's main collaborators. I find C++ templates to be seriously lacking in comparison to D templates, and it can be very frustrating at times when programming in C++.

  5. D has built-in contract programming.

  6. D has a built-in unit test framework.

  7. D has built-in support for unicode with string (UTF-8), wstring (UTF-16), and dstring (UTF-32). It makes it easy to deal with unicode. And if you want to just use string and generally not worry about unicode, you can - though some understanding of the basics of unicode does help with some of the standard library functions.

  8. D's operator overloading is much nicer than C++'s, allowing you to use one function to overload multiple operators at the same time. A prime example of this is when you need to overload the basic arithmetic operators and their implementations are identical save for the operator. String mixins make it a breeze, allowing you to have one, simple function definition for them all.

  9. D's arrays are vastly better than C++'s arrays. Not only are they a proper type with a length, but they can be appended to and resized. Concatenating them is easy. And best of all, they have slicing. And that's a huge boon for efficient array processing. Strings are arrays of characters in D, and it's not a problem (in fact it's great!), because D's arrays are so powerful.

I could go on and on. A lot of the improvements that D provides are little things (like using this for constructor names or disallowing if statements or loop bodies where a semicolon is their entire body), but some of them are pretty large, and when you add it all together, it makes for a much better programming experience. C++ 0x does add some of the features that D has which C++ was missing (e.g. auto and lambdas), but even with all of its improvements, there still isn't going to be much which is objectively better about C++ as a language than D.

There's no question that there are plenty of subjective reasons to like one over the other, and the relative immaturity of D's implementation can be a problem at times (though it has been improving very quickly of late - especially since the repositories were moved to github), and the lack of 3rd party libraries can definitely be a problem (though the fact that D can easily call C functions - and to a lesser extent, C++ functions - definitely mitigates the problem). But those are quality of implementation issues rather than issues with the language itself. And as the quality of implementation issues are fixed, it will become that much more pleasant to use D.

So, I suppose that the short answer to this question is "very little." D, as a language, is generally superior to C++.

share
8  
HEAVIEST thanks for giving links to the site! –  vines Jul 30 '11 at 23:41
2  
Garbage collection languages use 2-5x more memory than non GC langs(according to Alexandrescu's talk on YT) so that is definitely a problem if that(mem usage) is the bottleneck. –  NoSenseEtAl Aug 19 '11 at 9:10
add comment

RAII and stack memory usage

D 2.0 doesn't allow RAII to happen on the stack because it removed the value of the scope keyword in allocating class instances on the stack.

You can't do value-type inheritance in D, so effectively that forces you to do a heap allocation for any form of RAII.
That is, unless you use emplace, but that's very painful to use, since you have to allocate the memory by hand. (I have yet to find it practical to use emplace in D.)

share
add comment

C++ is much better at forcing you to be verbose. This might be better or worse in your eyes, depending on whether you like inference or verbosity.

Compare run-time memoization in C++:

template <typename ReturnType, typename... Args>
function<ReturnType (Args...)> memoize(function<ReturnType (Args...)> func)
{
    map<tuple<Args...>, ReturnType> cache;
    return ([=](Args... args) mutable {
            tuple<Args...> t(args...);
            return cache.find(t) == cache.end()
                ? cache[t] : cache[t] = func(args...);
    });
}

with the same thing in D:

auto memoize(F)(F func)
{
    alias ParameterTypeTuple!F Args;
    ReturnType!F[Tuple!Args] cache;
    return (Args args)
    {
        auto key = tuple(args);
        return key in cache ? cache[key] : (cache[key] = func(args));
    };
}

Notice, for example, the extra verbosity with template <typename ReturnType, typename... Args> versus (F), Args... versus Args, args... versus args, etc.
For better or worse, C++ is more verbose.

Of course, you could also do this in D:

template memoize(Return, Args...)
{
    Return delegate(Args) memoize(Return delegate(Args) func)
    {
        Return[Tuple!Args] cache;
        return delegate(Args args)
        {
            auto key = tuple(args);
            return key in cache ? cache[key] : (cache[key] = func(args));
        };
    }
}

and they would look almost identical, but then this would require a delegate, whereas the original accepted any callable object. (The C++0x version requires a std::function object, so either way, it's more verbose and restrictive in its inputs... which could be good if you like verbosity, bad if you don't.)

share
add comment

I don't know much about D, but many, many C++ programmers I know greatly dislike it, and I personally have to agree- I don't like the look of D and will not be taking a closer one.

In order to understand why D isn't gaining more traction, you need to start by understanding what attracts people to C++. In a word, the number one reason is control. When you program in C++, then you have complete control over your program. Want to replace the Standard library? You can. Want to do unsafe pointer casts? You can. Want to violate const-correctness? You can. Want to replace the memory allocator? You can. Want to copy around raw memory without regard for it's type? If you really want to. Want to inherit from multiple implementations? It's your funeral. Hell, you can even get garbage collection libraries, like the Boehm collector. Then you have issues like performance, which closely follows control- the more control a programmer has, the more optimized he can make his program. Performance is one of the major reasons to continue using C++.

Here's a few things that I've seen when doing a little research and speaking to a couple of people who have tried it:

Unified type hierarchy. C++ users use inheritance very rarely, most C++ programmers prefer composition, and types should only be linked through inheritance if there is a very good reason for doing so. The concept of Object violates this principle strongly by linking every type. In addition, it's violating one of C++'s most basic principles- you only use what you want. Not being given a choice about inheriting from Object, and the costs that go along with it, are very strongly against what C++ stands for as a language in terms of giving the programmer control over his program.

I've heard about problems with functions and delegates. Apparently, D has both functions and delegates as run-time callable function types, and they're not the same but they are interchangable or... something? My friend had quite a few problems with them. This is definitely a downgrade from C++, which just has std::function and you're done.

Then you've got compatibility. D is not particularly compatible with C++. I mean, no language is compatible with C++, let's face it, except C++/CLI which is kind of cheating, but as a barrier to entry, it's got to be mentioned.

Then, there are some other things. For example, just read the Wikipedia entry.

import std.metastrings;
pragma(msg, Format!("7! = %s", fact_7));
pragma(msg, Format!("9! = %s", fact_9));

printf is one of the most un-safe functions ever devised, in the same family as big problems like gets from the old C Standard library. If you search for it on Stack Overflow, you will find many, many questions relating to it's mis-use. Fundamentally, printf is a violation of DRY - you're giving the type in the format string, and then giving it again when you give it an argument. A violation of DRY where if you get it wrong, then very bad things happen- say, if you changed a typedef from a 16-bit integer to a 32-bit one. It's also not extendable at all- imagine what would happen if everyone invented their own format specifiers. C++'s iostreams may be slow, and their choice of operator may not be the greatest, and their interface could use work, but they are fundamentally guaranteed to be safe, and DRY is not violated, and they can be readily extended. This is not something that can be said of printf.

No multiple inheritance. That's very not the C++ way. C++ programmers expect to have complete control over their program and the language enforcing what you cannot inherit from is a violation of that principle. In addition, it makes inheritance (even more) fragile, because if you change a type from an interface to a class because you want to provide a default implementation or something, suddenly all your user's code is broken. That's not a good thing.

Another example is string and wstring. In C++ it's already quite painful to have to convert between them, and does this library support Unicode, and this old C library only uses const char*, and having to write different versions of the same function depending on the string argument type you want. Notably, the Windows headers, for example, have some extremely irritating macros to cope with the problem that can often interfere with your own code. Adding dstring to the mix is only going to make things worse, as now instead of two string types, you have to manage three. Having more than one string type is going to increase maintenance pains and introduce repetitive code dealing with strings.

Scott Meyers writes:

D is a programming language built to help programmers address the challenges of modern software development. It does so by fostering modules interconnected through precise interfaces, a federation of tightly integrated programming paradigms, language-enforced thread isolation, modular type safety, an efficient memory model, and more.

Language-enforced thread isolation is not a plus. C++ programmers expect full control over their programs, and the language forcing something is definitely not what the doctor ordered.

I'm also going to mention compile-time string manipulation. D has the ability to interpret D code at compile-time. This is not a plus. Consider the massive headaches caused by C's relatively limited preprocessor, well-known by all veteran C++ programmers, and then imagine how badly this feature is going to be abused. The ability to create D code at compile-time is great, but it should be semantic, not syntactic.

In addition, you can expect a certain reflex. D has garbage collection, which C++ programmers will associate with languages like Java and C# which are fairly directly opposed to it in philosophies, and the syntactic similarities will bring them to mind too. This isn't necessarily objectively justifiable, but it's something that certainly should be noted.

Fundamentally, it doesn't offer that much that C++ programmers can't already do. Maybe it's easier to write a factorial metaprogram in D, but we can already write factorial metaprograms in C++. Maybe in D you can write a compile-time ray-tracer, but nobody really wants to do that anyway. Compared to the fundamental violations of C++ philosophy, what you can do in D is not particularly notable.

Even if these things are only problems on the surface, then I'm pretty sure that the fact that on the surface, D doesn't actually look like C++ at all is probably a good reason that many C++ programmers are not migrating to D. Perhaps D needs to do a better job advertising itself.

share
9  
@DeadMG: It's 100% incorrect and missing the point to say This is definitely a downgrade from C++, which just has std::function and you're done. Why? Because you also, for example, have function pointers. It's exactly the same thing in D: D's "functions" are function pointers, and D's "delegates" are the same as C++'s std::function (except that they're built-in). There's no "downgrade" anywhere whatsoever -- and there's a 1:1 correspondence between them, so it shouldn't at all be confusing if you're familiar with C++. –  Mehrdad Aug 1 '11 at 12:43
10  
@Mark Trapp: I must admit that I don't quite understand your stance on the topic – comments are not to be used for, you know, commenting on an answer? –  klickverbot Aug 1 '11 at 13:26
6  
@Mark Trapp: My point is that most of the comments here were not obsolete (the meta discussion you linked specifically applies to suggestions which have already been incorporated into the original post), but pointed out factual inaccuracies in the post, which are still present. –  klickverbot Aug 1 '11 at 19:26
7  
A note on format: D's format function is typesafe (solves the safety/overflow issues) and does not violate DRY as the format string only specifies how the arguments should be formatted, not their types. This is possible thanks to D's typesafe variadics. Therefore, that objection at least is completely invalid. –  Justin W Aug 1 '11 at 22:05
17  
@Mark: Whatever is the current policy regarding them, I find it stupid and hindering that comment discussions are deleted. I think this answer had extensive discussions (which I'm now interested in), but I'm not sure, and I have no way to find out. That room you linked to has well over 10k messages, and I have no chance at all to find a discussion I seem to remember having taken place, but can't remember the content of. Discussions regarding this answer belong here, to this answer, and not to some chat room, where they might be mingled in discussions of sex, drugs, and rock'n'roll. –  sbi Aug 25 '11 at 13:00
show 7 more comments

One thing I appreciate in C++ is the ability to document a function argument or return value as a C++ reference instead of a pointer, hence implying taking a non-null value.

D version:

class A { int i; }

int foo(A a) {
    return a.i; // Will crash if a is null
}

int main() {
    A bar = null;
    // Do something, forgetting to set bar in all
    // branches until finally ending up at:
    return foo(bar);
}

C++ version:

class A { int i; };

int foo(A& a) {
    return a.i; // Will probably not crash since
                // C++ references are less likely
                // to be null.
}

int main() {
    A* bar = null;
    // Do something, forgetting to set bar in all
    // branches until finally ending up at:
    // Hm.. I have to dereference the bar-pointer
    // here, otherwise it wont compile.  Lets add
    // a check for null before.
    if (bar)
        return foo(*bar);
    return 0;
}

To be fair you can get very close to C++ by making A into a D struct and marking the foo()-argument as a ref (classes are reference types and structs are value types in D, similar to C#).

I believe there is a plan to create a NonNullable template for classes as a D standard library construct instead. Even so I like the brevity of just Type& compared to NonNullable(Type), and would prefer non-nullable as the default (rendering something like Type and Nullable(Type)). But it's too late to change that for D and I'm drifting off-topic now.

share
3  
Both function arguments and return values in D can be marked with ref to give you the same effect as C++'s &. The one major difference is that ref won't take a temporary even if it's const. –  Jonathan M Davis Aug 1 '11 at 1:29
    
I like the way returning references to local variables is prohibited in D, I was not aware of that until I read your comment. But you can still return a non-local null reference without thinking about it in a way where the C dereference operator will make you think. –  lumor Aug 2 '11 at 20:57
    
You're confusing things. Classes are always references, and that's separate from ref. References in D are like references in Java. They're managed pointers. Passing or returning by ref is like passing or returning with & in C++. Passing a class reference by ref is like passing a pointer in C++ with & (e.g. A*&). Classes don't go on the stack. Yes, NonNullable would make it possible to have a class reference which was guaranteed to be non-null, but that's completely separate from ref. What you're trying to do in the C++ code doesn't work in D because classes don't go on the stack. Structs do. –  Jonathan M Davis Aug 2 '11 at 22:51
1  
So yes, being able to have a class reference which is non-nullabe would be nice, but C++ manages to do what you're showing because it allows for classes to be on the stack and allows for pointers to be dereferenced. And while you can dereference pointers in D, classes are references, not pointers, so you can't dereference them. Since you can't put them on the stack, and you can't dereference them, there is no way built into D to have a class which can't be null. It is a loss, but NonNullable will fix it, and the gains from the separation of structs and classes are generally greater anyway. –  Jonathan M Davis Aug 2 '11 at 23:13
2  
C++ references cannot be null by the language standard (saying "probably will not be null" is incorrect since it can't be null). I do wish there was a way to disallow null as a valid value for a class. –  jsternberg Aug 3 '11 at 22:01
show 3 more comments

The most important thing that C++ "does better" than D is interfacing with legacy libraries. Various 3D engines, OpenCL and alike. As D is new, it has far smaller amount of different libraries to choose from.

Another important difference between the C++ and the D is that the C++ has multiple financially independent vendors, but as of 2014 the D has practically only one, the 2-man team that created it. It's interesting that the "second source principle" that says that projects should never depend on technology, components, that have only one, single, vendor, seems to hold even for software.

For comparison, the first version of the Ruby interpreter was written by the inventor of Ruby, the Yukihiro Matsumoto, but the 2014 era mainstream Ruby interpreter has been written practically from scratch by other people. Therefore, Ruby can be seen as a language that has more than one financially independent vendor. D, on the other hand, can be an awesome technology, but it depends on the few developers that develop it.

The history of Java shows that even if a technology, in this case, Java, has a fine, but single, financier, there is a great risk that the technology is essentially dumped, regardless of the huge corporate user base. A citation of the Apache Software Foundation, where the EC stands for "Executive Committee":

Oracle provided the EC with a Java SE 7 specification request and license that are self-contradictory, severely restrict distribution of independent implementations of the spec, and most importantly, prohibit the distribution of independent open source implementations of the spec.

As a historical note, it can be said that Java applets had hardware accelerated 3D canvas years before the HTML5 WebGL got developed. The Java applets start-up speed issue could have been solved, if the Java had been a community project, but the executives of the sole financier of the Java, the Sun Microsystems, did not find it important enough to have the Java implementation fixed. The end result: HTML5 canvas by multiple vendors as a "poor man's replica" of the Java GUI frameworks (Swing, etc.). Interestingly enough, on the server side the Python programming language has the same advantages that the Java promised: write once, run on every server, regardless of hardware, provided that the Python application is not compiled to machine code. The Python is about as old/young as the Java is, but unlike the Java, it's backed up by more than one independently financed team of developers (the PyPy and the main stream Python interpreter).

Summary:

When evaluating technology for production use, the most important properties of technologies are the people, who develop it, the social process, where the development takes place, and the number of financially independent development teams.

Whether it's more advantageous to use technology T1 over technology T2 depends on the vendors of the technologies and whether technology T1 allows to solve project related problems more cheaply than T2. For example, if the single supplier issue were ignored, then for information systems the Java would be a "better" technology than the C++, because Java binaries do not need recompilation at deployment to new hardware and the amount of memory management related software development work is smaller for the Java than it is for the C++. Projects that are developed from scratch, e.g. projects that do not depend on other libraries, might be cheaper to develop in D than C++, but, on the other hand, the C++ has more than one vendor and therefore is less risky in the long run. (The Java example, where the Sun Microsystems was almost OK, but the Oracle practically made Java the "new COBOL".)

A Possible Workaround to some of the C++ Limitations

One of the possible workarounds to some of the limitations of the C++ is to use a design pattern, where the initial task is taken to pieces and the pieces are "sorted" (classified, clustered, divided, other-nice-words-for-the-same-thing) to 2 classes: control logic related tasks, where memory access patterns do not allow locality; signal processing-like tasks, where locality is easily achieved. The signal processing "like" tasks can be implemented as a set of relatively simplistic console programs. The control logic related tasks are placed all to a single script that is written in Ruby or Python or otherwise something, where software development comfort has higher priority than speed.

To avoid expensive operating system process initialization and data copying between operating system processes, the set of small C++ console applications might be implemented as a single C++ program that is booted as a "servlet" by the Ruby/Python/etc. script. The Ruby/Python/etc. script shuts the servlet down before exit. Communication between the "servlet" and the Ruby/Python/etc. script takes place over a Linux named pipe or some similar mechanism.

If the initial task does not lend itself to be easily divided to pieces that can be classified to the 2 aforementioned classes, then a thing to try might be to re-phrase the problem so that the initial task changes.

share
add comment

protected by gnat Mar 18 at 19:32

Thank you for your interest in this question. Because it has attracted low-quality answers, posting an answer now requires 10 reputation on this site.

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.