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 next sibling parent reply 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
parent reply Walter Bright <newshound2 digitalmars.com> writes:
It's a nice idea, but is very fragile. The exact registers that are used are 
very sensitive to every detail, and hard to predict. The best options are:

1. write the whole dang thing in assembler

2. write a recognizer for it and custom code generation
Dec 01
next sibling parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 02/12/2025 6:08 PM, Walter Bright wrote:
 It's a nice idea, but is very fragile. The exact registers that are used 
 are very sensitive to every detail, and hard to predict. The best 
 options are:
 
 1. write the whole dang thing in assembler
 
 2. write a recognizer for it and custom code generation
3. Intrinsic with custom code generation
Dec 01
parent reply Walter Bright <newshound2 digitalmars.com> writes:
 3. Intrinsic with custom code generation
That is a viable approach. I've had good results by using pattern recognition rather than intrinsics, for things such as byte swapping.
Dec 01
parent "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 02/12/2025 7:28 PM, Walter Bright wrote:
 3. Intrinsic with custom code generation
That is a viable approach. I've had good results by using pattern recognition rather than intrinsics, for things such as byte swapping.
In this case it requires us to have (u)cent. The fact that we don't have this, and its thought acceptable to remove it, is to me something I swear in my head over. Not to mention fun stuff like this in "the workaround": https://github.com/dlang/dmd/issues/22170
Dec 01
prev sibling parent Dom Disc <dominikus scherkl.de> writes:
On Tuesday, 2 December 2025 at 05:08:39 UTC, Walter Bright wrote:
 It's a nice idea, but is very fragile. The exact registers that 
 are used are very sensitive to every detail, and hard to 
 predict.
Not in this case. The assembler documentation states that mul puts its result in registers RAX:RDX (or EAX:EDX for 32bit etc.) And the carry-flag is also well documented. Also RAX is always the return value. But of course it's very Intel specific.
 1. write the whole dang thing in assembler
I've done this and I hate it. It always requires extra steps to generate and include the other object file and I run always in some name-mangling problems. The solution with inline assembler feels so much more natural and is so easy readable - just, well, elegant.
 2. write a recognizer for it and custom code generation
I have no idea how to do this.
Dec 02
prev sibling next sibling parent reply Murilo <murilomiranda92 hotmail.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!
My Github is full of those. https://github.com/murilomir And my personal experience: in Dlang I can write code just as easily as in Python (sometimes even more easily). The code is always super readable and I can build absolutely anything using nothing more than the basic blocks of any programming language: - variables - functions - structs and classes - conditionals - loops - module imports
Nov 28
parent reply rnd2 <r_narang yahoo.com> writes:
On Friday, 28 November 2025 at 22:23:37 UTC, Murilo wrote:
 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!
My Github is full of those. https://github.com/murilomir And my personal experience: in Dlang I can write code just as easily as in Python (sometimes even more easily). The code is always super readable and I can build absolutely anything using nothing more than the basic blocks of any programming language: - variables - functions - structs and classes - conditionals - loops - module imports
What is most reliable and convenient for GUI in Dlang?
Dec 01
parent Serg Gini <kornburn yandex.ru> writes:
On Tuesday, 2 December 2025 at 07:19:02 UTC, rnd2 wrote:
 What is most reliable and convenient for GUI in Dlang?
Nothing special Qt, GTK, ImGui bindings. dlangui is kinda unique for D https://code.dlang.org/?sort=updated&limit=20&category=library.gui
Dec 02
prev sibling parent reply cc <vugewb+3ogyxzlhhabew grr.la> writes:
On Tuesday, 25 November 2025 at 01:18:21 UTC, Walter Bright wrote:
 I'm interested in anecdotes, experiences and examples of 
 Elegant D to incorporate!
2D slicing in my 2D array/Grid struct (which just holds a 1D array under the hood): ```d auto grid = Grid!char(6, 4, '.'); writeln(grid); ``` ``` [......] [......] ``` I enjoy the gameplay loop of "Write complex structure code with ultra-simple usage that abstracts away all that complexity when you need to actually do something with it, so your main() looks clean as a whistle". Also, easy UFCS templates: ```d SomeObject someObj = ... SomeStruct someStruct = ... // Writes all aggregate member-value pairs without the need of builtin toString methods writeln(someObj.toStringer); writeln(someStruct.toStringer(recursive:true)); ```
Dec 03
parent cc <vugewb+3ogyxzlhhabew grr.la> writes:
On Wednesday, 3 December 2025 at 16:52:43 UTC, cc wrote:
 ```d
 auto grid = Grid!char(6, 4, '.');

 writeln(grid);
 ```
Also the fact that while I can do this: ```d foreach (y; 0 .. grid.height) foreach (x; 0 .. grid.width) { doThing(grid[x,y]) } ``` I can also do: ```d foreach (coord, tile; grid) { // coord.x, coord.y doThing(tile); } ```
Dec 03