Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Introducing the D Programming Language
#1
[] 
"D is a systems programming language with C-like syntax and static typing. It combines efficiency, control and modeling power with safety and programmer productivity"
-dlang.org

First, let me tell you how I stumbled upon D language: I was upset by how C# source code can be retained from it's executable (or DLL) no matter if you use obfuscators and such. I was thinking why is it that much hard to interact with native APIs and being unable to do some low level stuff in C# was not fun. There was few other things I had in mind wondering why can't there be that kind of language... I tried my best to like C++, I really did. No matter how much I tell myself it's not that bad, I gave up. It's unnecessarily complicated with no win. So I started to look for some C like language that can handle anything from low level to high level, have an optional GC, feature rich, and plays well with other languages. After weeks of searching, I said to myself "I bet there is a language called D" and I googled "d programming language". First result was the dlang.org. When I clicked on it, I was no longer thinking about creating my own language. It was there, it was D.

Module system
No painful header file sh*t. There is no confusion of declaration and definition, order of signatures don't have a side effect, and no need for maintaining two different signatures. Yet, D supports separate compilation in a much cleaner way than C/C++.
Modules are simple:
    D-Code:
module drone.algorithm;
int[] quickSort(int[] data)
{
    //Implementation...
}

Doing something similar to above will require you to name your file "algorithm.d" and put it in a directory called "drone". This way you're forced to do the right thing. Doing so makes other people to figure out your code easier and it makes the project more manageable in the long run.
Here is how one can use modules:
    D-Code:
module program;
import drone.algorithm : quickSort; //import only the required function
import stdio = std.stdio; //renamed import can help not to pollute global scope
import std.algorithm; //just simply import
void main(string[] args)
{
    import std.conv : to; //scoped imports will only available in the function scope
    foreach(e; quickSort(args.map!(a => a.to!int)))
        stdio.writeln(e);
}


Compile times
The official reference compiler DMD is incredibly fast. One reason is not having any preprocessor (hence the module system), the other one is Walter Bright's outstanding optimization skills. DMD doesn't usually produce highly optimized/fast code, it produce it fast. Thus, compile-run-test cycle becomes satisfying. Many C++ guys expect a compiler error in their first D code compilation but get surprised that it's successfully compiled at such speed. There are also LDC (LLVM based D compiler) and GDC (GCC based D compiler) which compiles slower but produces strongly optimized binaries.

Slices
A slice in D seems like a dynamic array in almost all aspects of the concept -- when passed without adornments, the data referred to is passed by reference, and it supports all the properties and functions one would expect a dynamic array type to support. But there is one very important difference. A slice does not own the array, it references the array. That is, the slice is not responsible for allocation or deallocation of its data. The responsible party for managing a dynamic array's memory is the D runtime.

So where is the true dynamic array type in D? It's hidden by the runtime, and in fact, has no formal type. Slices are good enough, and as it turns out, the runtime is smart enough about what you want to do with the data, that you almost never notice dynamic arrays are missing as a full-fledged type. In fact, most D coders consider the D slice to be the dynamic array type -- it's even listed as a dynamic array type in the spec!

With the combined protection of having the length of the data, and the garbage collector to manage the memory backing the data, slices are an extremely powerful, dynamic concept that is safe from most memory corruption issues. With D slices, one can write high-performance code with elegant and concise syntax that is awkward or inefficient in almost any other language.

Let's see some D slices in action:
    D-Code:
import std.stdio;
void main()
{
    int[] a; // a is a slice
    a = new int[5]; // allocate a dynamic array of integers that has at least 5 elements, and give me a slice to the first 5. Note that all data in D is default assigned, int's are defaulted to 0, so this array contains five 0's
    int[] b = a[0..2]; // This is a 'slicing' operation. b now refers to the first two elements of a. Note that D uses open interval for the upper limit, so a[2] is not included in b.
    int[] c = a[$-2..$]; // c refers to the last two elements of a ($ stands for length inside a slice or index operation).
    c[0] = 4; // this also assigns a[3]
    c[1] = 5; // this also assigns a[4]
    b[] = c[]; // assign the first two elements of a[] to the value from the last two elements (4, 5).
    writeln(a); // prints "[4, 5, 0, 4, 5]"
    int[5] d; // d is a fixed sized array, allocated on the stack
    b = d[0..2]; // slices can point at fixed sized arrays too!
}

reference: D Array Article

Here is an advanced LF2 data parser (tokenizer) I wrote a while ago, it runs blazingly fast because no string copying takes place:
    D-Code:
import std.stdio : File;
import std.traits : isSomeString, isArray;
import std.range : isInfinite, isIterable, isInputRange;
import std.string : startsWith;
 
enum TokenState : ubyte
{
	none,
	xml,
	token,
	comment
}
 
enum TokenType : ubyte
{
	normal,
	xml,
	property,
}
 
struct Token(S) if(isSomeString!S)
{
	S str;
	size_t line, col;
	TokenType type;
	bool commentic;
 
	string toString()
	{
		return format(`"%s"[line: %d col: %d]  `, str, line, col);
	}
}
 
immutable string tokenHeads = ['<'], tokenEnds = ['>', ':'], tokenDelims = [' ', '\t'], 
	lineEnds = ['\n', '\r'];
enum char lineCommentChar = '#';
 
class ParserException : Exception
{
	this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) @(safe, nogc) pure nothrow
	{
		super(msg, file, line, next);
	}
}
 
