Thread overview
Is there a way to tell D to rearrange struct members or to not rearrange class members?
3 days ago
WraithGlade
3 days ago
Dejan Lekic
3 days ago
WraithGlade
3 days ago
Lance Bachmeier
3 days ago
Dejan Lekic
2 days ago
WraithGlade
2 days ago
Lance Bachmeier
2 days ago
monkyyy
3 days ago

I've read both of the available printed D books in their entirety (Ali's and Andrei's) and I noticed Andrei's book (circa ~2010) mentions that the D compiler rearranges the members of class objects to be more optimal by reducing alignment-induced padding whereas it leaves the alignment-induced padding of struct objects exactly the same as implied and required by the order in which you've written the members of the struct.

So, the question here is, is there a way to make the D compiler change that behavior per specific class and struct type definitions or at least across the whole compilation?

I looked in the pragma section in the D library documentation but didn't find it and didn't find it elsewhere either (e.g. it wasn't in the man page for DMD).

Does anyone know if such memory arrangement control is possible currently?

It isn't a major problem at all (easy to work around, such as by embedding a struct in a class for classs, or manually reordering struct members for structs), but I was just curious.

Thanks for reading, as always!

3 days ago

On Friday, 27 June 2025 at 11:23:56 UTC, WraithGlade wrote:

>

I've read both of the available printed D books in their entirety (Ali's and Andrei's) and I noticed Andrei's book (circa ~2010) mentions that the D compiler rearranges the members of class objects to be more optimal by reducing alignment-induced padding whereas it leaves the alignment-induced padding of struct objects exactly the same as implied and required by the order in which you've written the members of the struct.

Lots of things changed since Andrei's book.
I am guessing what you meant is - is there a way to control struct alignment, right?

The answer is yes - D has a nice way of controlling the alignment. - Here is a relevant section that explains it in fine details: https://dlang.org/spec/attribute.html#align

3 days ago

Thanks for responding to my question and for your time, etc.

I was aware of align but as far as I am aware it is orthogonal to what I'm asking about. The Andrei book says that D automatically rearranges members of classs in memory to avoid wasting memory due to padding between members whose width is less than the native CPU word size alignment, whereas structs are left as is (meaning the members aren't reordered for alignment padding optimization).

The align command specifies alignments but doesn't seem relevant to automatic rearranging of members for classes.

I'm not sure if D does that or not anymore, since (as you said) it has been a long while since that book was published.

3 days ago

On Friday, 27 June 2025 at 19:55:30 UTC, WraithGlade wrote:

>

Thanks for responding to my question and for your time, etc.

I was aware of align but as far as I am aware it is orthogonal to what I'm asking about. The Andrei book says that D automatically rearranges members of classs in memory to avoid wasting memory due to padding between members whose width is less than the native CPU word size alignment, whereas structs are left as is (meaning the members aren't reordered for alignment padding optimization).

The align command specifies alignments but doesn't seem relevant to automatic rearranging of members for classes.

I'm not sure if D does that or not anymore, since (as you said) it has been a long while since that book was published.

I think you're referring to this description in the spec:

>

The D compiler is free to rearrange the order of fields in a class to optimally pack them. Consider the fields much like the local variables in a function - the compiler assigns some to registers and shuffles others around all to get the optimal stack frame layout. This frees the code designer to organize the fields in a manner that makes the code more readable rather than being forced to organize it according to machine optimization rules. Explicit control of field layout is provided by struct/union types, not classes.

3 days ago

On Friday, 27 June 2025 at 19:55:30 UTC, WraithGlade wrote:

>

orthogonal to what I'm asking about. The Andrei book says that D automatically rearranges members of classs in memory to avoid wasting memory due to padding between members whose width is less than the native CPU word size alignment, whereas structs are left as is (meaning the members aren't reordered for alignment padding optimization).

So you were talking specifically about classes...

From the https://dlang.org/spec/class.html#fields section:

>

Implementation Defined: The D compiler is free to rearrange the order of fields in a class to optimally pack them. Consider the fields much like the local variables in a function - the compiler assigns some to registers and shuffles others around all to get the optimal stack frame layout. This frees the code designer to organize the fields in a manner that makes the code more readable rather than being forced to organize it according to machine optimization rules. Explicit control of field layout is provided by struct/union types, not classes.

