Re: Time for std.reflection
I like it. First a couple details: class ClassInfo { @property: string name(); string baseName(); string parentName(); // if applicable, null otherwise string[] interfaces(); bool isShared(); Protection protection(); DataMemberInfo[] data(); MethodInfo[] methods(); Object defaultConstructor(); ... } Why do you not use recursion here? Why not ClassInfo base(); ClassInfo parent(); and then you get baseName by calling base.name; Then for an e.g. method declaration we'd have: class MethodInfo { @property: string name(); bool isStatic(), isFinal(), isOverride(); Protection protection(); string[] parameterTypes(); string[] parameterNames(); } Do you think there'll be any way to get the actual types of the arguments and the return type back from the struct? I think that without compiler magic or an uncomfortable amount of templates it probably won't be possible, but I might be wrong. Now to my big complaint: I really dislike making the runtime api accessible through a mixin. I'd much prefer making it a non-member template. Reasons are a) I don't want to store the runtime information in my type. A vtable pointer should be enough to get that information. Maybe use it as an index into a global immutable associative array. For modules and non-class types the name can act as a unique identifier. b) It'd make it possible to get runtime information on types that I get from libraries. c) It would lead to less coupling. d) It would discourage writing types that rely on runtime reflection, but it would not make it impossible.
Re: How do you remove/insert elements in a dynamic array without allocating?
On Wednesday, 7 November 2012 at 09:45:48 UTC, monarch_dodra wrote: On Wednesday, 7 November 2012 at 03:45:06 UTC, Malte Skarupke wrote: Having no clear ownership for the array is not something I am willing to accept. Strong ownership puts you back into C++'s boat of bordering psychotic duplication on every pass by value. In a GC language, and in particular, D, that favors pass by value, this might not be the best approach. I'll re-iterate that you may consider looking into std.container.Array. It behaves much like would std::vector (reserve, etc)... You can extract an actual range from Array, but there is a clear container - range distinction. An added bonus is that it uses implicit reference semantics. This means that when you write a = b, then afterwards, you have a is b, and they are basically alias. This is a good thing, as it avoids payload duplication without your explicit consent. The implicit means that it will lazily initialize if you haven't done so yet. You claim you want explicit ownership: Array gives you that, but not in the classic RAII sense. If you need to duplicate an Array, you call dup manually. Also, Array uses a deterministic memory model, just like vector, that releases content as soon as it goes out of scope. I could have done without that, personally, but to each their own. I think we have just had different experiences. In my experience a shared_ptr is usually not what you want. Instead I prefer a unique_ptr in many cases. Just because multiple things are referencing your data, that doesn't mean that they should all share ownership of it. For me well defined ownership is just good coding practice, similar to the const keyword. I've seen it prevent bugs and therefore I use it for all cases that I can. I prefer to have those exceptions where I can not have clear ownership stand out, rather than them being the norm.
Re: How do you remove/insert elements in a dynamic array without allocating?
On Tuesday, 6 November 2012 at 09:10:08 UTC, bearophile wrote: Malte Skarupke: I will most certainly never use dynamic arrays or slices again for anything that needs to grow or shrink dynamically. And doing so you will miss an important and handy part of D :-/ Bye, bearophile I implemented my own DynamicArray struct which behaves more like I want it to and is still giving me all of the benefits that I want from dynamic arrays. Having no clear ownership for the array is not something I am willing to accept. Same thing for the non-deterministic copying and destruction behavior for the elements. That's the kind of thing which looks convenient at first, but will create many small performance problems. Once those add up to a big problem, it's incredibly frustrating to fix because your slow downs are from all over the place. I don't anticipate that I will ever run into a situation where I want to append to a range without caring about whether it allocates and copies or not. If I want to append to a range, I will write the extra line to create a copy manually. Because of that I don't need the syntactic ambiguity of treating a range the same as an array.
How do you remove/insert elements in a dynamic array without allocating
Let's say I want to
How do you remove/insert elements in a dynamic array without allocating?
Following code: void main() { import core.memory; GC.disable(); scope(exit) GC.enable(); int[] a = [1, 2, 3, 4, 5]; foreach(i; 0 .. 10) { --a.length; a ~= i; } } That loop will keep on allocating in every iteration until your memory is full. Is there a way to do something similar to this without allocating? I have also tried slicing: a = a[0 .. $ - 1]; // instead of (--a.length;) But neither one works. How do you work with the dynamic array without having to rely on the GC all the time? I want something similar to the stl vector, which only re-allocates once your array grows past a certain size, not on every append. Thanks! Malte
Re: How do you remove/insert elements in a dynamic array without allocating?
On Tuesday, 6 November 2012 at 01:25:39 UTC, Jonathan M Davis wrote: On Tuesday, November 06, 2012 02:11:06 Malte Skarupke wrote: Following code: void main() { import core.memory; GC.disable(); scope(exit) GC.enable(); int[] a = [1, 2, 3, 4, 5]; foreach(i; 0 .. 10) { --a.length; a ~= i; } } That loop will keep on allocating in every iteration until your memory is full. Is there a way to do something similar to this without allocating? I have also tried slicing: a = a[0 .. $ - 1]; // instead of (--a.length;) There's no real difference between those two. But neither one works. How do you work with the dynamic array without having to rely on the GC all the time? I want something similar to the stl vector, which only re-allocates once your array grows past a certain size, not on every append. Arrays do work that way. They have capacity, and they have reserve. They only append when they don't have enough memory or they're not the last slice in the block. The problem is that if you remove elements, the runtime doesn't know if there's another slice pointing to the element which was just removed, so it has to assume that that there is, and it'll be forced to reallocate when appending. If you _know_ that there are no slices of anything beyond the end of the array, then you can call assumeSafeAppend on the array, and then the runtime will mark it as the last slice in the block, and appending won't reallocate unless it actually runs out of space in the block (or you end up removing another element without calling assumeSafeAppend or you end up with a slice which contains elements beyond the end of that array - e.g. if you slice the array and then append to the slice). So, in this particular case, assumeSafeAppend would solve your problem. Whether it works in your program in general depends on what your program is doing. And if you want to make sure that the array has enough space before appending to it a bunch, then you can use reserve. However, if you're specifically building an array, you should probably look at std.array.Appender. Don't remove elements from that though. It's just for making appending more efficient, not for being used once the array has been fully constructed. If you haven't read it yet, I'd strongly advise reading this article on arrays in D: http://dlang.org/d-array-article.html - Jonathan M Davis Thanks, that explains it well. I must admit that I didn't fully understand slices before. I've read the linked article and am baffled that this is seen as acceptable behavior. I will most certainly never use dynamic arrays or slices again for anything that needs to grow or shrink dynamically.
Re: Const ref and rvalues again...
On Monday, 5 November 2012 at 03:26:10 UTC, Jonathan M Davis wrote: On Sunday, November 04, 2012 20:43:36 Andrei Alexandrescu wrote: On 11/4/12 7:58 PM, martin wrote: I find it sad that while this topic seems to be of high priority for quite a lot of language users, it is seemingly neglected by the head of language development (Walter, Andrei etc.). I was hoping auto ref solves this problem. I think it's currently only implemented for templates. And when we argued for altering it so that it operated like const ref in C++ (which allows const ref in D to continue to function like it does now), some folks complained, because they've found the current semantics of auto ref to be useful (something to do with propagating the exact, original type, I think). Now, since auto ref currently only works with templates, maybe we can keep its current semantics with templated functions but alter them for non-templated functions so that it works like const ref does in C++. The downside is that the semantics for auto ref between templated functions and non-templated functions are slightly different, but they're close enough that I'm not sure that it matters. - Jonathan M Davis Yes, please. Auto ref for non-template functions would solve the problem exactly. I also like it because then the intent of the programmer is clear.
Re: D vs C++11
On Friday, 2 November 2012 at 17:03:38 UTC, Erèbe wrote: Hello student here, I have started to learn D a few months ago with Andrei's book (I really liked arguments about design decisions), but as the same time I was learning new features of C++11, and now I'm really confused. (As learning projects, I've done an IRC Bot in D and an IPv6 stack in C++11) D is a great language and introduce a lot of features I really like (range, property, UFCS, great metaprogramming, ...) but C++11 and the new standard librairy are well supported now. I have some solid experience with C++, so I know how cumbersome C++ could be (C++11 and universal reference ?), but D has a lot of features too and (as C++) a slow learning curve. I would like to konw the point of view of the community about C++11 in regard of D ? Is the gap between D and C++11 is getting thinner ? Do you think D will keep attracting people while at the same time C++11 has more support (debugger, IDE, Librairies, Documentation) ? I've learned C++ in the last two years and learned D in the last couple months, and I slightly prefer C++ over D. When I started using C++11, I took for granted that all the features just work. Using D, I realize that that is actually unusual. In D you still encounter compiler bugs or inconsistent behavior way too often, and I have workarounds all over my code. I also prefer C++ being much more explicit about everything it does. For example I prefer the lambdas with a capture list over D delegates. And in D you've got the core runtime allocating memory without me being aware of it all the time. Sure, it gets garbage collected at some point, but I'd rather that it didn't do it at all. D also makes the const keyword more annoying than it should be. In C++ you typically use it as an indicator for the intent of the interface and to prevent you from making mistakes. There are some programmers who find it very annoying and who never use const. In D I am leaning towards being one of those programmers, even though I belong to the group who uses const more strictly in C++. That being said I do think that I write better code in D, but I wouldn't use it for real projects any time soon. It just isn't ready, and I'm sure that my existing code will break several more times in future compiler versions. At the moment the issue is that C++11 is pretty good, and D is not ready. So people will start using C++11 and they'll see that it's good enough and they'll never migrate. The best features of D don't matter if the language is a bit annoying as soon as you leave the space of clean and nice examples.
Re: D vs C++11
On Saturday, 3 November 2012 at 22:45:59 UTC, Tommi wrote: On Saturday, 3 November 2012 at 22:01:21 UTC, Malte Skarupke wrote: D also makes the const keyword more annoying than it should be. What kind of annoyances regarding const have you encountered in D? To start off it's simple things like this: void main() { struct A { this(int x) { this.x = x; } int x; } const(A) a = A(5); A b = a; } This doesn't compile. And it will probably never compile. The issue is that struct A has a context pointer and because of transitive const, you are not allowed to copy that pointer. And you can not specify your own copy constructor because all copy constructors happens post-blit, at which point you'd already have a non-const pointer. So that will probably never change. But that's not a big problem. It's more been stuff like me implementing an equivalent of std::function from C++. (as I said I like to be more explicit about things than delegates) I uploaded the code for it here: http://dpaste.dzfl.pl/60a46049 As you can see there isn't a single mention of const in there. All I wanted was a const and an immutable version of opCall and better const correctness for opAssign, but I just couldn't get it to compile. It'd be great if you could have a look at it. If you succeed in getting that code to be const correct, please tell me how you did it. (Also worth mentioning: I ran into at least two more issues in just this one file: 1. I couldn't specify the templated opAssign that C++'s std::function has because of a compiler bug (which will be fixed in DMD 2.061) and I had to define opAssign twice because there is no way to specify a function which accepts both an rvalue and an lvalue) That being said the code still is much cleaner than it would be in C++. Another issue I've had was trying to implement my own hashtable which has more deterministic memory behavior. In that I found it very difficult to get the ranges for byKey and byValue to be const correct. I think I had issues with the inout keyword when I was passing pointers marked as inout to the range object. I think I'll revisit that one tomorrow and maybe I'll then post code here.
How do you copy a const struct to a mutable?
I want to get this to compile: void main() { struct A { this(int x) { this.x = x; } int x; } const(A) a = A(5); A b = a; } It should clearly be legal to create a non-const copy of the struct. What am I missing in order to do this? Cheers, Malte
Re: Const ref and rvalues again...
On Friday, 19 October 2012 at 13:00:52 UTC, Timon Gehr wrote: On 10/19/2012 09:53 AM, Jacob Carlborg wrote: On 2012-10-19 04:48, Timon Gehr wrote: Then how to specify that the value of x cannot be escaped? I'm in favour of doing it the other way round and disallow escaping of ref parameters without an unsafe cast. scope is supposed to be used to prevent this. Sure, but how? void goo(scope int* x){ global0 = x; // should clearly be disallowed } void foo(scope ref int*** x){ global1 = x; // ? global2 = x; // ? global3 = *x; // ? globall4 = **x; // ? } Maybe we need this: void foo(scope ref int*** x); // ? void foo(ref int(***)scope x); // no escaping of x, *x, **x void foo(ref int*(**)scope x); // may escape **x void foo(ref int**(*)scope x); // may escape *x, **x What about x? No scope should mean that you can not escape the address of something. So void goo(scope int* x) { global0 = x; } Should be allowed. Scope in this case applies to the pointer. Not to the thing it's pointing to. The scope keyword is not transitive. That wouldn't make sense. It is perfectly legal to have a scoped pointer to something allocated on the heap. Whereas void goo(scope ref int x) { global0 = x; } Should NOT be allowed. It looks like it's the same code, but in this case x is an integer. In the last example x was a pointer to an integer. So it comes down to this: void goo(scope int* x) { global0 = x; // copying is allowed //global1 = x; // referencing is not allowed }
Re: Const ref and rvalues again...
On Thursday, 18 October 2012 at 06:11:26 UTC, monarch_dodra wrote: On Thursday, 18 October 2012 at 04:30:17 UTC, Jonathan M Davis wrote: On Thursday, October 18, 2012 06:24:08 jerro wrote: What would be the problem with const ref taking rvalues? Read the thread that I already linked to: http://forum.dlang.org/thread/4f84d6dd.5090...@digitalmars.com - Jonathan M Davis I read the thread, and not a single one of the problematic cases are actually valid C++. Yes: the faulty MSVC has taught people to do retarded things, or be afraid of things that were illegal to begin with (in particular, pass an rvalue to a ref, WHICH IS ILLEGAL IN C++), such as increment(5). There is actually nothing wrong with creating a temporary when something is bound to a const ref, provided the compiler follows the rules: *Only LValues with an EXACT type match may be passed to a reference. *In regards to *const* references, RValues may be copied in a temporary, and that temporary bound the the ref. I'm not saying we particularly *need* this in D (C++ has a by ref paradigm that makes it more important, but D *rarelly* ever passes by const ref). But if the compiler respects the above two rules (which it should), then RValue to const ref is both perfectly doable and safe (as safe as refs get anyways). The problem with binding rvalues to const ref is that you could take and store the address of it. That's why I'd recommend using in ref instead. @Jonathan: I had already read the linked discussion. There are many valid points in there, but also many invalid ones (as monarch_dodra has pointed out). But I think all problems in that thread should be solved by using in ref instead of const ref because then you'd be sure that the passed-in temporary can not escape the current function. @foobar: I like the idea, but it's probably going to break down in many cases. If you have a non-trivial copy constructor you want the ability to have complete control over when it gets copied and when it doesn't. I just don't trust compilers enough to think that they'd always make the same choice that I'd make. And also about losing semantic information: That's why I proposed the second point: Give the user the option to provide a function which should be preferred for rvalues. That way you don't lose semantic information.
Re: Const ref and rvalues again...
On Friday, 19 October 2012 at 00:03:49 UTC, Timon Gehr wrote: Const is different in D and in C++. Relating const and rvalues is arbitrary and does not make a lot of sense. Regarding 'in ref'/'scope ref': What should 'scope' apply to in void foo(scope ref int* x); Not sure what you mean with relating. I'm not making any claims about there being a relationship between rvalues and constness. This is about finding a way that you can define a function which safely accepts lvalues and rvalues without having to make a copy. If we specify the argument as ref in, then we can safely pass for example the number 5 to it. And this would never break existing code, so that something like swap(5, 4) would never be possible code. For the example that you gave you'd be unable to store the address of x. So doing int** storage; void foo(scope ref int * x) { storage = x; } would be illegal. @jerro: the same thing: I'm not trying to fix the problem that you mention. I'm trying to define a function which can safely accept rvalues and lvalues without having to make a copy.
Re: How mutable is immutable?
The issue is that you're thinking as you would in Java. I guess the rule in D for immutable is this: Immutable data won't change as long as it exists. The last part of that sentence would be a stupid thing to say in Java because things don't just cease to exist while you're still doing something with them. That is not the case in D. That being said it's very unlikely that you will ever run into this situation. You have to end the lifetime of the object manually to run into these issues. And in that case it'll be very easy to figure out what's wrong.
Const ref and rvalues again...
Hello, I realize that this has been discussed before, but so far there is no solution and this really needs to be a high priority: We need a way for a function to declare that it doesn't want it's argument to be copied, but it also doesn't care whether the argument is an rvalue or an lvalue. The C++ way of doing this would be to declare the argument as a const . Apparently it is not desired that we do the same thing for const ref. Currently, if you want that behavior, you have to write 2^n permutations of your function, with n being the number of arguments that the function takes. Here's my attempt at passing a struct to a function that takes three arguments without the struct being copied: int copyCounter = 0; struct CopyCounter { this(this) { ++copyCounter; } } void takeThree(ref in CopyCounter a, ref in CopyCounter b, ref in CopyCounter c) { writeln(took three); } void takeThree(in CopyCounter a, ref in CopyCounter b, ref in CopyCounter c) { takeThree(a, b, c); } void takeThree(ref in CopyCounter a, in CopyCounter b, ref in CopyCounter c) { takeThree(a, b, c); } void takeThree(ref in CopyCounter a, ref in CopyCounter b, in CopyCounter c) { takeThree(a, b, c); } void takeThree(in CopyCounter a, in CopyCounter b, ref in CopyCounter c) { takeThree(a, b, c); } void takeThree(in CopyCounter a, ref in CopyCounter b, in CopyCounter c) { takeThree(a, b, c); } void takeThree(ref in CopyCounter a, in CopyCounter b, in CopyCounter c) { takeThree(a, b, c); } void takeThree(in CopyCounter a, in CopyCounter b, in CopyCounter c) { takeThree(a, b, c); } static CopyCounter createCopyCounter() { return CopyCounter(); } void main() { CopyCounter first; CopyCounter second; CopyCounter third; takeThree(first, second, third); takeThree(createCopyCounter(), second, createCopCounter()); assert(copyCounter == 0); // yay, works } My propsed solution is this: - Make functions that take ref in arguments also accept rvalues. - The user can still provide an overload that accepts an rvalue, using the in keyword, and that one will be preferred over the ref in version. What do you think? Malte
Re: What is the case against a struct post-blit default constructor?
First of all thank you for the detailed responses. I wrote a response yesterday but somehow the website seems to have swallowed it. On Thursday, 11 October 2012 at 12:43:31 UTC, Andrei Alexandrescu wrote: We could (after all, C++ does it). There are a few disadvantages to doing so, however. 1. Defining static data is more difficult. Currently, all static data is statically-initialized. With default constructors, we'd need to define the pre-construction state of such objects anyway, and then change the compiler to call constructors prior to main(). I find the current design simpler and easier to use. This is a good reason. I like the idea of no code gets run before main Running code before main only lead to problems in C++. However those problems were always merely inconvenient, never big issues. I think it's not good to allow people to run code before main, but I think it's a bigger problem to have no default constructors. 2. Creating a temporary object cannot be anymore assumed to be a O(1), no-resources-allocated deal. Instead, generic code must conservatively assume that objects are always arbitrarily expensive to create. That makes some generic functions more difficult to implement. I think that is OK. The generic algorithm should assume that your object is cheap to create. In C++ all algorithms assume this and there are few issues. Sure, every now and then you pass an expensive-to-create object to an algorithm which creates instances, but that bug is very easy to debug. 3. Two-phase object destruction (releasing state and then deallocating memory), which is useful, is made more difficult by default constructors. Essentially the .init pre-default-constructor state intervenes in all such cases and makes it more difficult for language users to define and understand object states. I'm not sure that I understand this. My two ways of interpreting this are: A) You mean that the compiler currently assumes that it doesn't have to call the destructor for objects that are at init. But after introducing a default constructor it would always have to call the destructor. I think that's OK. That's an optimization that's unlikely to give you much gain for types that need a destructor. B) You mean that if we introduce a default constructor, there would still be situations where an object is at init and it's destructor gets called. For example if people throw exceptions. And users might be confused by this when their destructor gets run and their object is at init, instead of the state that they expect. I think this is OK. It is the same situation that we currently have with static opCall(). Yes, with the static opCall() hack people kinda expect that their object isn't always initialized, so their destructors probably react better to the state being at init, but I think if the documentation states clearly there are situations where the destructor will be called on an object whose default constructor was not called then people can handle that situation just fine. 4. Same as above applies to an object post a move operation. What state is the object left after move? C++'s approach to this, forced by the existence of default constructors and other historical artifacts, has a conservative approach that I consider inferior to D's: the state of moved-from object is decided by the library, there's often unnecessary copying, and is essentially unspecified except that it's valid so the moved-from object can continue to be used. This is in effect a back-door introduction of a no-resources-allocated state for objects, which is what default constructors so hard tried to avoid in the first place. For moving you'd just have to define a state that the source object is in after moving. Since it's a destructive move I would expect the object to be at init after moving, as if the destructor had been called. If that is well defined, then I think users will be fine with it. This is actually the situation that we currently have, and users seem to be fine with it. This can be achieved with a tiny change to the current implementation of std.algorithm.move: Make it memcpy from init instead of a statically allocated value. I'd also like it if we could write all structs so that init is a valid state of the struct, as Walter suggests. However this is going to make certain things impossible in the language. Simple things like having shared data between multiple instances of a struct. Or counting how often objects of a certain type was allocated. Or iterating over all instances of a type. In fact there are parts of the standard library that don't work because they'd need a default constructor. One of the linked posts mentions this example from std.typecons: import std.typecons; { RefCounted!(int, RefCountedAutoInitialize.yes) a; assert(a == 0); // works RefCounted!(int, RefCountedAutoInitialize.no) b = a; assert(b
Re: What is the case against a struct post-blit default constructor?
Hi, thanks for the detailed answers. So I am very much for keeping init. I just want that if the user specifies a default constructor, it is being called after the value has been initialized to init. On Wednesday, October 10, 2012 21:11:29 foobar wrote: Arrays - without changing existing syntax we can use these semantics: auto a = new int[](5); // compiler calls T() for each instance int[12] b; // ditto And what on earth does that buy you over init? That's what init _does_. And since the value needs to be known at compile time (otherwise arrays won't work for directly initializing _anything_ that needs to be initialized at compile time), a constructor really doesn't buy you anything here at all. init provides a nice, consistent way of initializing or assigning a value to a variable as well as providing a consistent default state for a type when you need to be able to set a variable of that type to a consistent, safe state (e.g. with std.algorithm.move). And as built-in types don't _have_ constructors, there's no other way for generic code to generically initialize anything. What does this buy you over init? This would help with structs that can't be initialized to a valid value at compile time. So what I expect to happen in a line like S[12] s; Is that they all get blitted to init, followed by a loop that calls the default constructor on each of these. If there is no default constructor, they stay at init and the loop doesn't happen. This would work with user defined types and with built-in types. If a constructor throws an exception, then the array is correctly initialized up to the element before the throwing one. The remaining elements are at init. For member variables I expect this to happen: If one of your member variables has a default constructor but you do not, then the compiler will generate an empty default constructor for you. This gives your object the same behavior in arrays as described above, which means that the member variable will always be correctly initialized using both init and the deafult constructor. If one of your member variables has a default constructor, and so do you, then the member variable's default constructor is called before your default constructor. If an exception is thrown, the containing object remains at the state it is in (most likely init) If you do not want the default constructor of your member variable to be called, you can declare it as S s = S.init; For emplace I expect that the default constructor gets called. For std.algorithm.move you'd have to define which state the source object is in after moving. Since it's a destructive move, I'd expect the object to be at init, as if a destructor had been called. You could implement that with a tiny change to the current implementation. (memcpy from init instead of a statically allocated instance) This should cover all the cases that you mentioned. It is highly performant (in fact this is very close to the behavior in C++, but faster because it uses init) and it won't affect structs that can be initialized at compile time. It will only be used for cases where you need to do things at runtime, and the users have the full ability to shoot themselves in the foot if they want to.
What is the case against a struct post-blit default constructor?
So this has been brought up many times (http://www.digitalmars.com/d/archives/digitalmars/D/Struct_no-arg_constructor_173172.html http://www.digitalmars.com/d/archives/digitalmars/D/learn/Default_constructor_for_structs_20997.html http://www.digitalmars.com/d/archives/digitalmars/D/struct_and_default_constructor_150016.html) However there was never a good answer. I would like a struct default constructor. My expected behavior for it is that the struct gets initialized to .init, then my destructor gets called so that I can do additional things if I want. This destructor always gets called when my struct is created without arguments. So for example struct S { this() { assert(bar == 10); foo = [5].ptr; } int * foo; int bar = 10; } S s; assert(*s.foo == 5); Possible cases against it: - It would be slower than just initializing to .init. My proposed solution: Make the default constructor optional. If I have a struct that doesn't define a default constructor, it is just intialized to .init. So I can have the speed if I want to. Also always run it post-blit (blitted from .init). Meaning I only need to use it for things that can only be initialized at runtime. - There already is a solution in @disable this(); static opCall() {...}. This is hacky and working against the language. It also makes it so that you can not allocate your struct on the heap. - Structs should be simple. I haven't heard this argument, but I could imagine someone making it. I think structs should not be simple. They are much too useful for that. Also them having copy constructors and opAssign indicates that structs aren't expected to be simple. - There would be a way around it by doing S s = S.init; I don't think that's a problem. If users want to shoot themselves in the foot, let em. The important part is that they have to go out of their way to do it. You could also handle that case in the copy constructor or assignment operator. (which is an improvement to the current behavior where you have to handle that case in every single member function, see for example std.typecons.RefCounted) So I really can't think of a reason for why you wouldn't want this. Yet this discussion has happened several times already. There is clear demand for it and very good reasons, such as those mentioned in all the linked discussions. So why is this being rejected? Cheers, Malte