/// This function tokenizes LF2 data and returns a slice-array of strings. Returned slices point to the given string.
public Token!S[] parseData(S)(S data, bool includeComments = false) if(isSomeString!S)
{
	debug(LogFile)
	{
		File parserLog = File("parser.log", "wb");
		scope(exit) parserLog.close();
	}
	Token!S[] slices = new Token!S[4];
	slices.reserve(data.length / 5); // Pre-allocate an aprox memory we might need
 
	bool commentness = false;
	TokenState state = TokenState.none;
	size_t tokenStart = 0, tokenCol = 1, tokenLine = 1, line = 1, col = 1;
Lforeach:
	foreach(i, ch; data)
	{
	Lswitch:
		final switch(state)
		{
			case TokenState.none:
				if(lineEnds.canFind(ch))
				{
					commentness = false;
					break Lswitch;
				}
				else if(tokenDelims.canFind(ch))
				{
					break Lswitch;
				}
				else if(tokenHeads.canFind(ch)) // <
				{
					state = TokenState.xml;
					tokenStart = i;
					tokenCol = col;
					tokenLine = line;
				}
				else if(tokenEnds.canFind(ch)) // > :
				{
					throw new ParserException(format("Unexpected token ending delimeter: '%c' in line: %d; at col: %d", ch, line, col));
				}
				else if(ch == lineCommentChar) // #
				{
					commentness = true;
				    if(!includeComments)
						state = TokenState.comment;
				}
				else
				{
					state = TokenState.token;
					tokenStart = i;
					tokenCol = col;
					tokenLine = line;
				}
				break Lswitch;
			case TokenState.xml:
				if(lineEnds.canFind(ch))
				{
					throw new ParserException(format("Unexpected line ending in line %d; at col %d", line, col));
				}
				else if(tokenDelims.canFind(ch))
				{
					throw new ParserException(format("Unexpected token delimeter in line %d; at col %d", line, col));
				}
				else if(tokenHeads.canFind(ch)) // <
				{
					throw new ParserException(format("Unexpected token beginning delimeter '%c' in line %d; at col %d", ch, line, col));
				}
				else if(tokenEnds[0] == ch) // >
				{
					slices ~= Token!S(data[tokenStart .. i + 1], tokenLine, tokenCol, TokenType.xml, commentness);
					state = TokenState.none;
				}
				else if(tokenEnds[1] == ch) // :
				{
					throw new ParserException(format("Unexpected token ending delimeter '%c' in line %d; at col %d", ch, line, col));
				}
				else if(ch == lineCommentChar) // #
				{
					commentness = true;
					if(!includeComments)
						throw new ParserException(format("Unexpected comment char '%c' in line %d; at col %d", ch, line, col));
				}
				break Lswitch;
			case TokenState.token:
				if(lineEnds.canFind(ch))
				{
					slices ~= Token!S(data[tokenStart .. i], tokenLine, tokenCol, TokenType.normal, commentness);
					state = TokenState.none;
					commentness = false;
				}
				else if(tokenDelims.canFind(ch))
				{
					slices ~= Token!S(data[tokenStart .. i], tokenLine, tokenCol, TokenType.normal, commentness);
					state = TokenState.none;
				}
				else if(tokenHeads.canFind(ch)) // <
				{
					slices ~= Token!S(data[tokenStart .. i], tokenLine, tokenCol, TokenType.normal, commentness);
					state = TokenState.xml;
					tokenStart = i;
				}
				else if(ch == tokenEnds[0]) // >
				{
					throw new ParserException(format("Unexpected token ending delimeter '%c' in line %d; at col %d", ch, line, col));
				}
				else if(ch == tokenEnds[1]) // :
				{
					slices ~= Token!S(data[tokenStart .. i + 1], tokenLine, tokenCol, TokenType.property, commentness);
					state = TokenState.none;
				}
				else if(ch == lineCommentChar) // #
				{
					commentness = true;
					if(!includeComments)
					{
						slices ~= Token!S(data[tokenStart .. i + 1], tokenLine, tokenCol, TokenType.normal, commentness);
						state = TokenState.comment;
					}
				}
				break Lswitch;
			case TokenState.comment:
				if(lineEnds.canFind(ch))
				{
					commentness = true;
					state = TokenState.none;
				}
				break Lswitch;
		}
		if(ch == '\n')
		{
			line++;
			col = 1;
		}
		else
			col++;
	}
	switch(state)
	{
		case TokenState.token:
			slices ~= Token!S(data[tokenStart .. $], tokenLine, tokenCol, TokenType.normal, commentness);
			break;
		case TokenState.xml:
			throw new ParserException(format("Reached end of file unexpectedly while parsing token \"%s\" in line %d; at col %d", data[tokenStart .. $], line, col));
		default:
			break;
	}
	debug(LogFile)
	{
		size_t ln = 1;
		foreach(t; slices)
		{
			if(ln < t.line)
			{
				parserLog.write("\r\n", t.toString);
				ln = t.line;
			}
			else
				parserLog.write(t.toString);
		}
		parserLog.writeln("\r\n");
		parserLog.close();
	}
 
	return slices;
}



Compile time function evaluation
This will describe the basics of a very powerful feature of the D programming language: the Compile-time Function Execution (CTFE), which allows complicated functions to be fully evaluated at compile-time, irrespective of the optimization levels.

C optimizations
If you are an average C programmer, you know that simple code can be trusted to be evaluated at compile-time thanks to optimizers. For instance, if you write something like:
    C-Code:
void square(int x) { return x * x; }
void foo(void)
{
    int k = square(32);
    /* ... */
}