2 days ago
On Friday, June 27, 2025 1:55:30 PM Mountain Daylight Time WraithGlade via Digitalmars-d-learn wrote:
> Thanks for responding to my question and for your time, etc.
>
> I was aware of `align` but as far as I am aware it is orthogonal to what I'm asking about. The Andrei book says that D automatically rearranges members of `class`s in memory to avoid wasting memory due to padding between members whose width is less than the native CPU word size alignment, whereas `struct`s are left as is (meaning the members aren't reordered for alignment padding optimization).
>
> The `align` command specifies alignments but doesn't seem relevant to automatic rearranging of members for classes.
>
> I'm not sure if D does that or not anymore, since (as you said) it has been a long while since that book was published.

I don't know how much D does that with classes, but the implementation is allowed to. It may do it all the time or not at all. I'd have to check.

As for structs, the compiler is not going to muck with their layout on its own. You'll get padding based on the relative size of the fields, but the D compiler is going to do what C does with the layout. The language doesn't provide any mechanism to automatically rearrange the fields.

I have occasionally considered writing something to do it - probably either a template mixin or a string mixin. You could write something where you gave it a list of types and the names you wanted for the member variables, and then it would order them however thy best fit to then be mixed into your struct. However, that would have a compilation cost every time you built that type, and it's rarely needed, so it's usually easier to just rearrange the member variables in whatever the optimal order is. And in most cases, personally, I don't care enough to bother figuring it out (though that's also why I've considered writing something to at least tell me the optimal order for space savings so that I can get an answer without having to think about it).

- Jonathan M Davis




2 days ago

On Friday, 27 June 2025 at 20:08:31 UTC, Lance Bachmeier wrote:

>

...

I think you're referring to this description in the spec:

>

The D compiler is free to rearrange the order of fields in a class to optimally pack them. Consider the fields much like the local variables in a function - the compiler assigns some to registers and shuffles others around all to get the optimal stack frame layout. This frees the code designer to organize the fields in a manner that makes the code more readable rather than being forced to organize it according to machine optimization rules. Explicit control of field layout is provided by struct/union types, not classes.

On Saturday, 28 June 2025 at 03:53:38 UTC, Jonathan M Davis wrote:

>

I don't know how much D does that with classes, but the implementation is allowed to. It may do it all the time or not at all. I'd have to check.

As for structs, the compiler is not going to muck with their layout on its own. You'll get padding based on the relative size of the fields, but the D compiler is going to do what C does with the layout. The language doesn't provide any mechanism to automatically rearrange the fields.

...

  • Jonathan M Davis

Thank you for linking to the spec Lance and for your insight Jonathan.

In addition to the class spec, I also looked at the struct spec and found that especially informative. The struct spec has a significant amount of precise nuance on the details of how struct low-level layouts work exactly and C compatibility details.

I was hoping there was some simple pragma such as some hypothetical pragma(memory_rearrange) or pragma(memory_fixed) to change the memory layout behavior of classs and structs to whatever is best, since in reality the optimal layout is entirely independent from the other properties that class and struct have and so in principle it'd be better for there to be a way to control it explicitly.

This is especially the case for struct, since there are lots of good reasons to avoid OOP and its overhead and conceptual muck (and indeed most of the most popular new languages seem to be aggressively moving away from OOP) but only very specific reasons (such as interfacing with C or hardware or network protocols, etc) to not want the memory layout of struct rearranged to be space-optimal.

Indeed, my hope is to not use OOP at all unless forced to at interface points by 3rd party libraries. The more I've used OOP the more I've found it ever increasingly awkward and stilted and fundamentally a misguided basis for structuring code both conceptually and practically.

Oh well though. It is not that hard or difficult to work around such things, especially with a language as nice as D (or similar languages), just occasionally a bit tedious.


A big freewheeling philosophical side-tangent:

This does line up with my experiences of language design features where an ideological "best practice" is codified into the language's structure itself tend to very often pan out in the long term to be design mistakes (although often, as in this case, relatively small ones). It is extremely easy to think that a supposed "best practice" covers all cases well and will improve code when in reality it does nothing of the sort.

Conceptually orthogonal concepts should be kept orthogonal in languages instead of being conflated or having unnatural arbitrary ideological constraints imposed upon them preemptively, in most if not almost all cases. Keeping orthogonal concepts orthogonal both simplifies implementations and reduces how often users are restricted and stifled for no real reason.

There is an oft recurring patterns of languages that impose such restrictions ending up benefiting from relax those constraints over time as they evolve and/or newer languages casting aside those kinds of unnatural assumptions entirely and benefit greatly from doing so.

