www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Elegant D

reply Walter Bright <newshound2 digitalmars.com> writes:
I've been thinking about writing an article about what makes D an elegant 
language to program in. D is indeed an elegant programming language.

I'm interested in anecdotes, experiences and examples of Elegant D to
incorporate!
Nov 24
next sibling parent Kapendev <alexandroskapretsos gmail.com> writes:
On Tuesday, 25 November 2025 at 01:18:21 UTC, Walter Bright wrote:
 I've been thinking about writing an article about what makes D 
 an elegant language to program in. D is indeed an elegant 
 programming language.

 I'm interested in anecdotes, experiences and examples of 
 Elegant D to incorporate!
I like how this looks in my code :) ```d /// A generic 2D rectangle. struct GRect(P, S = P) if (P.sizeof >= S.sizeof) { GVec2!P position; /// The position of the rectangle. GVec2!S size; /// The size of the rectangle. // ... } ```
Nov 24
prev sibling next sibling parent Richard (Rikki) Andrew Cattermole <richard cattermole.co.nz> writes:
1. External import path, make dllimport very easy without any 
warnings.

     ``$ ldc2 -oflibrary.dll -shared library/lib.d 
--fvisibility=public``

     ``$ ldc2 -extI library --dllimport=externalOnly main.d 
library.lib``

     ```d
	module lib;

     int var = 2;
     ```

     ```d
     module main;
     import lib;
     import std.stdio;

     void main() {
         writeln(var);
     }
     ```

2. Vector array ops make SIMD simple with ldc:
     Instead of going to these lengths: 
https://salykova.github.io/gemm-cpu

     You can write:

     ```d
     void kernel4(ref float[16] o, ref const float[16] a, ref 
const float[16] b, ref const     float[16] c) {
         o[] = b[] * a[];
         o[] += c[];
     }
     ```

     Needs https://github.com/ldc-developers/ldc/issues/4991 fixed 
to get the benefit of avx512vl.

3. Unittests add ddoc comment, and now it's an example

4. You don't have to rely on the signal handler to handle a 
segfault appropriately. You can also catch some really stupid 
problems at compile time too!

     ``dmd -preview=fastdfa main.d``

     ```d
     module main;

     void func(int* ptr) {
         int val = *ptr;
     }

     void main() {
         func(null);
     }
     ```

     No attributes required! All inferred.

     If that is not enough, you can use the null check to catch 
problems before they have a chance to infect a task and cause you 
problems. But alas that is waiting on a review from you Walter: 
https://github.com/dlang/dmd/pull/22040

     The elegance here is you don't have to infect your code with 
attributes and you will be able to get mostly protected that you 
can catch problems. Also allows for quicker turn around times.

5. opCast!bool can be used for error handling / to test the 
presence of a value with if statement
Nov 24
prev sibling next sibling parent Kagamin <spam here.lot> writes:
Hybrid reference/value type:
```
/// Buffered output stream
struct OutputStream
{
	/// Reference type
	package Instance* I;
	/// Implicitly convertible to value type
	pure ref Instance Forward(){ debug assert(!!I); return *I; }
	/// ditto
	alias Forward this;
	/// Null check
	const pure bool opCast(){ return !!I; }
/// Use this to store `OutputStream` as value type
struct Instance
{
	/// Implicitly convertible to reference type
	pure OutputStream Reference(){ return OutputStream(&this); }
	/// ditto
	alias Reference this;
	...other methods
	 disable this(this); //not copyable
}
}


/**
Text interface for `OutputStream`.
Examples:
---
OutputStream ostr;
auto wr=TextWriter(ostr);
wr.Write("text string");
---
*/
struct TextWriter
{
	OutputStream Output;
	void Write(in char[] txt)
	{
		Output.Write(cast(const byte[])txt); //trust.bytes;
	}
	void Write(in char[][] txts...)
	{
		foreach(txt;txts)Write(txt);
	}
}
```
Nov 25
prev sibling next sibling parent monkyyy <crazymonkyyy gmail.com> writes:
On Tuesday, 25 November 2025 at 01:18:21 UTC, Walter Bright wrote:
 I've been thinking about writing an article about what makes D 
 an elegant language to program in. D is indeed an elegant 
 programming language.

 I'm interested in anecdotes, experiences and examples of 
 Elegant D to incorporate!
