You claim to be concerned about performance, you worry about cache misses and indirections, yet you ignore one of the most common but subtle performance issues of most contemporary architectures. You obviously don't understand the issue of padding on modern architectures: we're talking about 32-bit boundaries on 32-bit systems here, not byte alignment, and the reason we're talking about that is the slow access times to memory that is not so aligned.
Even if alignment did result in faster execution in this case, I don't need the compiler second guessing me. If structure members are packed to their natural alignment, like GNU C++ does, I have an easy choice. If structure members all start on word boundaries, I don't. Of course, loops involving the default GNU C++ layout are at least twice as fast (just measured it on both Athlon and PPC).
You see, on modern machines, memory bandwidth matters a whole lot more than alignment within a word: it takes a long time for the processor to get a word from memory. Once loaded, the processor can manipulate bytes and shorts in it quickly. What is costly is non-aligned loads that cross word boundaries because they result in two words being loaded from memory.
You maintain that using indirection can cause a "severalfold space and time overhead" when on most systems, it only doubles the space overhead even in the worst possible case.
No matter how you do it, it costs more to allocate a word on the heap than just the word on the heap and the pointer to it, even in C++. And in languages like Java, each heap object has a three word header (well, maybe they got that down to two by now).
If performance mattered to you that much, you'd surely be aware that the price you pay for keeping GCC portable is that its output code can run several times slower than that generated by a compiler that's aware of the issues we've discussed and accounts for them properly.
I don't "pay a price" for keeping GNU C++ code portable. In any case, 4 Gbytes is not a lot of address space these days, and space often matters much more than time anyway: if the data structures don't fit, it doesn't matter how fast it runs on small problems. Even a factor of 2 in space makes a huge difference.
Finally, you belittle the job that I do and attack me personally over my knowledge of this subject, in spite of the fact that these issues are directly relevant to me, day in and day out, whereas you clearly aren't working in a performance-driven environment at all.
I have no idea what job you are doing because you haven't told us. And trying to pull authority while being anonymous just is silly, in particular when you are also wrong.
OK, I give up.
No need for you to give up programming over this. But you might seriously consider writing some test cases for your "interesting" theories. Maybe you'll even improve your company's mathematical software product; there is probably a lot of room: most commercial numerical software is awful.
If you write some code, and SCO says you need a license for their patent to use it, then you may not distribute it under the GPL
The GPL is a license to use and distribute copyrighted materials. If I'm the copyright holder, I don't need a license--I can distribute the software to whoever I like under whatever license I like. That's how we have dual-licensed software.
SCO can't sue people over violations of my license, just like I can't sue people over violations of Microsoft's licenses.
If you assume for a moment that SCO has a valid patent claim, and that they intend to enforce it WRT Linux, there is nothing the GPL can do to prevent this.
Sure there is. SCO has redistributed Linux. Therefore, they have accepted, and are bound by, the terms of the GPL. That affects how they can prosecute patents related to Linux.
the GCC C++ compiler is one of the few exceptions that appears to avoid padding out to natural alignment by default, at least in any version I've seen. Further, by failing to align the data members on natural boundaries, you typically take a performance hit.
The elements are bytes and the whole structure is 2 bytes. The packed representation is fully aligned, both as a whole and in terms of its elements. Some C++ compilers may well pad this anyway, but if they do, they have a quality of implementation issue (even if they are nominally within ANSI specs).
In any case, you are getting hung up on a minor point. Even if the structure contained a single 32bit word, there would still be severalfold space and time overhead.
People have tried for more than thirty years to make heap allocated objects like this fast enough and they have never succeeded. Language design would be a lot easier if they head.
By the way, I'm about to go into the office, where I work on an industry-leading, mathematically-intensive product whose whole purpose in life is the efficient manipulation of complex data structures to implement advanced mathematical algorithms with minimal run-time overhead.
Oh goodie.
It's written in C++, and ships on a dozen different platforms (mostly 32-bit) using 15+ different compilers
Well, that is just too bad for you. I lost my ambition to cater to the idiosyncracies of more than one C++ compiler more than a decade ago. My code is portable, but it's tuned only for GNU C++. That has turned out to be quite sufficient for all commercial and non-commercial purposes I have ever encountered.
"If you actually believe that hint to be true, I suggest you check again. On almost any current 32-bit platform, sizeof P will be 8 bytes, not 2."
Ummm--you don't have a clue. Try it out yourself.
$ cat foo.cc #include <stdio.h> struct P { signed char x; signed char y; }; int main(int argc,char **argv) { P x[16]; printf("%d\n",sizeof x); } $ g++ foo.cc $ a.out 32 $
"you've carefully chosen the worst possible case: a large array of objects that are as trivial as they can possibly be without being built-ins"
Yup, and that's exactly the case that value classes and structs are used for in C, C++, and C#. Together with overloading, it lets me implement numerical types that look like built-ins and work just as efficiently: fixed point numbers, small vectors, etc. Those are the meat of a lot of numerical, signal processing, and graphics code.
What you say is correct, but misses the point. It violates the GPL
No, it doesn't. If I distribute, under the GPL, source code that I have written myself, I am not violating the GPL. And whether I go after anybody else that violates the GPL on code that I hold the copyright to because of this is entirely up to me.
The intent of the patent clauses in the GPL is to prevent companies like SCO doing what this thread alleges: distributing GPL'ed source code written by others and trying to make revenue from patent licenses. Logically, it is mostly companies like SCO (or Thompson in your example) that one would likely go after.
"Just as it does with value classes on the stack. The overhead is comparable in each case."
"It's very likely that your array will be padded so the offset of each element coincides with the natural alignment of the processor, for example."
How many heap space the following C++ code end up using on a standard 32bit machine? How many function calls does the allocation take? How much memory gets written to?
struct { signed char x; signed char y} P; P *ps = new P[1000000];
(Hint: each P takes up 2 bytes inside the array.)
Now, how many bytes does the following Java code end up using on a standard 32bit machine? How much time does it take to allocate and clear those objects?
class P { public byte x; public byte y; } P ps = new P[1000000]; for(int i=0;i<1000000;i++) ps[i] = new P();
(Hint: each P takes up at least 16 bytes of heap space, plus the 4 bytes to hold the reference to it.)
Get it?
"However, there are usually relatively few such types in a program, even quite a large one."
There are also relatively few uses of "main()"; however, that doesn't make that language feature any less important.
"Where you're using a declarative programming style and this occurs a lot, there's nothing to stop an optimiser from playing the same tricks with a reference class."
Sorry, but you're wrong. A really smart, global optimizer can eliminate some heap allocations from some expressions, but it can't change array representations and it can't optimize this across most method or function calls.
"It often makes sense to force these to be indirected for future-proofing purposes,"
You can force whatever you like on your fellow programmers on your own projects. However, if a language wants to be suitable for modern, high performance numerical, graphics, and systems software development, it must support value classes. D and Java don't. C, C++, and C# do.
Graffiti combined the worst features of custom strokes and regular writing: like custom strokes, it required training, and like regular writing, it was comparatively slow. In addition, it required most people to look at the handheld.
Palm should have used something like Jot from the start, or they should have copied Xerox's Unistrokes better.
Here is some Unistrokes performance data showing it to be the fastest of the bunch. There are papers comparing Graffiti and Unistrokes directly, and, again, Unistrokes comes out way ahead.
There is no legal requirement to assert patents at any particular time. It is common practice to let other people use them freely for a few years and then bring out the lawyers.
Only trademarks need to be defended right away so that they don't fall into common usage.
We don't want to sue other Linux companies because it would give us bad PR. However, if business conditions or profits make it necessary, we will sue, even though we don't "desire" it.
We believe we do have intellectual property. We believe we can successfully sue other Linux vendors. However, we have not yet decided whether it is in our interest to do so. In particular, we fear the PR fall-out of such an action. That's why we would like you not to speculate as to whether we will or will not sue.
An "outright denial" would have been:
SCO has no intellectual property that would allow it to sue other Linux vendors.
The other acceptable response would have been:
SCO owns patent 6,666,666, which we believe is infringed by Linux implementations. We have contacted the USPTO to have the patent dedicated to the public domain.
Anything else is just PR-speak for "don't give us bad press--it's bad for our business".
Since SCO is actually redistributing Linux, they may well have granted every Linux user a license to use their patent under the GPL:
We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
So very wrong. If you were right, that would mean that I could write a GPLed program that reimplements the MP3 patent, and then tell Thompson Media that their patent is violating the GPL.
You can redistribute your source code all you like, but anybody using it would be violating Thompson's patent.
However, as soon as Thompson starts redistributing your source code and tries to assert their patent claims against users of your code, they are violating the GPL.
It doesn't matter what clock rates the P4 runs at. The fact of the matter is that with a P4 or Athlon, you get a machine that's twice as fast as a G4-based system for less money.
The last SPEC benchmarks that were done on the G4 and the P3 by Heise suggest that the G4 and the P3 have about the same performance at equal clock speeds. That's also been my impression when running compute-intensive jobs.
I don't generally buy the fastest machine on the block, but Apple seems to be really falling behind. Their answer seems to have been to ship all Power Mac G4 towers as dual processor. But two slower processors are not as useful as one fast processor. And the heat sinks and noise on those G4 towers are even more ridiculous than on the Pentium 4's.
Um... Sorry, you've lost me. Manipulating an array of pointers-to-objects instead of objects in-place -- which is all that's required to support value semantics but an underlying indirection for polymorphism purposes -- requires exactly one extra indirection per array access.
The indirection may or may not be significant (it can kill you on cache effects), but all those objects need to be allocated and deallocated, all that extra space needs to be initialized, etc. Most instances of value classes are created, their fields accessed once, and then they become garbage instantly. The other place where value classes matter, inside arrays, they are packed tightly and use up a fraction of their reference equivalents.
If it didn't matter, as you contend, then we might as well use heap allocated "Integer" and "Float" classes for everything in Java or C#. We don't because it's too slow and eats up way too much memory.
If you don't believe me, try implementing your own "Complex" class with heap allocation and compare its performance to C/C++ "complex".
Sorry, I misread that. However, as you can read from my response, I responsed to both cases.
Language designers have thought that it doesn't matter or that they can just optimize it away over and over, and it's been a flop every time. Either they've had to add the feature after the fact, with much pain, or numerical users have abandoned the platform quickly. Eiffel has had to add "expanded classes". JavaGrande has recommended value classes for Java. And languages that don't have it end up being as bad as Fortran 77 for numerical programming.
Unless I tell you, you can't possibly know what the underlying model is for MyType
First of all, in Java, that's not true because Java allows me to compare and hash object references. So, I can actually tell whether two objects are "the same" even if I can't change either of them. (Of course, via reflection, I actually can.)
MyType could be a simple pair of co-ordinates on a stack, or a (hidden) pointer to a full-blown OO type with polymorphism and all the trimmings.
Again, the point behind value classes is not abstraction or implementation flexibility or anything like that. The point is to provide something that allows me to run programs that otherwise wouldn't fit into memory because they take an order of magnitude more memory and an order of magnitude longer to run.
The point about arrays is well-taken, but that also relates to the underlying implementation of your type, and not to whether it has reference or value semantics.
No, it does not. You cannot even come close to the efficiency of a value class by fiddling around with the internal implementation of an object.
Providing what you're calling "value classes" isn't a problem. Nor is providing polymorphic behaviour with virtual functions. However, combining the two is a problem, and probably a top-5 cause of bugs in C++ programs.
I didn't ask for virtual functions on them. These kinds of classes go with overloading and templates.
As an aside, the term "value class" is slightly misleading, IMHO.
Well, it's what people have started calling them recently.
you could implement value semantics quite sensibly for a class that is really
No, you couldn't. You can emulate immutability through an interface, but immutability is not the point. I actually prefer my "value classes" to be mutable, although that doesn't seem to be the recent trend. What really matters is that they are call-by-value, return-by-value, and copy-on-assignment, as opposed to being passed around as object references. And, pragmatically, what matters is that these kinds of classes or records are packed into arrays, as opposed to involving arrays of heap references.
`Value classes' as you term them, amazingly complicate the language; they're one of the reasons that C++ is such a ball of hair.
C++ implements them poorly. Lots of other languages don't.
If you've got GC, then a reference-only design is a lot simpler. Whether this results in a lot of inefficiency is something of a controversial
It isn't controversial at all: reference counting is ridiculously inefficient for this purpose, and it is quite inefficient even relative to a GC.
Consider something like "struct { unsigned char x,y; } Pt;". Now, a "new Pt[1000000]" ends up taking 2 Mbytes (2 bytes per element) with value classes and at least a whopping 12 Mbytes (3 words per element) with reference counting.
However it's clear that many people think that `value classes' are `needed for efficiency,'
It's clear that many people don't have a clue when it comes to memory management. That includes people who think that garbage collection is inefficient as much as people who think that value classes are not needed.
Creating object instances on the stack. In D, all class objects are by reference. This eliminates the need for copy constructors, assignment operators, complex destructor semantics, and interactions with exception handling stack unwinding. Memory resources get freed by the garbage collector, other resources are freed by try-finally blocks.
The reason why C++ is so popular nowadays for numerical, engineering, graphics, and scientific applications is that it supports value classes: classes allocated on the stack, passed around by copying, and represented without any additional overhead. They are used for things like points, points with small coordinate ranges, vectors, 3D rotation matrixes, rectangles, and lots of other types. I don't believe any systems or applications language for which efficiency is a consideration can do without them.
Why the creators of D think that providing value classes is a problem, I don't understand. Sure, C++ fell all over itself with initializers, but lots of other languages have managed just fine. Pascal has value classes, and so does C#. JavaGrande recognized the lack of value classes as one of the biggest deficiencies in the Java language.
And it's not something a compiler can just optimize automatically, no matter how good it is: the use of value classes has user visible effects on interfaces and data structures.
While Christ is usually portrayed as a bit less Middle Eastern than one might historically expect, he is usually shown with dark hair and eyes in churches and paintings. And I don't see why portraying him as tall is a problem, or are you saying that everybody in the Middle East is short?
Of course, there is the perhaps more basic question of whether there is anything to portray at all or whether Christ is just a myth. And if you do believe the entire story, then the issue becomes: given his father, Christ might have had looked like anything, or even appeared differently to different people.
Even if alignment did result in faster execution in this case, I don't need the compiler second guessing me. If structure members are packed to their natural alignment, like GNU C++ does, I have an easy choice. If structure members all start on word boundaries, I don't. Of course, loops involving the default GNU C++ layout are at least twice as fast (just measured it on both Athlon and PPC).
You see, on modern machines, memory bandwidth matters a whole lot more than alignment within a word: it takes a long time for the processor to get a word from memory. Once loaded, the processor can manipulate bytes and shorts in it quickly. What is costly is non-aligned loads that cross word boundaries because they result in two words being loaded from memory.
You maintain that using indirection can cause a "severalfold space and time overhead" when on most systems, it only doubles the space overhead even in the worst possible case.
No matter how you do it, it costs more to allocate a word on the heap than just the word on the heap and the pointer to it, even in C++. And in languages like Java, each heap object has a three word header (well, maybe they got that down to two by now).
If performance mattered to you that much, you'd surely be aware that the price you pay for keeping GCC portable is that its output code can run several times slower than that generated by a compiler that's aware of the issues we've discussed and accounts for them properly.
I don't "pay a price" for keeping GNU C++ code portable. In any case, 4 Gbytes is not a lot of address space these days, and space often matters much more than time anyway: if the data structures don't fit, it doesn't matter how fast it runs on small problems. Even a factor of 2 in space makes a huge difference.
Finally, you belittle the job that I do and attack me personally over my knowledge of this subject, in spite of the fact that these issues are directly relevant to me, day in and day out, whereas you clearly aren't working in a performance-driven environment at all.
I have no idea what job you are doing because you haven't told us. And trying to pull authority while being anonymous just is silly, in particular when you are also wrong.
OK, I give up.
No need for you to give up programming over this. But you might seriously consider writing some test cases for your "interesting" theories. Maybe you'll even improve your company's mathematical software product; there is probably a lot of room: most commercial numerical software is awful.
The GPL is a license to use and distribute copyrighted materials. If I'm the copyright holder, I don't need a license--I can distribute the software to whoever I like under whatever license I like. That's how we have dual-licensed software.
SCO can't sue people over violations of my license, just like I can't sue people over violations of Microsoft's licenses.
If you assume for a moment that SCO has a valid patent claim, and that they intend to enforce it WRT Linux, there is nothing the GPL can do to prevent this.
Sure there is. SCO has redistributed Linux. Therefore, they have accepted, and are bound by, the terms of the GPL. That affects how they can prosecute patents related to Linux.
The elements are bytes and the whole structure is 2 bytes. The packed representation is fully aligned, both as a whole and in terms of its elements. Some C++ compilers may well pad this anyway, but if they do, they have a quality of implementation issue (even if they are nominally within ANSI specs).
In any case, you are getting hung up on a minor point. Even if the structure contained a single 32bit word, there would still be severalfold space and time overhead.
People have tried for more than thirty years to make heap allocated objects like this fast enough and they have never succeeded. Language design would be a lot easier if they head.
By the way, I'm about to go into the office, where I work on an industry-leading, mathematically-intensive product whose whole purpose in life is the efficient manipulation of complex data structures to implement advanced mathematical algorithms with minimal run-time overhead.
Oh goodie.
It's written in C++, and ships on a dozen different platforms (mostly 32-bit) using 15+ different compilers
Well, that is just too bad for you. I lost my ambition to cater to the idiosyncracies of more than one C++ compiler more than a decade ago. My code is portable, but it's tuned only for GNU C++. That has turned out to be quite sufficient for all commercial and non-commercial purposes I have ever encountered.
"If you actually believe that hint to be true, I suggest you check again. On almost any current 32-bit platform, sizeof P will be 8 bytes, not 2."
Ummm--you don't have a clue. Try it out yourself.
$ cat foo.cc
#include <stdio.h>
struct P { signed char x; signed char y; };
int main(int argc,char **argv) {
P x[16];
printf("%d\n",sizeof x);
}
$ g++ foo.cc
$ a.out
32
$
"you've carefully chosen the worst possible case: a large array of objects that are as trivial as they can possibly be without being built-ins"
Yup, and that's exactly the case that value classes and structs are used for in C, C++, and C#. Together with overloading, it lets me implement numerical types that look like built-ins and work just as efficiently: fixed point numbers, small vectors, etc. Those are the meat of a lot of numerical, signal processing, and graphics code.
No, it doesn't. If I distribute, under the GPL, source code that I have written myself, I am not violating the GPL. And whether I go after anybody else that violates the GPL on code that I hold the copyright to because of this is entirely up to me.
The intent of the patent clauses in the GPL is to prevent companies like SCO doing what this thread alleges: distributing GPL'ed source code written by others and trying to make revenue from patent licenses. Logically, it is mostly companies like SCO (or Thompson in your example) that one would likely go after.
Distributing the source code doesn't violate the patent. Running the resulting executable does.
"Just as it does with value classes on the stack. The overhead is comparable in each case."
"It's very likely that your array will be padded so the offset of each element coincides with the natural alignment of the processor, for example."
How many heap space the following C++ code end up using on a standard 32bit machine? How many function calls does the allocation take? How much memory gets written to?
struct { signed char x; signed char y} P;
P *ps = new P[1000000];
(Hint: each P takes up 2 bytes inside the array.)
Now, how many bytes does the following Java code end up using on a standard 32bit machine? How much time does it take to allocate and clear those objects?
class P { public byte x; public byte y; }
P ps = new P[1000000];
for(int i=0;i<1000000;i++) ps[i] = new P();
(Hint: each P takes up at least 16 bytes of heap space, plus the 4 bytes to hold the reference to it.)
Get it?
"However, there are usually relatively few such types in a program, even quite a large one."
There are also relatively few uses of "main()"; however, that doesn't make that language feature any less important.
"Where you're using a declarative programming style and this occurs a lot, there's nothing to stop an optimiser from playing the same tricks with a reference class."
Sorry, but you're wrong. A really smart, global optimizer can eliminate some heap allocations from some expressions, but it can't change array representations and it can't optimize this across most method or function calls.
"It often makes sense to force these to be indirected for future-proofing purposes,"
You can force whatever you like on your fellow programmers on your own projects. However, if a language wants to be suitable for modern, high performance numerical, graphics, and systems software development, it must support value classes. D and Java don't. C, C++, and C# do.
Palm should have used something like Jot from the start, or they should have copied Xerox's Unistrokes better.
Here is some Unistrokes performance data showing it to be the fastest of the bunch. There are papers comparing Graffiti and Unistrokes directly, and, again, Unistrokes comes out way ahead.
Only trademarks need to be defended right away so that they don't fall into common usage.
An "outright denial" would have been:
The other acceptable response would have been:
Anything else is just PR-speak for "don't give us bad press--it's bad for our business".
You can redistribute your source code all you like, but anybody using it would be violating Thompson's patent.
However, as soon as Thompson starts redistributing your source code and tries to assert their patent claims against users of your code, they are violating the GPL.
He wants to study computer engineering in Harvard University and eventually set up his own Internet or computer company.
(For people who don't get it, Harvard's CS department, while reasonably good, is not exactly the obvious top pick among CS hotshots.)
It doesn't matter what clock rates the P4 runs at. The fact of the matter is that with a P4 or Athlon, you get a machine that's twice as fast as a G4-based system for less money.
And we are simplifying the problem by killing off most species first--then we don't have to to bother identifying and cataloging them.
I don't generally buy the fastest machine on the block, but Apple seems to be really falling behind. Their answer seems to have been to ship all Power Mac G4 towers as dual processor. But two slower processors are not as useful as one fast processor. And the heat sinks and noise on those G4 towers are even more ridiculous than on the Pentium 4's.
The indirection may or may not be significant (it can kill you on cache effects), but all those objects need to be allocated and deallocated, all that extra space needs to be initialized, etc. Most instances of value classes are created, their fields accessed once, and then they become garbage instantly. The other place where value classes matter, inside arrays, they are packed tightly and use up a fraction of their reference equivalents.
If it didn't matter, as you contend, then we might as well use heap allocated "Integer" and "Float" classes for everything in Java or C#. We don't because it's too slow and eats up way too much memory.
If you don't believe me, try implementing your own "Complex" class with heap allocation and compare its performance to C/C++ "complex".
Language designers have thought that it doesn't matter or that they can just optimize it away over and over, and it's been a flop every time. Either they've had to add the feature after the fact, with much pain, or numerical users have abandoned the platform quickly. Eiffel has had to add "expanded classes". JavaGrande has recommended value classes for Java. And languages that don't have it end up being as bad as Fortran 77 for numerical programming.
First of all, in Java, that's not true because Java allows me to compare and hash object references. So, I can actually tell whether two objects are "the same" even if I can't change either of them. (Of course, via reflection, I actually can.)
MyType could be a simple pair of co-ordinates on a stack, or a (hidden) pointer to a full-blown OO type with polymorphism and all the trimmings.
Again, the point behind value classes is not abstraction or implementation flexibility or anything like that. The point is to provide something that allows me to run programs that otherwise wouldn't fit into memory because they take an order of magnitude more memory and an order of magnitude longer to run.
The point about arrays is well-taken, but that also relates to the underlying implementation of your type, and not to whether it has reference or value semantics.
No, it does not. You cannot even come close to the efficiency of a value class by fiddling around with the internal implementation of an object.
Besides, it goes so well with the one perfect shape for furniture.
I didn't ask for virtual functions on them. These kinds of classes go with overloading and templates.
As an aside, the term "value class" is slightly misleading, IMHO.
Well, it's what people have started calling them recently.
you could implement value semantics quite sensibly for a class that is really
No, you couldn't. You can emulate immutability through an interface, but immutability is not the point. I actually prefer my "value classes" to be mutable, although that doesn't seem to be the recent trend. What really matters is that they are call-by-value, return-by-value, and copy-on-assignment, as opposed to being passed around as object references. And, pragmatically, what matters is that these kinds of classes or records are packed into arrays, as opposed to involving arrays of heap references.
C++ implements them poorly. Lots of other languages don't.
If you've got GC, then a reference-only design is a lot simpler. Whether this results in a lot of inefficiency is something of a controversial
It isn't controversial at all: reference counting is ridiculously inefficient for this purpose, and it is quite inefficient even relative to a GC.
Consider something like "struct { unsigned char x,y; } Pt;". Now, a "new Pt[1000000]" ends up taking 2 Mbytes (2 bytes per element) with value classes and at least a whopping 12 Mbytes (3 words per element) with reference counting.
However it's clear that many people think that `value classes' are `needed for efficiency,'
It's clear that many people don't have a clue when it comes to memory management. That includes people who think that garbage collection is inefficient as much as people who think that value classes are not needed.
The reason why C++ is so popular nowadays for numerical, engineering, graphics, and scientific applications is that it supports value classes: classes allocated on the stack, passed around by copying, and represented without any additional overhead. They are used for things like points, points with small coordinate ranges, vectors, 3D rotation matrixes, rectangles, and lots of other types. I don't believe any systems or applications language for which efficiency is a consideration can do without them.
Why the creators of D think that providing value classes is a problem, I don't understand. Sure, C++ fell all over itself with initializers, but lots of other languages have managed just fine. Pascal has value classes, and so does C#. JavaGrande recognized the lack of value classes as one of the biggest deficiencies in the Java language.
And it's not something a compiler can just optimize automatically, no matter how good it is: the use of value classes has user visible effects on interfaces and data structures.
Of course, there is the perhaps more basic question of whether there is anything to portray at all or whether Christ is just a myth. And if you do believe the entire story, then the issue becomes: given his father, Christ might have had looked like anything, or even appeared differently to different people.