D is a great language and well designed, but as I've been learning it I have noticed that nearly always when there is something I dislike about the language (which is relatively seldom) it is because some form of "best practice" or structural assumption (rooted in a clearly apparent lack of imagination regarding the essentially infinite diversity of possible use cases) has been imposed upon the language.

There are very few imposed structural "best practices" that are genuinely universal in my experience. Good naming of variables would be a rare example of a universally good practice, in my opinion, but in contrast even pervasive and nearly universally advocated systems (such as OOP for many years in the past few decades) have turned out (from a deeper language design perspective) to ultimately be riddled with false assumptions and thus the structure imposed by such systems when reified and scaled up to real software systems has often caused more harm than good.

Anyway, that's just me rambling from a idealistic philosophical perspective about languages.

From a pragmatic perspective D (and many other languages) is great overall obviously and is very worth of praise and wider use in that regard.

There are still many places where future languages could improve things though, and most of the low hanging fruit in that regard hinge upon vigorously questioning many very arbitrary assumptions and needless rigidity (both in syntax and semantics) in language design.

One of my favorite examples of that syntactically is mixfix notation (unrelated to mixins, though the words look similar at a careless glance), i.e. allowing function definitions to be arbitrary phrases instead of alwaysTryingToCramAFullSentenceOfSemanticsAwkwardlyIntoOneSymbol. There is a pervasive false assumption though that since COBOL is bad and uses mixfix then mixfix itself must be bad but that entirely wrong and is almost 100% orthogonal conceptually.

Look for example at rare examples of modern mixfix (i.e. phrase based) languages such as Jinx on GitHub (a C++ embedded scripting language) and LDPL for syntactic demonstrations of the falseness of the assumption that C-like syntax is some kind of natural endpoint for language syntax evolution. Mixfix enables a level of readability that on a whole level above practically all the modern popular languages, especially if it was refined and polished up to be nice and homoiconic and concise enough. It lets you define functions as nearly natural language phrases such as "render (some_object) at location (some_vector) using (some_enum) rendering method" (improving readability even to the point non-programmers can read and understand it) and enables each argument to have its own separate vararg list in theory (not sure if Jinx or LDPL do that though) and so on.

Likewise, s-expression based languages such as Lisp and Scheme family languages (e.g. Racket and Steel Bank Common Lisp) and concatenative languages such as Forth and Factor also provide great demonstrations of how much more elegant and conceptually natural and unburdensome and freely expressive syntax can actually be. Factor identifiers can be literally anything except whitespace, for example, which is wonderfully liberating.

A hybrid of mixfix syntax and concatenative semantics with C-like performance for example would have fantastic potential for both readability and expressiveness, but the C family of languages has people syntactically chasing their own tails and also semantically working within a set of contrived classical OOP assumptions that have no actual genuinely logical basis in what computing or modeling of conceptual program designs is actually capable of.

In some ways OOP modeling is even literally conceptually backwards, since it poses that "subtypes" should be "extensions" with more capabilities than parent classes when in reality from a logical/mathematical perspective subtypes should actually be more constrained (hence less capable) than their parent types in order to actually be universally substitutable for their parent.

For example, a square is a subtype (a subset member) of a rectangle from a logical and mathematical perspective but OOP models that literally backwards (as something capable of more and hence as a superset, contradicting the actual logical type relation in reality) and hence results in many conceptually incorrect consequences such as the notorious "Circle-Ellipse" problem that demonstrates how ill-conceived OOP methodology actually is in actuality and how much of a conceptual deadend it actually is to try to force programs to fit any preconceived ontology of unnatural categories embodied by any class hierarchy.

That's precisely why so many OOP hierarchies pretty much never achieve conceptual perfection: they literally can't, it's logically impossible because OOP inherently embodies self-contradictory criteria in its philosophy of what types "should" be. Logical subtypes must be more constrained but extension implies a superset of capabilities. Those properties are fundamentally logically incompatible, hence the mess OOP usually creates if you look closely enough and question it alertly enough. Reuse of code via OOP inheritance in contrast is essentially just a poorer form of reuse than other more genuinely modular choices such as functions or fixed data formats (e.g. image file formats) or agent-based message passing ("true OOP" a la Smalltalk/Pharo) or MVC separation or templates or whatever other more well considered model one could use.

Subtyping and extension are like oil and water from the standpoint of actual logical reasoning. A square is a rectangle but rectangles require independently modifiable sides. Likewise, a square permits aggressive optimizations not possible for rectangles. Trying to put them in a hierarchy is thus a microcosm of how even for trivially simple and common cases OOP based models are doomed to fail conceptually (even if they "work") as an optimal model regardless of how much effort one ever puts into them. That's why compile-time typing and composition and functional programming and so on so often end up better: because they don't try to fulfill a self-contradictory and hence counterproductive misleading criteria for how code "should be" structure such as that embodied by classical OOP.