https://gist.github.com/crazymonkyyy/e6edc498376da0501c851c8c339eba4b vs a c hotload lib https://gist.github.com/crazymonkyyy/a7b3295286594c45af975c585a226e22
Nov 25
prev sibling next sibling parent "H. S. Teoh" <hsteoh qfbox.info> writes:
On Mon, Nov 24, 2025 at 05:18:21PM -0800, Walter Bright via Digitalmars-d wrote:
 I've been thinking about writing an article about what makes D an
 elegant language to program in. D is indeed an elegant programming
 language.
 
 I'm interested in anecdotes, experiences and examples of Elegant D to
 incorporate!
I don't know what your definition of "elegant" is, but here are some of my favorite features of D: 1. Built-in AA's. AA's get a lot of hate for some reason, but they're perfect for shell script replacements when you just need a hashtable quick'n'dirty and don't really need nor care about the fine details of hashtables. Plus, D's AA's have no silly arbitrary restrictions, like keys must be strings, or values must be strings. Recently I had to use sets in Javascript, it was horrendous. Keys must be strings, which means incessant conversions back and forth from objects (with the associated performance hit), and values break in weird ways unless you serialize them to strings first. In D, you just stick a struct into an AA key or value and it Just Works(tm) by default. In C++ you have to write 2 pages of code just to make structs work as hash keys, not to mention write ridiculously-convoluted boilerplate every time you want to use the resulting hash table as a type, ridiculous! 2. Built-in unittests. This one feature alone has improved my code quality by leaps and bounds. No need to install yet another tool just for unittesting, no need to switch to a different file to write unittests (which generally means I'd be too lazy to do it), no need to switch to a different language to write unittests in. D's unittest guilt-trip me into actually writing tests for my code, with the result that bugs are caught early, saving lots of debugging time later. Better yet, ddoc'd unittests means you don't have to repeat yourself: write a unittest once, and it serves as documentation on how to use your code, no need to go through another round to write code examples! And you're guaranteed that your code examples will actually compile, since they're unittests. 3. Sane template syntax: auto myRangeFunction(R)(R range) { ... } None of that nested angle-bracket horror in C++ that makes the language impossible to lex until you parsed it first. 4. UFCS chains FTW. 5. CTFE. None of the silly arbitrary limitations of C++'s constexpr, you just write code like code and it works at compile-time just as it works at runtime. 6. std.conv.to: the one-stop shop for all of your type conversion needs. I know std.conv gets a lot of hate for some of the ugly parts of the implementation, but the concept is sound and the practical usage so incredibly convenient I chafe inside every time I have to write code in a different language that doesn't have this capability. 7. DbI: I was able to write a serialization system that *didn't* require you to write serialization boilerplate in every object you wanted to be serializable. It even worked with arbitrary classes, using static this() inside a template wrapper struct to automatically include in the executable the ctor calls you need to reconstruct your class objects, *only* for the classes that you actually serialize in your code, no more, no less. Bypassing Object.factory completely (because that's *not* elegant). The basic idea is this: private Object delegate()[string] globalCtors; template serialize(T) if (is(T == class)) { void serialize(T classObj) {...} // N.B.: not addressable from outside, gets instantiated // exactly once per class type you pass to serialize() struct deserializeImpl { // static this() ensures we only have one // instance per class type T shared static this() { globalCtors[T.stringof] = () { // We use compile-time knowledge // of T to return an instance of // T at runtime. return new T; }; } } } So in the deserialization code, once you know the name of the class, you just look up globalCtors[className] to get a delegate that will create an instance of that class and deserialize the incoming data into it (not shown in code above for simplicity -- but basically you use __traits(parameters) to introspect the class ctor's parameters, and use that to generate code that reads the respective arguments from the serialized data -- man, I love D metaprogramming! -- and then make your ctor call -- all without touching Object.factory() at all). Thanks to D's metaprogramming capabilities, once the above is setup you don't even need to think about serialization anymore. You just pass the class object to serialize(), and the template, using DbI and static ctors, auto-generate all of the requisite machinery to make it all work. Not shown above is the version of serialize() that works for PODs and structs -- I have that as an overload, so once all of that is in place, all I need to do is to pass any type that I like to serialize(), and DbI takes care of everything else. Zero boilerplate FTW! 8. Have you heard about std.parallelism.parallel? Suppose you have a busy loop: foreach (data; bigArrayOfData) { doHeavyWork(data); } and doHeavyWork() basically operates independently on each piece of data. How do you parallelize it to take advantage of multiple CPU cores? In other languages that I know of, you'd have to do a major restructuring of your code, worry about race conditions, deal with the complexities of working with mutexes, semaphores, and what-not. In D? Check this out: foreach (data; bigArrayOfData.parallel) { doHeavyWork(data); } What, really? That's it? Yes, that's it! And what's even better about this: .parallel is NOT a built-in language construct! D gives you the power to implement awesome things like this as *user code*, not as in-language or in-compiler hacks. Now *that's* elegance. // There are many other little things about D that I love, and that make writing D such an elegant experience, but the above are the main ones that come to mind. There are probably many others. T -- If it tastes good, it's probably bad for you.
Nov 25
prev sibling next sibling parent Peter C <peterc gmail.com> writes:
On Tuesday, 25 November 2025 at 01:18:21 UTC, Walter Bright wrote:
 I've been thinking about writing an article about what makes D 
 an elegant language to program in. D is indeed an elegant 
 programming language.

 I'm interested in anecdotes, experiences and examples of 
 Elegant D to incorporate!