You trust your compiler to evaluate the square at compile-time, when optimizations are on. When things get more hairy:
    C-Code:
int factorial(int x)
{
    int result = x;
    while (--x)
        result *= x;
    return result;
}
void foo(void)
{
    int k = factorial(8);
    /* ... */
}

C programmers get immediately less confident about what will happen at run-time. For instance, would you say that your compiler is able to expand the above code at compile-time or not? Actually, the answer is “yes” in this particular case (unless you are using a very old compiler), but the point is still valid: this is not C code that one would write if he wants to be sure that the whole calculation be folded at compile-time.

There is also another issue: since the language does not mandate that the value is folded (and in fact, it is not folded when optimizations are disabled), you cannot create a constant out of it, such as by assigning it to a const variable.

When things get hairy
Now, let’s try with a (very naive and simple) solution of problem #1 of Project Euler:
    C-Code:
#include <stdio.h>
int euler1(int max)
{
    int i, res = 0;
    for (i = 1; i < max; i++)
    {
        if ((i % 3) == 0 || (i % 5) == 0)
            res += i;
    }
    return res;
}
int main()
{
    int r10 = euler1(10);
    int r1000 = euler1(1000);
    printf("%d %d\n", r10, r1000);
    return 0;
}

This program simply calculates the sum of all divisors of 3 or 5 below 1000. But if you look at the generated code with GCC under -O3, you will see that the actual results are not computed at compile-time, but rather calculated at runtime. I believe any average C programmer would agree that we should not expect this code to be folded at compile time.

Now, meet the equivalent D code:
    D-Code:
int euler1(int max)
{
    int i, res = 0;
    for (i = 1; i < max; i++)
    {
        if ((i % 3) == 0 || (i % 5) == 0)
            res += i;
    }
    return res;
}
int main()
{
    int r10 = euler1(10);
    int r1000 = euler1(1000);
    printf("%d %d\n", r10, r1000);
    return 0;
}

Deja-vu? Yes, it is exactly the same, barring the initial include statement that is not required (actually, there is no preprocessor in D and modules refer to each other with the import statement, but printf is a builtin). Of course, the above example was hand-crafted to make it both valid C and D code, but being D an evolution of C, the basic syntax is the same.

Meet CTFE
And now the hattrick: in D, we can request the compiler to evaluate euler1 at compile-time by simply using the static keyword at invocation time:
    D-Code:
static int r10 = euler1(10);
static int r1000 = euler1(1000);

Great, isn’t it? Now the result of the above function call are evaluated by the compiler, irrespective of the optimization levels. If the function cannot be evaluated at compile-time (usually because it has side-effects, like any kind of I/O), it will trigger a compile-time error.

We can verify that the above constants really do appear in the generated code by compiling with gdc -save-temps euler1.d and then inspecting euler1.s:
    ASM-Code:
D6euler14mainFZi3r10i:
    .long 23
.globl _D6euler14mainFZi5r1000i
    .align 4
    .type _D6euler14mainFZi5r1000i, @ object
    .size _D6euler14mainFZi5r1000i, 4
_D6euler14mainFZi5r1000i:
    .long 233168
    .section .rodata
.LC0:
    .string "%d %d\n"
    .text
    .globl _Dmain
    .type _Dmain, @ function
_Dmain:
.LFB3:
    pushq %rbp
.LCFI3:
    movq %rsp, %rbp
.LCFI4:
    movl _D6euler14mainFZi5r1000i(%rip), %edx
    movl _D6euler14mainFZi3r10i(%rip), %esi
    movl $.LC0, %edi
    movl $0, %eax
    call printf
    movl $0, %eax
    leave
    ret

Notice how the compiler has calculated the values 23 and 233168 (respectively, results of euler1(10) and euler1(1000)) and put them in the data section of the executable.

If you are curious of what happens when the compiler cannot do the whole evaluation at compile-time, it is sufficient to stick a printf() call somewhere in the euler() function. Since printf() does some I/O, it breaks CFTE, and the compiler will happily tell you about that:
Code:
euler1.d:9: Error: cannot evaluate printf("hello, world!\x0a") at compile time euler1.d:15: Error: cannot evaluate euler1(10) at compile time euler1.d:16: Error: cannot evaluate euler1(1000) at compile time

CTFE is simple yet very powerful. The fact that it is triggered at the call site (rather than being an attribute of the function, like the inline keyword) is a very smart design choice: it makes perfectly sense for the same function to be used at both run-time and compile-time, depending on the inputs.

For the C++ guys reading, C++0x has grown a constexpr keyword that, while looking superficially similar, it is a lot less powerful, since it can only be used on very simple functions (basically, one-liners). In fact, the keyword is meant to be used while declaring a function, and not at the call-site, so it has to apply only on small functions which can be proved to always yield a constant value.


origin: Compile Time Function Execution in D


Templates, Meta-programming, mixins, and CTFE combination
Meta-programming in D is extremely powerful, yet easy to use and understand at the same time.
Writing a generic code that works with any type is dead simple:
    D-Code:
T[] quickSort(T)(T[] array) //template function with type argument T
{
    //implementation...
}
struct RefCounted(T : struct)
{
    T* data;
    size_t rc = 0;
    void inc() { rc++; }
    void dec()
    {
        rc--;
        if(rc <= 0)
            destroy(*data);
    }
    //...
}

Imagine the possibilities:
    D-Code:
import std.stdio;
import std.traits;
import std.conv, std.algorithm, std.array, std.string;
import std.datetime;
 