That's just me pontificating about the ever elusive hypothetical "best language" and such though. Make of that what you will. Short and medium term pragmatism is a different matter, unfortunately. One is forced to contrive one's own mind to fit these kinds of pre-existing assumptions because that is what the body of most software already uses, which also creates a "chicken and egg" problem that perpetuates the lack of real conceptual diversity in the most popular (and hence viable in production) languages writ large.

That lack of real diversity also instills false confidence in the existing body of assumptions and implies that few people actually end up experiencing any full projects ever made under any alternative paradigm of design...

This tangent really got longer than I intended, but language design is a soapbox issue for me and so it was fun to let that tangent unroll wherever it went.

On the other hand, my years of obsession with finding better languages has done much harm to my actual software output and I have wished for many years now that I was not so uptight about these kinds of things because it really is quite a distraction from making more real software and such.

I often really wish I was the kind of person who didn't care about these kinds of things so much and didn't have such a hard time resisting the urge to build abstractions papering over these problems in ways that derail too much of my time and historically have led me to constantly switching languages and libraries literally for a whole decade without hardly producing any of the personal project software I've for so long wanted to. That has become a real problem for me unfortunately, and I really wish I could lighten up on it.

Anyone else had similar experiences in that regard and have some insight on fighting against one's own language idealist impulses enough to be productive?

I've tried telling myself to recognize that it is the end result (what the end-user sees, etc) that really matters many times, and countless other notes to myself in that regard, but here we are anyway.

Language design is fascinating but can be quite a distraction.

Perhaps I should go do a bit of art again for a while, since at least in art production one is not beset by these kinds of confounding factors of feeling forced to fit other people's minds such as we experience too often in software while wanting to express our own minds instead but being frustrated by the lack of viability of that in the ecosystem and the non-existence and ephemeral nature of the elusive "perfect language" and such. You know what I mean?

Anyway, have a great day/night/etc all and see you around!

2 days ago

On Saturday, 28 June 2025 at 15:20:44 UTC, WraithGlade wrote:

>

There are very few imposed structural "best practices" that are genuinely universal in my experience. Good naming of variables would be a rare example of a universally good practice, in my opinion, but in contrast even pervasive and nearly universally advocated systems (such as OOP for many years in the past few decades) have turned out (from a deeper language design perspective) to ultimately be riddled with false assumptions and thus the structure imposed by such systems when reified and scaled up to real software systems has often caused more harm than good.

I tend to agree. John Hughes wrote in his famous Why Functional Programming Matters

>

If omitting assignment statements brought such enormous benefits then Fortran programmers would have been doing it for twenty years. It is a logical impossibility to make a language more powerful by omitting features, no matter how bad they may be.

>

Even a functional programmer should be dissatisfied with these so-called advantages, because they give no help in exploiting the power of functional languages.

>

It’s helpful to draw an analogy between functional and structured programming. In the past, the characteristics and advantages of structured programming have been summed up more or less as follows. Structured programs contain no goto statements. Blocks in a structured program do not have multiple entries or exits. Structured programs are more tractable mathematically than their unstructured counterparts. These “advantages” of structured programming are very similar in spirit to the “advantages” of functional programming we discussed earlier. They are essentially negative statements, and have led to much fruitless argument about “essential gotos” and so on.

>

With the benefit of hindsight, it’s clear that these properties of structured programs, although helpful, do not go to the heart of the matter. The most important difference between structured and unstructured programs is that structured programs are designed in a modular way. Modular design brings with it great productivity improvements.

>

The absence of gotos, and so on, has very little to do with this.

If the only thing you can say is "that's bad practice" then you don't have a sensible argument. It's no better than proof by example. "It holds in these six examples, QED." The designer of a language doesn't have the knowledge required to universally declare something a bad practice that should be avoided. The language spec is not a linter and it shouldn't be a substitute for code review and sensible programming practice.

2 days ago

On Saturday, 28 June 2025 at 15:20:44 UTC, WraithGlade wrote:

>

D is a great language and well designed, but as I've been learning it I have noticed that nearly always when there is something I dislike about the language (which is relatively seldom) it is because some form of "best practice" or structural assumption (rooted in a clearly apparent lack of imagination regarding the essentially infinite diversity of possible use cases) has been imposed upon the language.

come to opend and complain to adr about arbitrary limitations