D Programming Advanced Experienced Freshers Interview Questions Answers
Why The Name D?
The original name was the Mars Programming Language. But my friends kept calling it D, and I found myself starting to call it D. The idea of D being a successor to C goes back at least as far as 1988, as in this thread.
Could You Change The Name? D Is Kind Of Hard To Search For On Search Engines?
No. We understand it can be frustrating but it's far too late for a name change at this point. We recommend using "dlang", "d programming", "d language", or "d programming language" in your search terms. Doing so should yield substantially better search results.
Most publicly available D code has "// Written in the D programming language" as its first comment.
Is There A Linux Port Of D?
Yes, the D compiler includes a linux version.
Is There A Gnu Version Of D?
Yes, gdc - the D frontend with GCC.
How Do I Write My Own D Compiler For Cpu X?
Burton Radons has written a back end. You can use as a guide.
Where Can I Get A Gui Library For D?
Since D can call C functions, any GUI library with a C interface is accessible from D. Various D GUI libraries and ports can be found at the D wiki.
Where Can I Get An Ide For D?
Lists of editors and IDEs that support D can be found on the D wiki.
Why Is Printf In D?
printf is not part of D, it is part of C's standard runtime library which is accessible from D. D's standard runtime library has std.stdio.writefln, which is as powerful as printf but is much easier to use.
Why Doesn't The Case Range Statement Use The Case X..y: Syntax?
The usages of .. would then be:
case X..Y:
foreach(e; X..Y)
array[X..Y]
Case (1) has a VERY DIFFERENT meaning from (2) and (3). (1) is inclusive of Y, and (2) and (3) are exclusive of Y. Having a very different meaning means it should have a distinctly different syntax.
What Guarantees Are Shared Supposed To Provide?
Shared means that multiple threads can access the data. The guarantee is that if it is not shared, and not immutable, that only the current thread can see it.
What Does Shared Have To Do With Synchronization?
Only shared data can be synchronized. It makes no sense to synchronize thread local data.
What Are The Semantics Of Casting From Unshared To Shared?
Make sure there are no other unshared references to that same data.
What Are The Semantics Of Casting From Shared To Unshared?
Make sure there are no other shared references to that same data.
Why Does A Large Static Array Bloat My Executable File Size?
Given the declaration:
char[1024 * 1024] arr;
the executable size increases by a megabyte in size. In C, this would not as arr would be stored in the BSS segment. In D, arr is not stored in the BSS segment because:
The char type is initialized to 0xFF, not 0. Non-zero data cannot be placed in BSS.
Statically allocated data is placed in thread local storage. The BSS segment is not thread local, and there is no thread local equivalent of BSS.
The following will be placed in BSS:
__gshared byte[1024 * 1024] arr;
as bytes are 0 initialized and __gshared puts it in the global data.
There are similiar issues for float, double, and real static arrays. They are initialized to NaN (Not A Number) values, not 0.
The easiest way to deal with this issue is to allocate the array dynamically at run time rather than statically allocate it.
The front end for the dmd D compiler is open source. The back end for dmd is licensed from Symantec, and is not compatible with open-source licenses such as the GPL. Nonetheless, the complete source comes with the compiler, and all development takes place publicly on github. Compilers using the DMD front end and the GCC and LLVM open source backends are also available. The runtime library is completely open source using the Boost License 1.0. The gdc and ldcD compilers are completely open sourced.
Why Does The Standard Library Use The Boost License? Why Not Public Domain?
Although most jurisdictions use the concept of Public Domain, some (eg, Japan) do not. The Boost License avoids this problem. It was chosen because, unlike almost all other open source licenses, it does not demand that the license text be included on distributions in binary form.
Why No Fall Through On Switch Statements?
Many people have asked for a requirement that there be a break between cases in a switch statement, that C's behavior of silently falling through is the cause of many bugs.
In D2, implicit fall through is disallowed. You have to add a goto case; statement to explicitly state the intention of falling through.
There was further request that the break statement be made implicit. The reason D doesn't change this is for the same reason that integral promotion rules and operator precedence rules were kept the same - to make code that looks the same as in C operate the same. If it had subtly different semantics, it will cause frustratingly subtle bugs.
Why Should I Use D Instead Of Java?
D is distinct from Java in purpose, philosophy and reality. See this comparison.
Java is designed to be write once, run everywhere. D is designed for writing efficient native system apps. Although D and Java share the notion that garbage collection is good and multiple inheritance is bad, their different design goals mean the languages have very different feels.
Doesn't C++ Support Strings, Etc. With Stl?
In the C++ standard library are mechanisms for doing strings, dynamic arrays, associative arrays, and bounds-checked arrays.
Sure, all this stuff can be done with libraries, following certain coding disciplines, etc. But object oriented programming can also be done in C (it's been done). Isn't it incongruous that something like strings, supported by the simplest BASIC interpreter, requires a very large and complicated infrastructure to support? Just the implementation of a string type in STL is over two thousand lines of code, using every advanced feature of templates. How much confidence can you have that this is all working correctly, how do you fix it if it is not, what do you do with the notoriously inscrutable error messages when there's an error using it, how can you be sure you are using it correctly (so there are no memory leaks, etc.)?
D's implementation of strings is simple and straightforward. There's little doubt about how to use it, no worries about memory leaks, error messages are to the point, and it isn't hard to see if it is working as expected or not.
Can't Garbage Collection Be Done In C++ With An Add-on Library?
Yes, I use one myself. It isn't part of the language, though, and requires some subverting of the language to make it work. Using gc with C++ isn't for the standard or casual C++ programmer. Building it into the language, like in D, makes it practical for everyday programming chores.
GC isn't that hard to implement, either, unless you're building one of the more advanced ones. But a more advanced one is like building a better optimizer - the language still works 100% correctly even with a simple, basic one. The programming community is better served by multiple implementations competing on quality of code generated rather than by which corners of the spec are implemented at all.
Why Is Overloading Of The Assignment Operator Not Supported?
Overloading of the assignment operator for structs is supported in D 2.0.
The ‘~’ Is Not On My Keyboard?
On PC keyboards, hold down the [Alt] key and press the 1, 2, and 6 keys in sequence on the numeric pad. That will generate a ‘~’ character.
Can I Link In C Object Files Created With Another Compiler?
DMD produces OMF (Microsoft Object Module Format) object files while other compilers such as VC++ produce COFF object files. DMD's output is designed to work with DMC, the Digital Mars C compiler, which also produces object files in OMF format.
The OMF format that DMD uses is a Microsoft defined format based on an earlier Intel designed one. Microsoft at one point decided to abandon it in favor of a Microsoft defined variant on COFF.
Using the same object format doesn't mean that any C library in that format will successfully link and run. There is a lot more compatibility required - such as calling conventions, name mangling, compiler helper functions, and hidden assumptions about the way things work. If DMD produced Microsoft COFF output files, there is still little chance that they would work successfully with object files designed and tested for use with VC. There were a lot of problems with this back when Microsoft's compilers did generate OMF.
Having a different object file format makes it helpful in identifying library files that were not tested to work with DMD. If they are not, weird problems would result even if they successfully managed to link them together. It really takes an expert to get a binary built with a compiler from one vendor to work with the output of another vendor's compiler.
That said, the linux version of DMD produces object files in the ELF format which is standard on linux, and it is specifically designed to work with the standard linux C compiler, gcc.
Why Not Support Regular Expression Literals With The /foo/g Syntax?
There are two reasons:
The /foo/g syntax would make it impossible to separate the lexer from the parser, as / is the divide token.
There are already 3 string types; adding the regex literals would add 3 more. This would proliferate through much of the compiler, debugger info, and library, and is not worth it.
Can't Unit Testing Be Done In C++ With An Add-on Library?
Sure. Try one out and then compare it with how D does it. It'll be quickly obvious what an improvement building it into the language is.
Why Have An Asm Statement In A Portable Language?
An asm statement allows assembly code to be inserted directly into a D function. Assembler code will obviously be inherently non-portable. D is intended, however, to be a useful language for developing systems apps. Systems apps almost invariably wind up with system dependent code in them anyway, inline asm isn't much different. Inline asm will be useful for things like accessing special CPU instructions, accessing flag bits, special computational situations, and super optimizing a piece of code.
Before the C compiler had an inline assembler, I used external assemblers. There was constant grief because many, many different versions of the assembler were out there, the vendors kept changing the syntax of the assemblers, there were many different bugs in different versions, and even the command line syntax kept changing. What it all meant was that users could not reliably rebuild any code that needed assembler. An inline assembler provided reliability and consistency.
What Is The Point Of 80 Bit Reals?
More precision enables more accurate floating point computations to be done, especially when adding together large numbers of small real numbers. Prof. Kahan, who designed the Intel floating point unit, has an eloquent paper on the subject.
How Do I Do Anonymous Struct/unions In D?
import std.stdio;
struct Foo
{
union { int a; int b; }
struct { int c; int d; }
}
void main()
{
writefln(
"Foo.sizeof = %d, a.offset = %d, b.offset = %d, c.offset = %d, d.offset = %d",
Foo.sizeof,
Foo.a.offsetof,
Foo.b.offsetof,
Foo.c.offsetof,
Foo.d.offsetof);
}
How Do I Get Printf() To Work With Strings?
In C, the normal way to printf a string is to use the %s format:
char s[8];
strcpy(s, "foo");
printf("string = '%s'n", s);
Attempting this in D, as in:
char[] s;
s = "foo";
printf("string = '$(B %s)'n", s);
usually results in garbage being printed, or an access violation. The cause is that in C, strings are terminated by a 0 character. The %s format prints until a 0 is encountered. In D, strings are not 0 terminated, the size is determined by a separate length value. So, strings are printf'd using the %.*s format:
char[] s;
s = "foo";
printf("string = '$(B %.*s)'n", s);
which will behave as expected. Remember, though, that printf's %.*s will print until the length is reached or a 0 is encountered, so D strings with embedded 0's will only print up to the first 0.
Of course, the easier solution is just use std.stdio.writefln which works correctly with D strings.
What Is Immutable Good For?
Immutable data, once initialized, is never changed. This has many uses:
Access to immutable data need not be synchronized when multiple threads read it.
Data races, tearing, sequential consistency, and cache consistency are all non-issues when working with immutable data.
Pure functions can only accept immutable parameters.
When doing a deep copy of a data structure, the immutable portions need not be copied.
Invariance allows a large chunk of data to be treated as a value type even if it is passed around by reference (strings are the most common case of this).
Immutable type provides more self-documenting information to the programmer.
Immutable data can be placed in hardware protected read-only memory, or even in ROMs.
If immutable data does change, it is a sure sign of a memory corruption bug, and it is possible to automatically check for such data integrity.
Immutable types provide for many program optimization opportunities.
const acts as a bridge between the mutable and immutable worlds, so a single function can be used to accept both types of arguments.
Why Are Floating Point Values Default Initialized To Nan Rather Than 0?
A floating point value, if no explicit initializer is given, is initialized to NaN (Not A Number):
double d; // d is set to double.nan
NaNs have the interesting property in that whenever a NaN is used as an operand in a computation, the result is a NaN. Therefore, NaNs will propagate and appear in the output whenever a computation made use of one. This implies that a NaN appearing in the output is an unambiguous indication of the use of an uninitialized variable.
If 0.0 was used as the default initializer for floating point values, its effect could easily be unnoticed in the output, and so if the default initializer was unintended, the bug may go unrecognized.
The default initializer value is not meant to be a useful value, it is meant to expose bugs. Nan fills that role well.
But surely the compiler can detect and issue an error message for variables used that are not initialized? Most of the time, it can, but not always, and what it can do is dependent on the sophistication of the compiler's internal data flow analysis. Hence, relying on such is unportable and unreliable.
Because of the way CPUs are designed, there is no NaN value for integers, so D uses 0 instead. It doesn't have the advantages of error detection that NaN has, but at least errors resulting from unintended default initializations will be consistent and therefore more debuggable.
Why Aren't All Digital Mars Programs Translated To D?
There is little benefit to translating a complex, debugged, working application from one language to another. But new Digital Mars apps are implemented in D.
When Should I Use A Foreach Loop Rather Than A For?
By using foreach, you are letting the compiler decide on the optimization rather than worrying about it yourself. For example - are pointers or indices better? Should I cache the termination condition or not? Should I rotate the loop or not? The answers to these questions are not easy, and can vary from machine to machine. Like register assignment, let the compiler do the optimization.
for (int i = 0; i < foo.length; i++)
or:
for (int i = 0; i < foo.length; ++i)
or:
for (T* p = &foo[0]; p < &foo[length]; p++)
or:
T* pend = &foo[length];
for (T* p = &foo[0]; p < pend; ++p)
or:
T* pend = &foo[length];
T* p = &foo[0];
if (p < pend)
{
do
{
...
} while (++p < pend);
}
and, of course, should I use size_t or int?
for (size_t i = 0; i < foo.length; i++)
Let the compiler pick!
foreach (v; foo)
...
Note that we don't even need to know what the type T needs to be, thus avoiding bugs when T changes. I don't even have to know if foo is an array, or an associative array, or a struct, or a collection class. This will also avoid the common fencepost bug:
for (int i = 0; i <= foo.length; i++)
And it also avoids the need to manually create a temporary if foo is a function call.
The only reason to use a for loop is if your loop does not fit in the conventional form, like if you want to change the termination condition on the fly.
Isn't Garbage Collection Slow And Non-deterministic?
Yes, but all dynamic memory management is slow and non-deterministic, including malloc/free. If you talk to the people who actually do real time software, they don't use malloc/free precisely because they are not deterministic. They preallocate all data. However, the use of GC instead of malloc enables advanced language constructs (especially, more powerful array syntax), which greatly reduce the number of memory allocations which need to be made. This can mean that GC is actually faster than explict management.
Can't A Sufficiently Smart Compiler Figure Out That A Function Is Pure Automatically?
The compiler infers purity (and safety, and nothrow) for delegate and function literals. It doesn't do this for normal functions for several reasons:
most functions call other functions, which call other functions, until one of them calls a library routine whose source is not available to the compiler. So it will have to assume it is not pure. With a pure function attribute, external library functions that are pure can be marked as pure, and then the analysis can work for enough cases to be useful.
Since virtual functions (and by extension delegates and function pointers) can be extended by the user at times the compiler won't see it, they have to be assumed to be impure.
If the programmer intends for a particular function to be pure and the compiler detects it is not, this may go unnoticed by the programmer. Even worse, if the programmer does notice it, it may be arbitrarily difficult to determine why the compiler thinks it is impure - is it a programming mistake or a compiler bug?
Why Allow Cast(float) If It Isn't Supposed To Work?
The floating point rules are such that transforming cast(real)cast(float) to cast(real) is a valid transformation. This is because the floating point rules are written with the following principle in mind:
An algorithm is invalid if it breaks if the floating point precision is increased. Floating point precision is always a minimum, not a maximum.
Programs that legitimately depended on maximum precision are:
compiler/library validation test suites
ones trying to programmatically test the precision
is not of value to user programming, and there are alternate ways to test the precision.
D has .properties that take care of that.
Programs that rely on a maximum accuracy need to be rethought and reengineered.
Why Can't Nested Functions Be Forward Referenced?
Declarations within a function are different from declarations at module scope. Within a function, initializers for variable declarations are guaranteed to run in sequential order. Allowing arbitrary forward references to nested functions would break this, because nested functions can reference any variables declared above them.
int first() { return second(); }
int x = first(); // x depends on y, which hasn't been declared yet.
int y = x + 1;
int second() { return y; }
But, forward references of nested functions are sometimes required (eg, for mutually recursive nested functions). The most general solution is to declare a local, nested struct. Any member functions (and variables!) of that struct have non-sequential semantics, so they can forward reference each other.
Why Does D Have Const?
People often express frustration with const and immutable in D 2.0 and wonder if it is worth it.
It makes function interfaces more self-documenting. Without transitive const, for all pointer/reference parameters one must rely on the documentation (which is always missing, out of date, or wrong). Note that without transitivity, C++ const is nearly useless for such self-documentation, which is why C++ programmers tend to rely on convention instead.
It makes for interfaces that can be relied upon, which becomes increasingly important the more people that are involved with the code. In other words, it scales very well. People who are involved with projects with large teams of programmers say that lack of const makes their lives difficult because they cannot rely on the compiler to enforce convention. The larger the team, the worse it gets. Managing APIs is critical to a large project - it's why BASIC doesn't scale (for an extreme example).
Const transitivity makes for some interesting optimization opportunities. The value of this has not been explored or exploited.
Here's the biggie. Points 1..3 are insignificant in comparison. The future of programming will be multicore, multithreaded. Languages that make it easy to program them will supplant languages that don't. Transitive const is key to bringing D into this paradigm. The surge in use of Haskell and Erlang is evidence of this coming trend (the killer feature of those languages is they make it easy to do multiprogramming). C++ cannot be retrofitted to supporting multiprogramming in a manner that makes it accessible. D isn't there yet, but it will be, and transitive const will be absolutely fundamental to making it work.
Of course, for writing single-threaded one man programs of fairly modest size, const is not particularly useful. And in D const can be effectively ignored by just not using it, or by using D 1.0. The only place const is imposed is with the immutable string type.
What Principles Drove The D Const Design?
It will be mathematically sound. That means there are no legal escapes from it.
Any type can be wrapped in a struct and the resulting struct can still exhibit the same const behavior - in other words, no magic behavior for certain types.
Const behavior will be transitive.
Const behavior for type T will be equivalent for all types T.
What Is Transitive Const?
Transitive const means that once const is applied to a type, it applies recursively to every sub-component of that type. Hence:
const(int*)** p;
p += 1; // ok, p is mutable
*p += 1; // ok, *p is mutable
**p += 1; // error, **p is const
***p += 1; // error, ***p is const
With transitivity, there is no way to have a const pointer to mutable int.
C++ const is not transitive.
What Is Head Const?
Head const is where the const applies only to the component of the type adjacent to the const.
For example:
headconst(int**) p;
would be read as p being a: const pointer to mutable pointer to mutable int. D does not have head const (the headconst is there just for illustrative purposes), but C++ const is a head const system.
What Is Tail Const?
Tail const is the complement of head const - everything reachable from the const type is also const except for the top level.
For example:
tailconst(int**) p;
would be read as p being a: mutable pointer to const pointer to const int. Head const combined with tail const yields transitive const. D doesn't have tailconst (the keyword is there just for illustrative purposes) as a distinct type constructor.
What Is Logical Const?
Logical const refers to data that appears to be constant to an observer, but is not actually const. An example would be an object that does lazy evaluation:
struct Foo
{
mutable int len;
mutable bool len_done;
const char* str;
int length()
{
if (!len_done)
{
len = strlen(str);
len_done = true;
}
return len;
}
this(char* str) { this.str = str; }
}
const Foo f = Foo("hello");
bar(f.length);
The example evaluates f.len only if it is needed. Foo is logically const, because to the observer of the object its return values never change after construction. The mutable qualifier says that even if an instance of Foo is const, those fields can still change. While C++ supports the notion of logical const, D does not, and D does not have a mutable qualifier.
The problem with logical const is that const is no longer transitive. Not being transitive means there is the potential for threading race conditions, and there is no way to determine if an opaque const type has mutable members or not.
Why Not Use Readonly To Mean Read Only View?
Readonly has a well established meaning in software to mean ROM, or Read Only Memory that can never be changed. For computers with hardware protection for memory pages, readonly also means that the memory contents cannot be altered. Using readonly in D to mean a read only view of memory that could be altered by another alias or thread runs counter to this.
How Does Const Differ In C++?
C++ has a const system that is closer to D's than any other language, but it still has huge differences:
const is not transitive
no immutables
const objects can have mutable members
const can be legally cast away and the data modified
const T and T are not always distinct types
Why Aren't Function Parameters Const By Default?
Since most (nearly all?) function parameters will not be modified, it would seem to make sense to make them all const by default, and one would have to specifically mark as mutable those that would be changed. The problems with this are:
1. It would be a huge break from past D practice, and practice in C, C++, Java, C#, etc.
2. It would require a new keyword, say mutable.
3. And worst, it would make declarations inconsistent:
4. void foo(int* p)
5. {
6. int* q;
7. ...
8. }
p points to const, and q points to mutable. This kind of inconsistency leads to all sorts of mistakes. It also makes it very hard to write generic code that deals with types.
Using in can mitigate the ugliness of having to annotate with const:
void str_replace(in char[] haystack, in char[] needle);
Are Static Class Members Covered By Transitive Const?
A static class member is part of the global state of a program, not part of the state of an object. Thus, a class having a mutable static member does not violate the transitive constness of an object of that class.
Why Doesn't D Have An Interface To C++ As Well As C?
Here are some reasons why it isn't a full interface:
Attempting to have D interface with C++ is nearly as complicated as writing a C++ compiler, which would destroy the goal of having D be a reasonably easy language to implement. For people with an existing C++ code base that they must work with, they are stuck with C++ (they can't move it to any other language, either).
There are many issues that would have to be resolved in order for D code to call some arbitrary C++ code that is presumed to be unmodifiable. This list certainly isn't complete, it's just to show the scope of the difficulties involved.
D source code is unicode, C++'s is ASCII with code pages. Or not. It's unspecified. This impacts the contents of string literals.
std::string cannot deal with multibyte UTF.
C++ has a tag name space. D does not. Some sort of renaming would have to happen.
C++ code often relies on compiler specific extensions.
C++ has namespaces. D has modules. There is no obvious mapping between the two.
C++ views source code as one gigantic file (after preprocessing). D sees source code as a hierarchy of modules and packages.
Enum name scoping rules behave differently.
C++ code, despite decades of attempts to replace macro features with inbuilt ones, relies more heavily than ever on layer after layer of arbitrary macros. D does not always have an analog for token pasting and stringizing.
Macro names have global scope across #include files, but are local to the gigantic source files.
C++ has arbitrary multiple inheritance and virtual base classes. D does not.
C++ does not distinguish between in, out and ref (i.e. inout) parameters.
The C++ name mangling varies from compiler to compiler.
C++ throws exceptions of arbitrary type, not just descendants of Object.
C++ overloads based on const and volatile. D overloads based on const and immutable.
C++ overloads operators in significantly different ways - for example, operator[]() overloading for lvalue and rvalue is based on const overloading and a proxy class.
C++ overloads operators like < completely independently of >.
C++ does not distinguish between a class and a struct object.
The vtbl[] location and layout is different between C++ and D.
The way RTTI is done is completely different. C++ has no classinfo.
D does not have two phase lookup, nor does it have Koenig (ADL) lookup.
C++ relates classes with the 'friend' system, D uses packages and modules.
C++ class design tends to revolve around explicit memory allocation issues, D's do not.
D's template system is very different.
C++ has 'exception specifications'.
C++ has global operator overloading.
C++ name mangling depends on const and volatile being type modifiers. D name mangling depends on const and immutable being type modifiers. D's const is also transitive, unlike C++. One cannot have a const pointer to mutable in D.
The bottom line is the language features affect the design of the code. C++ designs just don't fit with D. Even if you could find a way to automatically adapt between the two, the result will be about as enticing as the left side of a honda welded to the right side of a camaro.
Why Doesn't D Use Reference Counting For Garbage Collection?
Reference counting has its advantages, but some severe disadvantages:
Cyclical data structures won't get freed.
Every pointer copy requires an increment and a corresponding decrement - including when simply passing a reference to a function.
In a multithreaded app, the incs and decs must be synchronized.
Exception handlers (finally blocks) must be inserted to handle all the decs so there are no leaks. Contrary to assertions otherwise, there is no such thing as "zero overhead exceptions."
In order to support slicing and interior pointers, as well as supporting reference counting on arbitrary allocations of non-object data, a separate "wrapper" object must be allocated for each allocation to be ref counted. This essentially doubles the number of allocations needed.
The wrapper object will mean that all pointers will need to be double-dereferenced to access the data.
Fixing the compiler to hide all this stuff from the programmer will make it difficult to interface cleanly with C.
Ref counting can fragment the heap thereby consuming more memory just like the gc can, though the gc typically will consume more memory overall.
Ref counting does not eliminate latency problems, it just reduces them.
The proposed C++ shared_ptr<>, which implements ref counting, suffers from all these faults. I haven't seen a heads up benchmark of shared_ptr<> vs mark/sweep, but I wouldn't be surprised if shared_ptr<> turned out to be a significant loser in terms of both performance and memory consumption.
That said, D may in the future optionally support some form of ref counting, as rc is better for managing scarce resources like file handles. Furthermore, if ref counting is a must, Phobos has the std.typecons.RefCounted type which implements it as a library, similar to C++'s shared_ptr<>.
Why The Name D?
The original name was the Mars Programming Language. But my friends kept calling it D, and I found myself starting to call it D. The idea of D being a successor to C goes back at least as far as 1988, as in this thread.
Could You Change The Name? D Is Kind Of Hard To Search For On Search Engines?
No. We understand it can be frustrating but it's far too late for a name change at this point. We recommend using "dlang", "d programming", "d language", or "d programming language" in your search terms. Doing so should yield substantially better search results.
Most publicly available D code has "// Written in the D programming language" as its first comment.
Is There A Linux Port Of D?
Yes, the D compiler includes a linux version.
Is There A Gnu Version Of D?
Yes, gdc - the D frontend with GCC.
How Do I Write My Own D Compiler For Cpu X?
Burton Radons has written a back end. You can use as a guide.
Where Can I Get A Gui Library For D?
Since D can call C functions, any GUI library with a C interface is accessible from D. Various D GUI libraries and ports can be found at the D wiki.
Where Can I Get An Ide For D?
Lists of editors and IDEs that support D can be found on the D wiki.
Why Is Printf In D?
printf is not part of D, it is part of C's standard runtime library which is accessible from D. D's standard runtime library has std.stdio.writefln, which is as powerful as printf but is much easier to use.
Why Doesn't The Case Range Statement Use The Case X..y: Syntax?
The usages of .. would then be:
case X..Y:
foreach(e; X..Y)
array[X..Y]
Case (1) has a VERY DIFFERENT meaning from (2) and (3). (1) is inclusive of Y, and (2) and (3) are exclusive of Y. Having a very different meaning means it should have a distinctly different syntax.
What Guarantees Are Shared Supposed To Provide?
Shared means that multiple threads can access the data. The guarantee is that if it is not shared, and not immutable, that only the current thread can see it.
What Does Shared Have To Do With Synchronization?
Only shared data can be synchronized. It makes no sense to synchronize thread local data.
What Are The Semantics Of Casting From Unshared To Shared?
Make sure there are no other unshared references to that same data.
What Are The Semantics Of Casting From Shared To Unshared?
Make sure there are no other shared references to that same data.
D Programming Advanced Experienced Freshers Interview Questions Answers |
Given the declaration:
char[1024 * 1024] arr;
the executable size increases by a megabyte in size. In C, this would not as arr would be stored in the BSS segment. In D, arr is not stored in the BSS segment because:
The char type is initialized to 0xFF, not 0. Non-zero data cannot be placed in BSS.
Statically allocated data is placed in thread local storage. The BSS segment is not thread local, and there is no thread local equivalent of BSS.
The following will be placed in BSS:
__gshared byte[1024 * 1024] arr;
as bytes are 0 initialized and __gshared puts it in the global data.
There are similiar issues for float, double, and real static arrays. They are initialized to NaN (Not A Number) values, not 0.
The easiest way to deal with this issue is to allocate the array dynamically at run time rather than statically allocate it.
Is D Open Source?
The front end for the dmd D compiler is open source. The back end for dmd is licensed from Symantec, and is not compatible with open-source licenses such as the GPL. Nonetheless, the complete source comes with the compiler, and all development takes place publicly on github. Compilers using the DMD front end and the GCC and LLVM open source backends are also available. The runtime library is completely open source using the Boost License 1.0. The gdc and ldcD compilers are completely open sourced.
Why Does The Standard Library Use The Boost License? Why Not Public Domain?
Although most jurisdictions use the concept of Public Domain, some (eg, Japan) do not. The Boost License avoids this problem. It was chosen because, unlike almost all other open source licenses, it does not demand that the license text be included on distributions in binary form.
Why No Fall Through On Switch Statements?
Many people have asked for a requirement that there be a break between cases in a switch statement, that C's behavior of silently falling through is the cause of many bugs.
In D2, implicit fall through is disallowed. You have to add a goto case; statement to explicitly state the intention of falling through.
There was further request that the break statement be made implicit. The reason D doesn't change this is for the same reason that integral promotion rules and operator precedence rules were kept the same - to make code that looks the same as in C operate the same. If it had subtly different semantics, it will cause frustratingly subtle bugs.
Why Should I Use D Instead Of Java?
D is distinct from Java in purpose, philosophy and reality. See this comparison.
Java is designed to be write once, run everywhere. D is designed for writing efficient native system apps. Although D and Java share the notion that garbage collection is good and multiple inheritance is bad, their different design goals mean the languages have very different feels.
Doesn't C++ Support Strings, Etc. With Stl?
In the C++ standard library are mechanisms for doing strings, dynamic arrays, associative arrays, and bounds-checked arrays.
Sure, all this stuff can be done with libraries, following certain coding disciplines, etc. But object oriented programming can also be done in C (it's been done). Isn't it incongruous that something like strings, supported by the simplest BASIC interpreter, requires a very large and complicated infrastructure to support? Just the implementation of a string type in STL is over two thousand lines of code, using every advanced feature of templates. How much confidence can you have that this is all working correctly, how do you fix it if it is not, what do you do with the notoriously inscrutable error messages when there's an error using it, how can you be sure you are using it correctly (so there are no memory leaks, etc.)?
D's implementation of strings is simple and straightforward. There's little doubt about how to use it, no worries about memory leaks, error messages are to the point, and it isn't hard to see if it is working as expected or not.
Can't Garbage Collection Be Done In C++ With An Add-on Library?
Yes, I use one myself. It isn't part of the language, though, and requires some subverting of the language to make it work. Using gc with C++ isn't for the standard or casual C++ programmer. Building it into the language, like in D, makes it practical for everyday programming chores.
GC isn't that hard to implement, either, unless you're building one of the more advanced ones. But a more advanced one is like building a better optimizer - the language still works 100% correctly even with a simple, basic one. The programming community is better served by multiple implementations competing on quality of code generated rather than by which corners of the spec are implemented at all.
Why Is Overloading Of The Assignment Operator Not Supported?
Overloading of the assignment operator for structs is supported in D 2.0.
The ‘~’ Is Not On My Keyboard?
On PC keyboards, hold down the [Alt] key and press the 1, 2, and 6 keys in sequence on the numeric pad. That will generate a ‘~’ character.
Can I Link In C Object Files Created With Another Compiler?
DMD produces OMF (Microsoft Object Module Format) object files while other compilers such as VC++ produce COFF object files. DMD's output is designed to work with DMC, the Digital Mars C compiler, which also produces object files in OMF format.
The OMF format that DMD uses is a Microsoft defined format based on an earlier Intel designed one. Microsoft at one point decided to abandon it in favor of a Microsoft defined variant on COFF.
Using the same object format doesn't mean that any C library in that format will successfully link and run. There is a lot more compatibility required - such as calling conventions, name mangling, compiler helper functions, and hidden assumptions about the way things work. If DMD produced Microsoft COFF output files, there is still little chance that they would work successfully with object files designed and tested for use with VC. There were a lot of problems with this back when Microsoft's compilers did generate OMF.
Having a different object file format makes it helpful in identifying library files that were not tested to work with DMD. If they are not, weird problems would result even if they successfully managed to link them together. It really takes an expert to get a binary built with a compiler from one vendor to work with the output of another vendor's compiler.
That said, the linux version of DMD produces object files in the ELF format which is standard on linux, and it is specifically designed to work with the standard linux C compiler, gcc.
Why Not Support Regular Expression Literals With The /foo/g Syntax?
There are two reasons:
The /foo/g syntax would make it impossible to separate the lexer from the parser, as / is the divide token.
There are already 3 string types; adding the regex literals would add 3 more. This would proliferate through much of the compiler, debugger info, and library, and is not worth it.
Can't Unit Testing Be Done In C++ With An Add-on Library?
Sure. Try one out and then compare it with how D does it. It'll be quickly obvious what an improvement building it into the language is.
Why Have An Asm Statement In A Portable Language?
An asm statement allows assembly code to be inserted directly into a D function. Assembler code will obviously be inherently non-portable. D is intended, however, to be a useful language for developing systems apps. Systems apps almost invariably wind up with system dependent code in them anyway, inline asm isn't much different. Inline asm will be useful for things like accessing special CPU instructions, accessing flag bits, special computational situations, and super optimizing a piece of code.
Before the C compiler had an inline assembler, I used external assemblers. There was constant grief because many, many different versions of the assembler were out there, the vendors kept changing the syntax of the assemblers, there were many different bugs in different versions, and even the command line syntax kept changing. What it all meant was that users could not reliably rebuild any code that needed assembler. An inline assembler provided reliability and consistency.
What Is The Point Of 80 Bit Reals?
More precision enables more accurate floating point computations to be done, especially when adding together large numbers of small real numbers. Prof. Kahan, who designed the Intel floating point unit, has an eloquent paper on the subject.
How Do I Do Anonymous Struct/unions In D?
import std.stdio;
struct Foo
{
union { int a; int b; }
struct { int c; int d; }
}
void main()
{
writefln(
"Foo.sizeof = %d, a.offset = %d, b.offset = %d, c.offset = %d, d.offset = %d",
Foo.sizeof,
Foo.a.offsetof,
Foo.b.offsetof,
Foo.c.offsetof,
Foo.d.offsetof);
}
How Do I Get Printf() To Work With Strings?
In C, the normal way to printf a string is to use the %s format:
char s[8];
strcpy(s, "foo");
printf("string = '%s'n", s);
Attempting this in D, as in:
char[] s;
s = "foo";
printf("string = '$(B %s)'n", s);
usually results in garbage being printed, or an access violation. The cause is that in C, strings are terminated by a 0 character. The %s format prints until a 0 is encountered. In D, strings are not 0 terminated, the size is determined by a separate length value. So, strings are printf'd using the %.*s format:
char[] s;
s = "foo";
printf("string = '$(B %.*s)'n", s);
which will behave as expected. Remember, though, that printf's %.*s will print until the length is reached or a 0 is encountered, so D strings with embedded 0's will only print up to the first 0.
Of course, the easier solution is just use std.stdio.writefln which works correctly with D strings.
What Is Immutable Good For?
Immutable data, once initialized, is never changed. This has many uses:
Access to immutable data need not be synchronized when multiple threads read it.
Data races, tearing, sequential consistency, and cache consistency are all non-issues when working with immutable data.
Pure functions can only accept immutable parameters.
When doing a deep copy of a data structure, the immutable portions need not be copied.
Invariance allows a large chunk of data to be treated as a value type even if it is passed around by reference (strings are the most common case of this).
Immutable type provides more self-documenting information to the programmer.
Immutable data can be placed in hardware protected read-only memory, or even in ROMs.
If immutable data does change, it is a sure sign of a memory corruption bug, and it is possible to automatically check for such data integrity.
Immutable types provide for many program optimization opportunities.
const acts as a bridge between the mutable and immutable worlds, so a single function can be used to accept both types of arguments.
A floating point value, if no explicit initializer is given, is initialized to NaN (Not A Number):
double d; // d is set to double.nan
NaNs have the interesting property in that whenever a NaN is used as an operand in a computation, the result is a NaN. Therefore, NaNs will propagate and appear in the output whenever a computation made use of one. This implies that a NaN appearing in the output is an unambiguous indication of the use of an uninitialized variable.
If 0.0 was used as the default initializer for floating point values, its effect could easily be unnoticed in the output, and so if the default initializer was unintended, the bug may go unrecognized.
The default initializer value is not meant to be a useful value, it is meant to expose bugs. Nan fills that role well.
But surely the compiler can detect and issue an error message for variables used that are not initialized? Most of the time, it can, but not always, and what it can do is dependent on the sophistication of the compiler's internal data flow analysis. Hence, relying on such is unportable and unreliable.
Because of the way CPUs are designed, there is no NaN value for integers, so D uses 0 instead. It doesn't have the advantages of error detection that NaN has, but at least errors resulting from unintended default initializations will be consistent and therefore more debuggable.
Why Aren't All Digital Mars Programs Translated To D?
There is little benefit to translating a complex, debugged, working application from one language to another. But new Digital Mars apps are implemented in D.
When Should I Use A Foreach Loop Rather Than A For?
By using foreach, you are letting the compiler decide on the optimization rather than worrying about it yourself. For example - are pointers or indices better? Should I cache the termination condition or not? Should I rotate the loop or not? The answers to these questions are not easy, and can vary from machine to machine. Like register assignment, let the compiler do the optimization.
for (int i = 0; i < foo.length; i++)
or:
for (int i = 0; i < foo.length; ++i)
or:
for (T* p = &foo[0]; p < &foo[length]; p++)
or:
T* pend = &foo[length];
for (T* p = &foo[0]; p < pend; ++p)
or:
T* pend = &foo[length];
T* p = &foo[0];
if (p < pend)
{
do
{
...
} while (++p < pend);
}
and, of course, should I use size_t or int?
for (size_t i = 0; i < foo.length; i++)
Let the compiler pick!
foreach (v; foo)
...
Note that we don't even need to know what the type T needs to be, thus avoiding bugs when T changes. I don't even have to know if foo is an array, or an associative array, or a struct, or a collection class. This will also avoid the common fencepost bug:
for (int i = 0; i <= foo.length; i++)
And it also avoids the need to manually create a temporary if foo is a function call.
The only reason to use a for loop is if your loop does not fit in the conventional form, like if you want to change the termination condition on the fly.
Isn't Garbage Collection Slow And Non-deterministic?
Yes, but all dynamic memory management is slow and non-deterministic, including malloc/free. If you talk to the people who actually do real time software, they don't use malloc/free precisely because they are not deterministic. They preallocate all data. However, the use of GC instead of malloc enables advanced language constructs (especially, more powerful array syntax), which greatly reduce the number of memory allocations which need to be made. This can mean that GC is actually faster than explict management.
Can't A Sufficiently Smart Compiler Figure Out That A Function Is Pure Automatically?
The compiler infers purity (and safety, and nothrow) for delegate and function literals. It doesn't do this for normal functions for several reasons:
most functions call other functions, which call other functions, until one of them calls a library routine whose source is not available to the compiler. So it will have to assume it is not pure. With a pure function attribute, external library functions that are pure can be marked as pure, and then the analysis can work for enough cases to be useful.
Since virtual functions (and by extension delegates and function pointers) can be extended by the user at times the compiler won't see it, they have to be assumed to be impure.
If the programmer intends for a particular function to be pure and the compiler detects it is not, this may go unnoticed by the programmer. Even worse, if the programmer does notice it, it may be arbitrarily difficult to determine why the compiler thinks it is impure - is it a programming mistake or a compiler bug?
Why Allow Cast(float) If It Isn't Supposed To Work?
The floating point rules are such that transforming cast(real)cast(float) to cast(real) is a valid transformation. This is because the floating point rules are written with the following principle in mind:
An algorithm is invalid if it breaks if the floating point precision is increased. Floating point precision is always a minimum, not a maximum.
Programs that legitimately depended on maximum precision are:
compiler/library validation test suites
ones trying to programmatically test the precision
is not of value to user programming, and there are alternate ways to test the precision.
D has .properties that take care of that.
Programs that rely on a maximum accuracy need to be rethought and reengineered.
Why Can't Nested Functions Be Forward Referenced?
Declarations within a function are different from declarations at module scope. Within a function, initializers for variable declarations are guaranteed to run in sequential order. Allowing arbitrary forward references to nested functions would break this, because nested functions can reference any variables declared above them.
int first() { return second(); }
int x = first(); // x depends on y, which hasn't been declared yet.
int y = x + 1;
int second() { return y; }
But, forward references of nested functions are sometimes required (eg, for mutually recursive nested functions). The most general solution is to declare a local, nested struct. Any member functions (and variables!) of that struct have non-sequential semantics, so they can forward reference each other.
Why Does D Have Const?
People often express frustration with const and immutable in D 2.0 and wonder if it is worth it.
It makes function interfaces more self-documenting. Without transitive const, for all pointer/reference parameters one must rely on the documentation (which is always missing, out of date, or wrong). Note that without transitivity, C++ const is nearly useless for such self-documentation, which is why C++ programmers tend to rely on convention instead.
It makes for interfaces that can be relied upon, which becomes increasingly important the more people that are involved with the code. In other words, it scales very well. People who are involved with projects with large teams of programmers say that lack of const makes their lives difficult because they cannot rely on the compiler to enforce convention. The larger the team, the worse it gets. Managing APIs is critical to a large project - it's why BASIC doesn't scale (for an extreme example).
Const transitivity makes for some interesting optimization opportunities. The value of this has not been explored or exploited.
Here's the biggie. Points 1..3 are insignificant in comparison. The future of programming will be multicore, multithreaded. Languages that make it easy to program them will supplant languages that don't. Transitive const is key to bringing D into this paradigm. The surge in use of Haskell and Erlang is evidence of this coming trend (the killer feature of those languages is they make it easy to do multiprogramming). C++ cannot be retrofitted to supporting multiprogramming in a manner that makes it accessible. D isn't there yet, but it will be, and transitive const will be absolutely fundamental to making it work.
Of course, for writing single-threaded one man programs of fairly modest size, const is not particularly useful. And in D const can be effectively ignored by just not using it, or by using D 1.0. The only place const is imposed is with the immutable string type.
What Principles Drove The D Const Design?
It will be mathematically sound. That means there are no legal escapes from it.
Any type can be wrapped in a struct and the resulting struct can still exhibit the same const behavior - in other words, no magic behavior for certain types.
Const behavior will be transitive.
Const behavior for type T will be equivalent for all types T.
What Is Transitive Const?
Transitive const means that once const is applied to a type, it applies recursively to every sub-component of that type. Hence:
const(int*)** p;
p += 1; // ok, p is mutable
*p += 1; // ok, *p is mutable
**p += 1; // error, **p is const
***p += 1; // error, ***p is const
With transitivity, there is no way to have a const pointer to mutable int.
C++ const is not transitive.
What Is Head Const?
Head const is where the const applies only to the component of the type adjacent to the const.
For example:
headconst(int**) p;
would be read as p being a: const pointer to mutable pointer to mutable int. D does not have head const (the headconst is there just for illustrative purposes), but C++ const is a head const system.
What Is Tail Const?
Tail const is the complement of head const - everything reachable from the const type is also const except for the top level.
For example:
tailconst(int**) p;
would be read as p being a: mutable pointer to const pointer to const int. Head const combined with tail const yields transitive const. D doesn't have tailconst (the keyword is there just for illustrative purposes) as a distinct type constructor.
What Is Logical Const?
Logical const refers to data that appears to be constant to an observer, but is not actually const. An example would be an object that does lazy evaluation:
struct Foo
{
mutable int len;
mutable bool len_done;
const char* str;
int length()
{
if (!len_done)
{
len = strlen(str);
len_done = true;
}
return len;
}
this(char* str) { this.str = str; }
}
const Foo f = Foo("hello");
bar(f.length);
The example evaluates f.len only if it is needed. Foo is logically const, because to the observer of the object its return values never change after construction. The mutable qualifier says that even if an instance of Foo is const, those fields can still change. While C++ supports the notion of logical const, D does not, and D does not have a mutable qualifier.
The problem with logical const is that const is no longer transitive. Not being transitive means there is the potential for threading race conditions, and there is no way to determine if an opaque const type has mutable members or not.
Why Not Use Readonly To Mean Read Only View?
Readonly has a well established meaning in software to mean ROM, or Read Only Memory that can never be changed. For computers with hardware protection for memory pages, readonly also means that the memory contents cannot be altered. Using readonly in D to mean a read only view of memory that could be altered by another alias or thread runs counter to this.
How Does Const Differ In C++?
C++ has a const system that is closer to D's than any other language, but it still has huge differences:
const is not transitive
no immutables
const objects can have mutable members
const can be legally cast away and the data modified
const T and T are not always distinct types
Why Aren't Function Parameters Const By Default?
Since most (nearly all?) function parameters will not be modified, it would seem to make sense to make them all const by default, and one would have to specifically mark as mutable those that would be changed. The problems with this are:
1. It would be a huge break from past D practice, and practice in C, C++, Java, C#, etc.
2. It would require a new keyword, say mutable.
3. And worst, it would make declarations inconsistent:
4. void foo(int* p)
5. {
6. int* q;
7. ...
8. }
p points to const, and q points to mutable. This kind of inconsistency leads to all sorts of mistakes. It also makes it very hard to write generic code that deals with types.
Using in can mitigate the ugliness of having to annotate with const:
void str_replace(in char[] haystack, in char[] needle);
Are Static Class Members Covered By Transitive Const?
A static class member is part of the global state of a program, not part of the state of an object. Thus, a class having a mutable static member does not violate the transitive constness of an object of that class.
Why Doesn't D Have An Interface To C++ As Well As C?
Here are some reasons why it isn't a full interface:
Attempting to have D interface with C++ is nearly as complicated as writing a C++ compiler, which would destroy the goal of having D be a reasonably easy language to implement. For people with an existing C++ code base that they must work with, they are stuck with C++ (they can't move it to any other language, either).
There are many issues that would have to be resolved in order for D code to call some arbitrary C++ code that is presumed to be unmodifiable. This list certainly isn't complete, it's just to show the scope of the difficulties involved.
D source code is unicode, C++'s is ASCII with code pages. Or not. It's unspecified. This impacts the contents of string literals.
std::string cannot deal with multibyte UTF.
C++ has a tag name space. D does not. Some sort of renaming would have to happen.
C++ code often relies on compiler specific extensions.
C++ has namespaces. D has modules. There is no obvious mapping between the two.
C++ views source code as one gigantic file (after preprocessing). D sees source code as a hierarchy of modules and packages.
Enum name scoping rules behave differently.
C++ code, despite decades of attempts to replace macro features with inbuilt ones, relies more heavily than ever on layer after layer of arbitrary macros. D does not always have an analog for token pasting and stringizing.
Macro names have global scope across #include files, but are local to the gigantic source files.
C++ has arbitrary multiple inheritance and virtual base classes. D does not.
C++ does not distinguish between in, out and ref (i.e. inout) parameters.
The C++ name mangling varies from compiler to compiler.
C++ throws exceptions of arbitrary type, not just descendants of Object.
C++ overloads based on const and volatile. D overloads based on const and immutable.
C++ overloads operators in significantly different ways - for example, operator[]() overloading for lvalue and rvalue is based on const overloading and a proxy class.
C++ overloads operators like < completely independently of >.
C++ does not distinguish between a class and a struct object.
The vtbl[] location and layout is different between C++ and D.
The way RTTI is done is completely different. C++ has no classinfo.
D does not have two phase lookup, nor does it have Koenig (ADL) lookup.
C++ relates classes with the 'friend' system, D uses packages and modules.
C++ class design tends to revolve around explicit memory allocation issues, D's do not.
D's template system is very different.
C++ has 'exception specifications'.
C++ has global operator overloading.
C++ name mangling depends on const and volatile being type modifiers. D name mangling depends on const and immutable being type modifiers. D's const is also transitive, unlike C++. One cannot have a const pointer to mutable in D.
The bottom line is the language features affect the design of the code. C++ designs just don't fit with D. Even if you could find a way to automatically adapt between the two, the result will be about as enticing as the left side of a honda welded to the right side of a camaro.
Why Doesn't D Use Reference Counting For Garbage Collection?
Reference counting has its advantages, but some severe disadvantages:
Cyclical data structures won't get freed.
Every pointer copy requires an increment and a corresponding decrement - including when simply passing a reference to a function.
In a multithreaded app, the incs and decs must be synchronized.
Exception handlers (finally blocks) must be inserted to handle all the decs so there are no leaks. Contrary to assertions otherwise, there is no such thing as "zero overhead exceptions."
In order to support slicing and interior pointers, as well as supporting reference counting on arbitrary allocations of non-object data, a separate "wrapper" object must be allocated for each allocation to be ref counted. This essentially doubles the number of allocations needed.
The wrapper object will mean that all pointers will need to be double-dereferenced to access the data.
Fixing the compiler to hide all this stuff from the programmer will make it difficult to interface cleanly with C.
Ref counting can fragment the heap thereby consuming more memory just like the gc can, though the gc typically will consume more memory overall.
Ref counting does not eliminate latency problems, it just reduces them.
The proposed C++ shared_ptr<>, which implements ref counting, suffers from all these faults. I haven't seen a heads up benchmark of shared_ptr<> vs mark/sweep, but I wouldn't be surprised if shared_ptr<> turned out to be a significant loser in terms of both performance and memory consumption.
That said, D may in the future optionally support some form of ref counting, as rc is better for managing scarce resources like file handles. Furthermore, if ref counting is a must, Phobos has the std.typecons.RefCounted type which implements it as a library, similar to C++'s shared_ptr<>.
Post a Comment