// 1. Zero Runtime Allocation (High Performance) // 2. Maximum Compile-Time Optimization (CTFE) // 3. Safety and Control // What this code does: // Calculates the 64-bit integer overflow year (over 292 billion) // using Compile-Time Function Execution (CTFE) // and then prints the comma-formatted result at runtime // with zero Garbage Collector (GC) allocation. module myModule; safe: private: import core.stdc.stdio : printf; import core.stdc.stdlib : exit; enum MAX_BUFFER_SIZE = 26; enum : double { MAX_SECONDS = cast(double)long.max, SECONDS_PER_YEAR = 365.25 * 24.0 * 60.0 * 60.0 } pure nogc long calculateRawOverflowNumber() { double maxYears = MAX_SECONDS / SECONDS_PER_YEAR; double targetYearDouble = 1970.0 + maxYears; return cast(long)targetYearDouble; } trusted nogc size_t longToCommaStringNogc(long n, char* buffer, size_t bufferSize) { char[MAX_BUFFER_SIZE] temp; char* currentDigitPtr = temp.ptr + MAX_BUFFER_SIZE - 1; long currentN = n; size_t digits = 0; do { *currentDigitPtr = cast(char)('0' + currentN % 10); currentN /= 10; currentDigitPtr--; digits++; } while (currentN > 0); currentDigitPtr++; size_t commaCount = (digits - 1) / 3; size_t totalLength = digits + commaCount; if (totalLength + 1 > bufferSize) { printf("Error: Buffer too small.\n"); exit(1); } char* targetPtr = buffer; for (size_t i = 0; i < digits; i++) { if (i > 0 && (digits - i) % 3 == 0) { *targetPtr = ','; targetPtr++; } *targetPtr = currentDigitPtr[i]; targetPtr++; } *targetPtr = '\0'; return totalLength; } trusted nogc void main() { enum long RAW_OVERFLOW_NUMBER = calculateRawOverflowNumber(); char[MAX_BUFFER_SIZE] stackBuffer; size_t len = longToCommaStringNogc(RAW_OVERFLOW_NUMBER, stackBuffer.ptr, stackBuffer.length); printf("The 64-bit overflow year is: %s\n", stackBuffer.ptr); }
Nov 25
prev sibling parent Dom Disc <dominikus scherkl.de> writes:
On Tuesday, 25 November 2025 at 01:18:21 UTC, Walter Bright wrote:
 I've been thinking about writing an article about what makes D 
 an elegant language to program in. D is indeed an elegant 
 programming language.

 I'm interested in anecdotes, experiences and examples of 
 Elegant D to incorporate!
I love to be able to do this: ```d /// calculate product inplace and return the high bits /// thanks to a little bit assembler, this is really fast ulong mulx(ref ulong a, ulong b, ulong c) safe pure nothrow nogc { a *= b; // the high bits of this multiplication are in RDX a += c; // and the carry of this addition in the carry flag asm trusted pure nogc nothrow { adc RDX, 0; // add the carry to the high bits mov RAX, RDX; // and move them to the return value ret; // thats it } } ulong mul(ulong[] a, ulong b, ulong c =0) safe pure nothrow nogc { foreach(i; 0..a.length) c = mulx(a[i], b, c); return c; } ``` And get the same performance as if the whole function would be written in fully optimized assembler as it is necessary in C or C++.
Nov 26