public struct XmlIgnore { public bool ignore = true; }
 
public struct ComplexTestStruct {
@(XmlIgnore(false))
  int myint;
@(XmlIgnore(true))
  double precision;
@(XmlIgnore)
  Duration thetime;
  bool truth;
  string[string] properties
}
 
void main()
{
    auto data = ComplexTestStruct(50, 0.4, dur!"msecs"(100), true, ["one":"first", "two":"second"]);
    writeXml(data);
}
 
public void writeXml(T)(T obj, int indentLevel = 0, string name = null)
{
	writeIndented(indentLevel, "<", name == null ? T.stringof : name, ">\n");
	foreach(mem; FieldNameTuple!T)
	{
		const string mix = "obj." ~ mem;
		static if(!hasUDA!(mixin(mix), XmlIgnore) || (!hasUDA!(mixin(mix), XmlIgnore(true))))
		{
			const string typeStr = typeof(mixin(mix)).stringof;
			auto var = mixin(mix);
			static if(__traits(isScalar, var))
			{
				writeIndented(indentLevel + 1, "<", mem, ">", var, "</", mem, ">\n");
			}
			else static if(__traits(isAssociativeArray, var))
			{
				writeIndented(indentLevel + 1, "<", mem, ">\n");
				foreach(key, val; var)
					writeIndented(indentLevel + 2, "<", key, ">", val, "</", key, ">\n");
				writeIndented(indentLevel + 1, "</", mem, ">\n");
			}
			else static if(isArray!(typeof(var)) && !isSomeString!(typeof(var)))
			{
				const string arrayElementTypeStr = typeof(var[0]).stringof;
				static if(isBuiltinType!(typeof(var[0])))
				{
					//writeln(arrayElementTypeStr);
					writeIndented(indentLevel + 1, "<", mem, ">\n");
					foreach(val; var)
						writeIndented(indentLevel + 2, "<", arrayElementTypeStr, ">", val, "</", arrayElementTypeStr, ">\n");
					writeIndented(indentLevel + 1, "</", mem, ">\n");
				}
				else
				{
					//writeln(arrayElementTypeStr);
					writeIndented(indentLevel + 1, "<", mem, ">\n");
					foreach(val; var)
						writeXml(val, indentLevel + 2);
					writeIndented(indentLevel + 1, "</", mem, ">\n");
				}
			}
			else static if(is(typeof(var) == struct) || is(typeof(var) == class) || is(typeof(var) == interface))
			{
				writeXml(var, indentLevel + 1, mem);
			}
			else if(__traits(compiles, to!string(var)))
			{
				//writeln(typeStr);
				writeIndented(indentLevel + 1, "<", mem, ">", to!string(var), "</", mem, ">\n");
			}
			else
			{
				//writeln(typeStr);
				writeIndented(indentLevel + 1, "<", mem, ">", var, "</", mem, ">\n");
			}
		}
	}
	writeIndented(indentLevel, "</", name == null ? T.stringof : name, ">\n");
}
 
private void writeIndented(T...)(int level, T text)
{
	makeIndent(level);
	write(text);
}
 
private void makeIndent(int level)
{
	for(int i = 0; i < level; i++)
		write("  ");
}



As this post turned out to be too long, you can ask me to elaborate on things you couldn't understand.

Have a nice day...
Ultimately, my constant dissatisfaction with the way things are becomes the driving force behind everything I do.
[Image: sigline.png]
LF2 IDE - Advanced visual data changer featuring instant data loader
LF2 Sprite Sheet Generator - Template based sprite sheet generator based on Gad's method
[Image: sigline.png]
There is no perfect language, but C++ is the worst.
Reply
Thanks given by: A-Man , MangaD , kairunotabi
#2
Are the "!" in
(e; quickSort(args.map!(a => a.to!int)))
not typos O_o?

I like the slices, though if they were going with a notation similar to that of day to day mathematics, it'd have been great if they made the range inclusive since both brackets are closed. Also, if assigning a variable to a slice still only reference, how do you copy an array then? with a method?

I don't know why use "static" as a keyword for compile time evaluation though. What do you do for static class/struct members?

Also about constexpr only being able to contains a single expression, check this out :P.

Do we have pointers also (I am not saying I want them, just asking)?

Anyway, it looks quite nice. But it's more than just the language semantics and design that makes it; There is also the community, resources, support..etc. It really sucks that languages like C# always have to wait a while to try out stuff like Vulkan.
[Image: signature.png]
A-Engine: A new beat em up game engine inspired by LF2. Coming soon

A-Engine Dev Blog - Update #8: Timeout

Reply
Thanks given by:
#3
(03-06-2016, 03:19 PM)A-Man Wrote:  Are the "!" in
(e; quickSort(args.map!(a => a.to!int)))
not typos O_o?
Actually not. 'map' is a template function that takes a delegate template parameter (lambda, function... anything that you can call), this makes function inlining optimizations possible. This is how you call a template function:
    D-Code:
T[] quickSort(T)(T[] arr)
{
    //...
}
//...
float[] arr = [5.2f, 3.0f, 2.0f, 12.7f, 55.0f];
quickSort!(float)(arr);
quickSort(arr); //same: compiler can deduce type automatically


(03-06-2016, 03:19 PM)A-Man Wrote:  I like the slices, though if they were going with a notation similar to that of day to day mathematics, it'd have been great if they made the range inclusive since both brackets are closed. Also, if assigning a variable to a slice still only reference, how do you copy an array then? with a method?
Making range non-inclusive makes perfect sense and it actually make things easier, it's more consistence this way believe me.
I think you misunderstood slices, but array copying is dead simple:
    D-Code:
