The D Programming Language, Version 1.0 570
penguinblotter writes in a journal article: "Soon, Walter Bright is scheduled to release version 1.0 of the D Programming Language. D is a systems programming language. Its focus is on combining the power and high performance of C and C++ with the programmer productivity of modern languages like Ruby and Python. Special attention is given to the needs of quality assurance, documentation, management, portability and reliability. D has appeared on Slashdot a few times before, and Walter has continued to add more and more features. Most Slashdot community comments in these articles have been offered on feature X or spec Y without reading through the extensive D newsgroup archives. It has been here over the past seven years where extremely gifted and experienced programmers hashed out discussions and arrived at excellent implementations of all the ideas discussed." Read on for the rest of penguinblotter's writeup.
For those with a C/C++ background, D offers:
- native code speed
- extremely fast compilation times
- garbage collection (although you can manage your own memory if you want)
- OOP - by reference only, easy initialization, always virtual
- cleaner template metaprogramming syntax, more powerful templates, as well
- built-in dynamic and associative arrays, array slicing
- versioning (no preprocessor madness)
- link-compatibility with C
- nested functions
- class delegates / function pointers
- module system
- similar syntax
- No virtual machine or interpreter
- built-in unit testing and design-by-contract
From D's creator:
For me, it's hard to pinpoint any particular feature or two. It's the combination of features that makes the cake, not the sugar, flour or baking powder. So,
- My programs come together faster and have fewer bugs.
- Once written, the programs are easier to modify.
- I can do (1) and (2) without giving up performance.
Re:Weird writeup: (Score:1, Interesting)
Point.
Python and D (Score:4, Interesting)
One area I see D being useful in is integration with Python. Writing to the raw Python/C API is cumbersome. (Managing reference counts is tedious.) Boost.Python is difficult to build and slow to compile. I've written a library for D called Pyd [dsource.org], whose purpose is not entirely unlike Boost.Python's.
Pyd is easy to use. It provides its own extension to Python's distutils. Usually, you just need to make sure the D compiler is on your PATH, write a setup.py file, and run python setup.py build.
"Hello world" in Pyd looks something like this (and I apologize for the lack of indentation):
Re:GC, No Vm or performance hit (Score:3, Interesting)
Re:Do we really need another D infomercial? (Score:3, Interesting)
Ironically, I consider most of the C++ to D examples there to be flaws in D.
Supplying predefined comparison operators is all very well, but what if a class doesn't support the concept of equality? Alternatively, suppose it supports only equality and not ordering, or vice versa? How do I do that in a natural way, with a single comparison function to define?
The whole concept of relying on scoped variables completely misses a major advantage of RAII, which is that in the common usage, you can't forget anything (a delete, finally or in this case scope) and inadvertently skip the destructor. Requiring some special keywords to get this behaviour is just horrible.
The construction/initialisation semantics just seem a mess. You've either introduced some hideous inefficiency and semantic problems (everything is default-initialised and then reassigned afterwards in the constructor if necessary) or you've introduced a horrible loophole (constructors can start messing around with uninitialised data, for example by calling another member function, before the class invariants are properly set up). The latter is even worse than the analogous loophole in C++.
This sort of thing is exactly my big beef with D, and the reason I doubt I will ever seriously consider it for a non-trivial project in its current form. It's going for style over substance, PR hype over effectiveness. It does away with a few controversial things in C++, but some of its underlying models are simply broken, and as I illustrated elsewhere, its improvements in other areas are far from state-of-the-art.
Re:This won't work... (Score:4, Interesting)
Re:Do we really need another D infomercial? (Score:3, Interesting)
Not really. Take a look at the performance, addressing modes, and so on. The support for 80-bit on Intel boxes is not the same as the support for 64-bit, at least in practical terms.
Also, while the vast majority of the world's FP hardware may indeed run on x86 (I don't know), I would suggest that at least a very significant minority of the software that actually requires high-precision floating point work still runs on workstations which may well be based on other architectures.
No-one wishes this were not so more than me, I promise you: I write high-performance, high-precision mathematical libraries for a living, and minor differences in behaviour across platforms or where precision has been lost are the bane of my working life.
Re:Because the ones we have suck? (Score:3, Interesting)
Are you really well acquainted with gcj? I'm sorry, but I don't get how the end result or even the stuff going into it (and the required inputs, like making some explicit calls that would never be required in Java) can be called Java anymore.
the point I didn't make well was that when a language has been designed to execute inside a containing environment (the JRE or whatever facsimile thereof) you can't just up and erase that... without emulating all the stuff that was supposed to be alive in that environment. Taking a look at the gcj's to-do list and all the stuff that isn't yet supported should be enough to show you not only that this is not a trivial task, but to suggest that perhaps it's not a useful task, and I say that knowing that people have worked very hard on the project.
Maybe it makes sense for some resource-constrained settings like embedded systems, but there i've used Java straight up, satisfactorily. Granted, these are not life-critical systems I've built, but rather than compiling Java - or trying to - the better answer is to use a more appropriate language in those circumstances.
Re:Weird writeup: (Score:3, Interesting)
Re:Do we really need another D infomercial? (Score:2, Interesting)
VC++ doesn't. Java doesn't. C# doesn't. Python doesn't. Ruby doesn't. 80 bit floating point is highly useful, and it's about time it was required for languages on FPUs that support it.
Re:This won't work... (Score:1, Interesting)
Re:GC, No Vm or performance hit (Score:3, Interesting)
Comparison to Objective-C? (Score:5, Interesting)
I noticed that a comparison to Objective-C is quite conspicuously absent from the list of languages compared to D. Why is it missing? Granted D seems to be a much greater change to C than Objective-C is but I can't help but thinking that one of the main attractions to D seems to be its heap-based garbage-collected object system. You can already get the object runtime with Objective-C. If you use GNU you can even have Boehm GC (which is apparently the GC that D uses). If you use Apple you will have to wait for Leopard to get GC. Another new Objective-C feature is the ability to use full C++ objects as instance variables in your Objective-C classes and do the right thing with initializing (calling the default no-argument constructor upon alloc).
On top of that, Objective-C actually includes tons of reflection information. Although Objective-C has protocols which are roughly equivalent to Java/C# interfaces they are almost completely unnecessary. In Objective-C one can query at runtime whether a method is implemented or not and if so call it. So whereas in Java you'd do this:
in Objective-C you can do this:
The difference being that in the Java case you have to declare MyInterface as containing the one doSomething() method and inform java that your object extends MyInterface whereas in Objective-C you merely need to provide a doSomething method on your object.
Basically that means that in Objective-C every single method effectively becomes an interface. You would not believe how useful this is once you realize it. Note that at runtime there is ZERO difference. In both the Java and Objective-C cases the object is being checked to see if it implements something. Same with C++ if you use dynamic_cast<>()
Granted every language has its niche and I'm sure D will find its. Objective-C's niche is definitely GUI programming. The ample reflection information allows for easy implementations of archiving (serialization) and most importantly key-value coding and the related action methods pattern. It's a pretty damn cool thing when your RAD tool simply outputs archived objects that refer to methods to be called upon certain actions simply by name.
OOP languages are slow (Score:3, Interesting)
CPUs put a lot of stock in branch prediction; due to the nature of OOP languages like C++, Objective-C (I like this one), and D, this doesn't work. The way virtuals and class inheritence works, functions are necessarily dealt with as pointers; the function is pointed to by pointing to a master class object, basically. Here's a C reconstruction:
struct myClass_members { // constructor // destructor // member function
// Data // Pointer to a list of members as above // an integer value
struct myClass_members *(*alloc)();
void (*destroy)(struct myClass *);
int (*my_member)();
};
struct myClass {
struct myClass_members *call;
int my_value;
};
What you do is initialize a constant myClass_members (called myClass_Object here) with a bunch of pointers to static functions in one source file; then call myClass_Object->alloc to create a new one (we'll call it my_inst). Then do my_inst->call->my_member() to call the member, and similarly my_inst->call->destroy(my_inst) to deallocate the class.
Basically, OOP languages like C++ and Java use this methodology, but it's obscured through friendly syntax. What we can expose from the above is:
The whole "native execution speed" thing is bunk. Script languages are executed on a native bytecode interpreter, or JIT'd to native. The amount of work that goes into the execution is what you care about; as well as the utilization of the CPU's most powerful facilities. You can only justify OOP languages by saying that either A) the majority of the work doesn't involve making calls to other class members, and thus won't be hurt by this; or B) CPU speed doesn't matter. I hate argument (B); (A) I can accept, barely enough to tip my hat to you for having good software engineering sense.
Re:I have a problem with GC in a systems language. (Score:4, Interesting)
I wasn't happy about that either. Garbage collection in a language with destructors leads to wierd semantics, which is why Microsoft's "Managed C++" is a nightmare. I corresponded a bit with Walter Bright in the early days of D, but didn't press the issue.
What seems to work in practice is reference counting. GC gets most of the academic attention, but Perl and Python are both basically reference counted, and the result seems to be that programmers in those languages can ignore memory allocation. Java programmers have to pay a bit more attention, worrying about when GC will run and when finalizers will be called. Reference counting is deterministic; the same thing will happen every time, so timing is repeatable. That's not true of GC.
There are two basic problems with reference counts - overhead and cycles. Overhead can be dealt with by hoisting reference count updates out of loops at compile time, so that you're not frantically updating reference counts within an inner loop. Hoisting (along with common subexpression elimination), by the way, is also the answer to subscript checking overhead.
Cycles are a more serious problem. Conceptually, the answer is strong and weak pointers (in the Perl sense, not the Java sense), which allows the programmer to express things like trees. (Links towards the leaves should be strong pointers; back pointers towards the head should be weak pointers.)
In practice, cycles aren't a serious problem, because they're generated by design errors and tend to happen in normal program operation, so they show up early in testing as memory leaks. Dangling pointers, on the other hand, tend to show up in error cases, which is why they survive testing to become delivered bugs.
Ideally, you'd like to detect cycles at the moment they're created, at least for debug purposes. This is quite possible, although there's substantial overhead.
Attempts to retrofit reference counting to C++ via templates have been made, but they are never airtight. To get anything done, raw pointers have to leak out, which makes the reference counting scheme very brittle.
Re:The feature-checklist school of software design (Score:3, Interesting)
Perhaps accidentally, you've just hit on one feature of programming language designs that I think does justify a new compiler front-end: ease of parsing for use with tools. Parsing the current monsters like C++ and Perl is so awkward and error-prone that few tools even get simple things like syntax highlighting 100% right (and the performance of those that do is... less than stellar). I imagine most of us are more interested in the underlying semantics of programming languages than in the specific syntax anyway, so can't we use a grammar that is easy to parse effectively, and then have tools from syntax highlighters to source code navigation to refactoring working quickly and reliably for a change?
Re:GC, No Vm or performance hit (Score:3, Interesting)
In theory yes, but in practice not very much; conservative gc works very well in most cases. The main drawbacks are:
Re:Do we really need another D infomercial? (Score:4, Interesting)
What do you think a programming language should do when I try to compare two things that can't be compared for equality?
Re:Keeping It Simple (Score:2, Interesting)
Re:This won't work... (Score:3, Interesting)
Re:GDC source is not 64-bit clean (Score:3, Interesting)
See http://dsource.org/projects/gentoo/wiki/LaymanSetu [dsource.org] p for a portage overlay that includes DMD-bin. You have to edit the layman configuration and disable warnings about missing fields, but it works fine after that.
I tried it, and it added the package, but it is masked by missing keyword. Besides, I don't want to install dmd, which is the 32bit compiler from digital mars, I'd rather have the gcc addon gdc built into my existing 64bit compiler system. I currently don't have the 32bit emulation libs installed, and I don't plan on installing them either. I have a pretty cool system going that is 64bit clean and runs like my own personal supercomputer. I'm into engineering, science, and mathematics programming, so I really like the free extra precision with 64bit and sse3 not to mention the extra cpu registers.
I might try and compile D (gdc) into /usr/local/gcc-4.0 again just to see if I can get it to work, but it is obvious that some patches need to get sent upstream for the amd64 platform. I'm not sure how best to implement the patches, but I would think that it should be done using autotools, and that config.h mechanism.