auto newArray = array.dup(); //duplicate
newArray[0] = 5; //doesn't affect 'array'


(03-06-2016, 03:19 PM)A-Man Wrote:  I don't know why use "static" as a keyword for compile time evaluation though. What do you do for static class/struct members?
You're missing the point, static is not reserved for CTFE in anyway. A static variable cannot be initialized with a function call in C actually, compiler will complain that it needs a constant value meanwhile you gave him an expression (function call) because of the nature of a static variable. *Note that we're talking about static variables in functions, not static members of classes or whatever.*
So when you use static keyword compiler thinks you want that to be evaluated at compile time because a static variable can only be initialized with a constant value. It can also be achieved with 'const' keyword.

(03-06-2016, 03:19 PM)A-Man Wrote:  Also about constexpr only being able to contains a single expression, check this out :P.
CTFE is getting too powerful

(03-06-2016, 03:19 PM)A-Man Wrote:  Do we have pointers also (I am not saying I want them, just asking)?
Of course we have. It's a systems programming language dude...

(03-06-2016, 03:19 PM)A-Man Wrote:  Anyway, it looks quite nice. But it's more than just the language semantics and design that makes it; There is also the community, resources, support..etc. It really sucks that languages like C# always have to wait a while to try out stuff like Vulkan.
I don't understand what you mean by that.
Ultimately, my constant dissatisfaction with the way things are becomes the driving force behind everything I do.
[Image: sigline.png]
LF2 IDE - Advanced visual data changer featuring instant data loader
LF2 Sprite Sheet Generator - Template based sprite sheet generator based on Gad's method
[Image: sigline.png]
There is no perfect language, but C++ is the worst.
Reply
Thanks given by:
#4
(03-06-2016, 03:19 PM)A-Man Wrote:  Are the "!" in
(e; quickSort(args.map!(a => a.to!int)))
not typos O_o?
No. It is D's way to express template arguments.
stuff!int();
in D is equivalent to
stuff<int>();
in C++.

(03-06-2016, 03:19 PM)A-Man Wrote:  I like the slices, though if they were going with a notation similar to that of day to day mathematics, it'd have been great if they made the range inclusive since both brackets are closed. Also, if assigning a variable to a slice still only reference, how do you copy an array then? with a method?
The square brackets are for array indexing. The problem with closed ranges is that you cannot represent an empty range generally.

(03-06-2016, 03:19 PM)A-Man Wrote:  I don't know why use "static" as a keyword for compile time evaluation though. What do you do for static class/struct members?
Because @Nightmarex1337 is mistaken (or at least not wholly accurate).
static
means static lifetime, which in this case is the same as in C++, but D just has the rule that such variables must be initialized with a constant expression. If you use this in a function, on a variable you modify you will get unexpected results. If you do not plan to modify the variable it is equivalent to making the variable
constexpr
in C++.

(03-06-2016, 03:19 PM)A-Man Wrote:  Do we have pointers also (I am not saying I want them, just asking)?
Yes.

(03-06-2016, 03:19 PM)A-Man Wrote:  Anyway, it looks quite nice. But it's more than just the language semantics and design that makes it; There is also the community, resources, support..etc. It really sucks that languages like C# always have to wait a while to try out stuff like Vulkan.
You can, even in C#, though you will have to tell the language what the interface is, it is not hard just tedious. With D my guess is it would be less painful though since it has much more in common with C and C++ than C# has.

@Nightmarex1337
My main reason for not jumping on the D-ship is:
  1. I dislike a lot of the syntax in D, particularly the syntax for templates. Say what you will about angle bracket syntax in C++, but it is distinct and easily recognizable. I find particularly function template declarations in D are ugly.
  2. D has garbage collection. And you cannot go near it without being contaminated by the radiation unless you are separated by 1 meter wall of concrete in every direction, and I would rather avoid having concrete in my programs.
  3. Differentiation between value and reference types in the core language. In fact I have never seen a good reason for reference types, but even if such a case exists (which I sure hope it does or it shows a very negative tendency in a lot of popular programming languages) it should not be implemented in the core language, but as a library feature.
  4. Lack of experience with D. C++ has a lot of weird quirks, but I have learned what they are and how to avoid them, to a point where I practically never run into them. I do not know about any of the quirks in D and learning about them when I have a perfectly good alternative is not going to happen without another really good incentive, and on top of that I also do not know how to write simple things in D like variadic template value parameters, which is a rather nice thing to know how to do.
Age ratings for movies and games (and similar) have never been a good idea.
One can learn a lot from reinventing wheels.
An unsound argument is not the same as an invalid one.
volatile in C++ does not mean thread-safe.
Do not make APIs unnecessarily asynchronous.
Make C++ operator > again
Trump is an idiot.
Reply
Thanks given by:
#5
NX Wrote:I think you misunderstood slices, but array copying is dead simple
Python has slicing and will reference when you assign an array. But slicing would always do a deep copy, so I thought that's how it'd work too here. But .dup() works well too.

NX Wrote:You're missing the point, static is not reserved for CTFE in anyway ... also be achieved with 'const' keyword.
SomeoneElse Wrote:Because @Nightmarex1337 is ... in C++.
I see. So I understand things gets implicitly declared for CTFE? I am not sure, this link NX gave is of a forum thread in which the first post links to an issue posted on stack overflow that shows how hideous this can become.

NX Wrote:I don't understand what you mean by that.
I mean there are also other factors one should consider when comparing a language to another. I named Vulkan as an example for an API which came available natively on C and not other languages. Other languages one generally need to wait for wrappers and ports or write them on their own. Also, most of the questions/pitholes of C/C++, if not all, have already been asked at least once on the internet for you to find when you're stumbled. That's probably not true for D however, with which you're to expect a less active community supporting it.
[Image: signature.png]
A-Engine: A new beat em up game engine inspired by LF2. Coming soon

A-Engine Dev Blog - Update #8: Timeout

Reply
Thanks given by:
#6
(03-06-2016, 05:17 PM)Someone else Wrote:  Because @Nightmarex1337 is mistaken (or at least not wholly accurate).
static
means static lifetime, which in this case is the same as in C++, but D just has the rule that such variables must be initialized with a constant expression. If you use this in a function, on a variable you modify you will get unexpected results. If you do not plan to modify the variable it is equivalent to making the variable
constexpr
in C++.
I'm not mistaken here. Try to initialize a static variable with a return value of a function in C and you will be suprized.


(03-06-2016, 05:17 PM)Someone else Wrote:  I dislike a lot of the syntax in D, particularly the syntax for templates. Say what you will about angle bracket syntax in C++, but it is distinct and easily recognizable. I find particularly function template declarations in D are ugly.
This is ironic that you tell me D templates look ugly and keep coding in C++.

(03-06-2016, 05:17 PM)Someone else Wrote:  D has garbage collection. And you cannot go near it without being contaminated by the radiation unless you are separated by 1 meter wall of concrete in every direction, and I would rather avoid having concrete in my programs.
D gives you fine-grained control over it's garbage collector. In fact, you can totally avoid it and use malloc / free instead. std.experimental.allocator package contains allocator abstractions for different memory management strategies. You can use std.typecons.Unique and std.typecons.RefCounted for deterministic resource management. There are GC independent standard library forks around. D language is a pragmatic tool that becomes what you want it to be. Stop complaining, start experimenting.

(03-06-2016, 05:17 PM)Someone else Wrote:  Differentiation between value and reference types in the core language. In fact I have never seen a good reason for reference types, but even if such a case exists (which I sure hope it does or it shows a very negative tendency in a lot of popular programming languages) it should not be implemented in the core language, but as a library feature.
I never dealt with value type classes but I guess reference types make things easier for both users and compiler writers.

(03-06-2016, 05:17 PM)Someone else Wrote:  Lack of experience with D. C++ has a lot of weird quirks, but I have learned what they are and how to avoid them, to a point where I practically never run into them. I do not know about any of the quirks in D and learning about them when I have a perfectly good alternative is not going to happen without another really good incentive, and on top of that I also do not know how to write simple things in D like variadic template value parameters, which is a rather nice thing to know how to do.
This is not a valid argument of not using a language. Of course, I'm more familiar with C# and I can just use it instead but it's more fun to discover new things. There are way less quirks in D than those exist in C++.
Variadic template function can be written as such:
    D-Code:
void write(Args...)(Args args) if(args.length >0)
{
    writeln(args.length, '\t', args[0]);
    foreach(i, arg; args)
        writeln('[', i, ']', typeof(arg).stringof, ' ', arg);
}


(03-06-2016, 03:19 PM)A-Man Wrote:  I see. So I understand things gets implicitly declared for CTFE? I am not sure, this link NX gave is of a forum thread in which the first post links to an issue posted on stack overflow that shows how hideous this can become.
Ohh great. Did I told you how hideous C++ can become?

(03-06-2016, 03:19 PM)A-Man Wrote:  
NX Wrote:I don't understand what you mean by that.
I mean there are also other factors one should consider when comparing a language to another. I named Vulkan as an example for an API which came available natively on C and not other languages. Other languages one generally need to wait for wrappers and ports or write them on their own. Also, most of the questions/pitholes of C/C++, if not all, have already been asked at least once on the internet for you to find when you're stumbled. That's probably not true for D however, with which you're to expect a less active community supporting it.
I don't think your example worth discussing (no offense), but I find D community to be surprisingly active. Yes, it's a small community, but really active.
Ultimately, my constant dissatisfaction with the way things are becomes the driving force behind everything I do.
[Image: sigline.png]
LF2 IDE - Advanced visual data changer featuring instant data loader
LF2 Sprite Sheet Generator - Template based sprite sheet generator based on Gad's method
[Image: sigline.png]
There is no perfect language, but C++ is the worst.
Reply
Thanks given by:
#7
list<list<list<float>>>
vs
list!(list!(list!int))

The former looks clearer to me.

NX Wrote:Ohh great. Did I told you how hideous C++ can become?
Not in that way. C/C++ are explicit with pretty much all they do (leave alone auto and decltype stuff), which I like.

NX Wrote:
SomeoneElse Wrote:Lack of experience with D. ...
This is not a valid argument of not using a language. ...
How is it not? If both D and C++ serve for the same purpose, and especially if I believe what I use is better suited for myself, I should not be forced to use D (applies to any other language to be used over another).

Quote:I don't think your example worth discussing (no offense), but I find D community to be surprisingly active. Yes, it's a small community, but really active.
I am not sure what would be worth discussing then. You keep arguing against C++ (or C, it hasn't been clear lately) with complaints about things like design. Things which are largely subjective and depends on what the user has gotten used to.
[Image: signature.png]
A-Engine: A new beat em up game engine inspired by LF2. Coming soon

A-Engine Dev Blog - Update #8: Timeout

Reply
Thanks given by:
#8
(03-07-2016, 06:14 AM)A-Man Wrote:  
list<list<list<float>>>
vs
list!(list!(list!int))

The former looks clearer to me.
It's not about being clear, it's about making syntax easy to parse for compilers. I do think C++ / C# style templates look better but they cause a lot of trouble for compilers and since creator of D lang (Walter Bright) is a C++ compiler writer (at least he used to be) his desicions are usually to make things easier for compiler dev team.

(03-07-2016, 06:14 AM)A-Man Wrote:  
NX Wrote:Ohh great. Did I told you how hideous C++ can become?
Not in that way. C/C++ are explicit with pretty much all they do (leave alone auto and decltype stuff), which I like.
C is explicit, yes. C++ is nowhere near being explicit.
Every time I say something you guys argue on the opposite side. The same person who says he likes shorter functions telling me he likes things explicit the other day. Don't argue for the sake of arguing. Stop self contradiction. Get your facts straight and provide some serious examples that support your claims. I don't have time for these.

(03-07-2016, 06:14 AM)A-Man Wrote:  How is it not? If both D and C++ serve for the same purpose, and especially if I believe what I use is better suited for myself, I should not be forced to use D (applies to any other language to be used over another).
I'm not forcing anyone to use D. I'm just saying just because you know a language doesn't mean you should not use or learn some other language. Also I don't know how do you even decide what suit your needs without trying different solutions and such. You can see a lot of people hate GC and bash it meanwhile people effectively use it to create low latency software and keep splashing real examples on to faces of those who say it's not possible. There is a huge world out there, don't be a strict minded guy, speak about your experiences, don't tell me about rant of a random guy on the Internet. Make your own desicions from experiencing different things (not just one).
And you know what they say: two language, two person...

(03-07-2016, 06:14 AM)A-Man Wrote:  I am not sure what would be worth discussing then.
You said Vulkan is directly available in C/C++. For the love of God of course it is. C is a universal standard for interoperability and of course they make it available for C (and as a consequence C++). Your example is was so meaningless that I couldn't find anything to argue on that. There is a reason why vk.xml exists.

(03-07-2016, 06:14 AM)A-Man Wrote:  You keep arguing against C++ (or C, it hasn't been clear lately) with complaints about things like design. Things which are largely subjective and depends on what the user has gotten used to.
Purpose of this post is not to argue about C/C++, but rather praise D. There are few (if not many) things D does better than them that worth mentioning, but you're highly misunderstanding my words, saying D lang is nice and all is not equivalent to C++ sucks. I didn't even say anything subjective, I stated reasonings behind design desicions and I don't see anything subjective in my posts, if you think so, point them out.
Ultimately, my constant dissatisfaction with the way things are becomes the driving force behind everything I do.
[Image: sigline.png]
LF2 IDE - Advanced visual data changer featuring instant data loader
LF2 Sprite Sheet Generator - Template based sprite sheet generator based on Gad's method
[Image: sigline.png]
There is no perfect language, but C++ is the worst.
Reply
Thanks given by:
#9
(03-07-2016, 02:59 PM)Nightmarex1337 Wrote:  It's not about being clear, it's about making syntax easy to parse for compilers. I do think C++ / C# style templates look better but they cause a lot of trouble for compilers and since creator of D lang (Walter Bright) is a C++ compiler writer (at least he used to be) his desicions are usually to make things easier for compiler dev team.
Sounds lazy if you want my opinion. Developers should strive on making things easier for the end users even when that would cause heaps of difficulties from their side.

Nightmarex1337 Wrote:C is explicit, yes. C++ is nowhere near being explicit.
Every time I say something you guys argue on the opposite side. The same person who says he likes shorter functions telling me he likes things explicit the other day. Don't argue for the sake of arguing. Stop self contradiction. Get your facts straight and provide some serious examples that support your claims. I don't have time for these.
I like shorter names when they're clearer. I hate verbosity when it's unnecessary. That's why we name our variables
tmp
or
temp
and not
temporaryVariable
. I never said I liked implicit because it will always introduce complexities when you're not aware of how it works, just like that stackoverflow question which tried to evaluate his function at compile time without him asking for it. I don't know about my examples, but I could say the same about you. "C++ is ugly" "C++ is bad" is all you've been saying so far.

Nightmarex1337 Wrote:I'm just saying just because you know a language doesn't mean you should not use or learn some other language. Also I don't know how do you even decide what suit your needs without trying different solutions and such.
Haskel? Sure, it's a functional programming language with a unique design. Lisp? why not. You get familiar with polish notation which can be useful in dealing with tree data structures. Python? General purpose (and, subjective: awesome syntax). But when it comes to languages like D, which purpose is to just be another C++, especially if one has already gotten pretty invested in the latter, should not be a "should". I don't pick my calculator after trying each and everyone out there; there's simply not time for this. Instead, I make an educated guess for my choice based on a research of what other people have written and thought of the other languages online.

Nightmarex1337 Wrote:There is a huge world out there, don't be a strict minded guy, speak about your experiences, don't tell me about rant of a random guy on the Internet. Make your own desicions from experiencing different things (not just one).
And you know what they say: two language, two person...
That's funny considering you've sent me a PM of a quote by Linux Torvalds criticizing C++ the other day as an argument, to which I replied
Quote:I've always looked up to Mr. Torvalds, regardless of his impoliteness, as a phenomenal programmer, and I was surprised to hear this quote from you. But I cannot allow this to affect the conclusion I've reached about C++.

Nightmarex1337 Wrote:You said Vulkan is directly available in C/C++. For the love of God of course it is. C is a universal standard for interoperability and of course they make it available for C (and as a consequence C++). Your example is was so meaningless that I couldn't find anything to argue on that. There is a reason why vk.xml exists.
I don't know what that word means, but I did not say Vulkan is directly available, but immediately, with respect to time. This means that all C/C++ programmers have a head-start.

Nightmarex1337 Wrote:Purpose of this post is not to argue about C/C++, but rather praise D. There are few (if not many) things D does better than them that worth mentioning, but you're highly misunderstanding my words, saying D lang is nice and all is not equivalent to C++ sucks. I didn't even say anything subjective, I stated reasonings behind design desicions and I don't see anything subjective in my posts, if you think so, point them out.
Disregarding all the implications about C++ your posts are plagued with, I've got this direct statement of yours in particular, only a few posts back:
Nightmarex1337 Wrote:This is ironic that you tell me D templates look ugly and keep coding in C++.
How's that not subjective? It's just a generic opinion blatantly stated as an argument.

I haven't declared any verdict on the language. All I've been doing is inquiring from you, the experienced one who introduced me to this, about things which I found peculiar - hoping I'd get an answer that explains or clarifies these peculiarities. I'm in fact actually liking the language so far.
[Image: signature.png]
A-Engine: A new beat em up game engine inspired by LF2. Coming soon

A-Engine Dev Blog - Update #8: Timeout

Reply
Thanks given by:
#10
(03-07-2016, 04:57 PM)A-Man Wrote:  Sounds lazy if you want my opinion. Developers should strive on making things easier for the end users even when that would cause heaps of difficulties from their side.
I knew I should have told you this results in significantly faster compile times, because semantic analysis is not required for ambiguity resolution between right shift operator >> and template syntax. When you want to avoid shooting yourself in the foot, it's not laziness, it's nothing but taking the right pragmatic desicion.

(03-07-2016, 04:57 PM)A-Man Wrote:  I like shorter names when they're clearer. I hate verbosity when it's unnecessary. That's why we name our variables
tmp
or
temp
and not
temporaryVariable
. I never said I liked implicit because it will always introduce complexities when you're not aware of how it works, just like that stackoverflow question which tried to evaluate his function at compile time without him asking for it. I don't know about my examples, but I could say the same about you. "C++ is ugly" "C++ is bad" is all you've been saying so far.
:facepalm:

(03-07-2016, 04:57 PM)A-Man Wrote:  Haskel? Sure, it's a functional programming language with a unique design. Lisp? why not. You get familiar with polish notation which can be useful in dealing with tree data structures. Python? General purpose (and, subjective: awesome syntax). But when it comes to languages like D, which purpose is to just be another C++, especially if one has already gotten pretty invested in the latter, should not be a "should". I don't pick my calculator after trying each and everyone out there; there's simply not time for this. Instead, I make an educated guess for my choice based on a research of what other people have written and thought of the other languages online.
Often, programmer teams will resort to a hybrid approach, where they will mix python and C++, trying to get productivity of Python and the performance of C++. The frequency of this approach indicates that there is a large unmet in the programming language department.
D intends to fill that need. It combines the ability to do low level manipulation of the machine with the latest technologies in building reliable, maintainable, portable, high level code. D has moved well ahead of any other language in abilities to support and integrate multiple paradigms like imparative, OOP, functional, and generic programming.
-Walter Bright, Co-designer of D

(03-07-2016, 04:57 PM)A-Man Wrote:  That's funny considering you've sent me a PM of a quote by Linux Torvalds criticizing C++ the other day as an argument, to which I replied
Quote:I've always looked up to Mr. Torvalds, regardless of his impoliteness, as a phenomenal programmer, and I was surprised to hear this quote from you. But I cannot allow this to affect the conclusion I've reached about C++.
Because I was tired of arguing, that's it.

(03-07-2016, 04:57 PM)A-Man Wrote:  I don't know what that word means, but I did not say Vulkan is directly available, but immediately, with respect to time. This means that all C/C++ programmers have a head-start.
:facepalm:

(03-07-2016, 04:57 PM)A-Man Wrote:  Disregarding all the implications about C++ your posts are plagued with, I've got this direct statement of yours in particular, only a few posts back:
Nightmarex1337 Wrote:This is ironic that you tell me D templates look ugly and keep coding in C++.
How's that not subjective? It's just a generic opinion blatantly stated as an argument.
This is indeed subjective, but I'm not arguing over it. I thought I have enough permission to state my opinion when someone else states his opinion. It's not an argument, it's as you said an opinion.

(03-07-2016, 04:57 PM)A-Man Wrote:  I haven't declared any verdict on the language. All I've been doing is inquiring from you, the experienced one who introduced me to this, about things which I found peculiar - hoping I'd get an answer that explains or clarifies these peculiarities. I'm in fact actually liking the language so far.
I'm a pretty bad teacher, I guess...
Ultimately, my constant dissatisfaction with the way things are becomes the driving force behind everything I do.
[Image: sigline.png]
LF2 IDE - Advanced visual data changer featuring instant data loader
LF2 Sprite Sheet Generator - Template based sprite sheet generator based on Gad's method
[Image: sigline.png]
There is no perfect language, but C++ is the worst.
Reply
Thanks given by:




Users browsing this thread: 1 Guest(s)