www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Default initialization no longer a thing

reply IGotD- <nise nise.com> writes:
I've recently seen that modern program languages are going away 
from default initialization. D early recognized no initialization 
being one of the many flaws in C/C++ and added default 
initialization which greatly improved stability which has been 
the standard for many languages since. C++ "fixed" this very 
recently but really not.

Now even more modern languages are going away from default 
initialization as some claim that default initialization was a 
source of bugs. The implementation might differ, some must give a 
variable a value at declaration others detect use before assign.

What is your take on this and if D would ever be modernized, is 
this something that D should consider?
Oct 23 2023
next sibling parent reply matheus <matheus gmail.com> writes:
On Monday, 23 October 2023 at 18:54:45 UTC, IGotD- wrote:
 ...
 Now even more modern languages are going away from default ...
Could you please share a few examplesnames of these modern languages? By the way I have mixed feelings abouts this subject, I read pro/con about this, but I really think "DI" is not going to fix much of the problem. Matheus.
Oct 23 2023
parent IGotD- <nise nise.com> writes:
On Monday, 23 October 2023 at 19:15:29 UTC, matheus wrote:
 Could you please share a few examplesnames of these modern 
 languages?
Swift and Dart for example.
Oct 23 2023
prev sibling next sibling parent reply claptrap <clap trap.com> writes:
On Monday, 23 October 2023 at 18:54:45 UTC, IGotD- wrote:
 Now even more modern languages are going away from default 
 initialization as some claim that default initialization was a 
 source of bugs. The implementation might differ, some must give 
 a variable a value at declaration others detect use before 
 assign.
The bug is using a variable before it has been assigned the **correct** value. Default initialisation doesn't solve that problem, only makes the side effects less onerous. Less likely to give weird results. If you have a variable that needs to be initialised via a large switch, you declare it up front, and it is set in the switch. It would be more useful to know if you forgot to set it in one of the case statements that it would be to have it default initialised to zero or be told it needs to be initialised at the declaration. But tracking the use of uninitialized variables like that is probably pretty difficult / expensive for the compiler.
Oct 23 2023
parent IGotD- <nise nise.com> writes:
On Monday, 23 October 2023 at 20:34:31 UTC, claptrap wrote:
 But tracking the use of uninitialized variables like that is 
 probably pretty difficult / expensive for the compiler.
Not sure if computers have become fast enough so that we can do this without compile times becoming insanely slow have anything to do with it. Imagine a Rust compiler running on 16MHz 386 during the 80s.
Oct 23 2023
prev sibling next sibling parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Monday, October 23, 2023 12:54:45 PM MDT IGotD- via Digitalmars-d wrote:
 I've recently seen that modern program languages are going away
 from default initialization. D early recognized no initialization
 being one of the many flaws in C/C++ and added default
 initialization which greatly improved stability which has been
 the standard for many languages since. C++ "fixed" this very
 recently but really not.

 Now even more modern languages are going away from default
 initialization as some claim that default initialization was a
 source of bugs. The implementation might differ, some must give a
 variable a value at declaration others detect use before assign.

 What is your take on this and if D would ever be modernized, is
 this something that D should consider?
Default initialization is too baked into D for it to change at this point, and there are features that we have which you can't have without it (at least not without having objects being garbage, because they haven't been given a value yet). It's why disabling default initialization on structs can be quite annoying, since it results in them not working in a number of places (particularly with regards to arrays). In general though, if you want to avoid issues with objects being used before they're properly initialized, you have two options: 1. Have default initialization so that it's guaranteed that the object will have a value even if it's ever used before it has the value that you want it to actually have. 2. Make the compiler smart enough to catch when a variable is used before it's initialized and make it an error, thereby forcing explicit initialization of all variables before they're used. The second approach works in a number of cases, but inevitably, the compiler is not smart enough to correctly determine whether a variable has actually been initialized in all cases, forcing you to give it a value when it shouldn't be necessary (this is something that can happen in Java quite easily). And it's _not_ something that is actually fully solvable, because it's possible that whether a variable has been initialized yet or not depends on runtime logic which is affected by stuff outside of that function, which the programmer is aware of, but the compiler can't be due to separate compilation (though arguably, if the logic is separated enough from the variable's initialization, it should be given a value regardless just to be safe, since the other code could change without the variable's initialization code being altered appropriately). It becomes easier for the compiler if you simply require that the variable be given a value when it's declared, but that arguably just makes the problem worse, because then you're forced to give the variable a value before you want to in any situation where you need to declare it before giving it the actual value that you want to give it. And ultimately, it results in the programmer manually doing what default initialization would have done and give the variable a value that they don't actually want to use but which will at least not be garbage. However, arguably, an even bigger issue is initialization that doesn't necessarily involve a variable. For instance, you could have something like auto arr = new int[](10); or foo(new int[](10)); In D, all of the array's elements are default-initialized to the init value of the element type, so no garbage is involved, but what if you had no default initialization? You'd be forced to do something like auto arr = new int[](10, value); and set all of the elements in the array to some programmer-provided value, which really isn't any better than using a default value and might even be less efficient given that the compiler knows the type's init value at compile time, but it wouldn't know what the value would be if it's provided at runtime. Various other aspects of arrays also depend on the default value and really can't be done without it. E.G. arr.length += 20; isn't going to work without a default value. Without that, you'd be forced to append or use a different syntax that provided your own value to use as the default before you go and assign it what you actually want it to be later. Default values also make implementing the logic in user-defined types easier and safer (especially in classes with inheritance), because the compiler can rely on everything having an actual value before the constructors run. Having something like immutable does actually force you to implement a lot of the same logic that you'd have to have without default initialization, so D can't simplify how constructors work with regards to code flow analysis quite as much as might be nice, but a language without immutable or const could forgo a lot of the code flow analysis that languages typically have to do for constructors in the face of inheritance, because it could know that the member variables wouldn't be garbage. With D, the compiler knows that they're not garbage but has to make sure that it doesn't reassign values to any const or immutable member variables. There are certainly cases where default-initialized objects can be a problem (e.g. when you end up with a null pointer or reference), and in some cases, having default values can be problematic (which is why the ability disable default initialization was added to structs in D), so there's certainly an argument for requiring initialization in some cases rather than relying on a default value, but in general, having default values for all types is far more flexible than requiring that the compiler track whether a variable is initialized before it's used. So, I think that D made the right choice, but it's not particularly surprising if a number of the newer languages out there have made a different choice. Ultimately though, I don't think that it's possible to prevent bugs with regards to initializing variables with default values that shouldn't actually be used, because even if you don't have default values in the language, there will always be cases where programmers have to give a variable a default value of some kind anyway, because the compiler can't always correctly determine whether a variable is used before it's initialized if it allows deferring initialization (and if it doesn't allow defering initialization, then you'll end up with user-decided default values that much more frequently). - Jonathan M Davis
Oct 23 2023
prev sibling next sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Monday, 23 October 2023 at 18:54:45 UTC, IGotD- wrote:
 What is your take on this and if D would ever be modernized, is 
 this something that D should consider?
Most of the time, default initialization is what you want, and it doesn't cause any problems. So I think having default initialization by default but allowing the programmer to opt out is probably the right way to handle this. Currently, D allows you to ` disable this()` for user-defined types, but it doesn't give you any way to opt out of `T.init`. This is something that should be improved. If disabling `T.init` entirely is too disruptive, there should at least be a way to make `T.init` accessible only in ` system` code.
Oct 23 2023
next sibling parent deadalnix <deadalnix gmail.com> writes:
On Monday, 23 October 2023 at 22:45:29 UTC, Paul Backus wrote:
 On Monday, 23 October 2023 at 18:54:45 UTC, IGotD- wrote:
 What is your take on this and if D would ever be modernized, 
 is this something that D should consider?
Most of the time, default initialization is what you want, and it doesn't cause any problems. So I think having default initialization by default but allowing the programmer to opt out is probably the right way to handle this. Currently, D allows you to ` disable this()` for user-defined types, but it doesn't give you any way to opt out of `T.init`. This is something that should be improved. If disabling `T.init` entirely is too disruptive, there should at least be a way to make `T.init` accessible only in ` system` code.
disable this plain doesn't work. It prevent things in some cases, but utltimately fails to enforce the invariant it sets out to enforce.
Oct 23 2023
prev sibling parent zjh <fqbqrr 163.com> writes:
On Monday, 23 October 2023 at 22:45:29 UTC, Paul Backus wrote:

 Currently, D allows you to ` disable this()` for user-defined 
 types, but it doesn't give you any way to opt out of `T.init`. 
 This is something that should be improved.
Right!
Oct 23 2023
prev sibling parent reply Guillaume Piolat <first.name gmail.com> writes:
On Monday, 23 October 2023 at 18:54:45 UTC, IGotD- wrote:
 What is your take on this and if D would ever be modernized, is 
 this something that D should consider?
Sorry don't have any issue with T.init. It's not like because it's in D and have not changed for 5 years that it must be bad.
Oct 24 2023
parent reply Hipreme <msnmancini hotmail.com> writes:
On Tuesday, 24 October 2023 at 15:30:33 UTC, Guillaume Piolat 
wrote:
 On Monday, 23 October 2023 at 18:54:45 UTC, IGotD- wrote:
 What is your take on this and if D would ever be modernized, 
 is this something that D should consider?
Sorry don't have any issue with T.init. It's not like because it's in D and have not changed for 5 years that it must be bad.
Nope, default initialization is the best thing that could have been created. After people created typescript because not having types was a mistake, the second think we got was default initialization. The only problem I ever had with D was float being initialized to nan instead of 0. This has been talked a lot of times now. If you read the post from Sonke, you can see that D is not being how simple it was from before from the addition of lot of keywords: `pure`, `nothrow`, ` nogc`, `scope`, `return`. I don't want any more verbosity than that, so all hail default initialization :D
Oct 24 2023
next sibling parent bachmeier <no spam.net> writes:
On Tuesday, 24 October 2023 at 15:39:09 UTC, Hipreme wrote:

 If you read the post from Sonke, you can see that D is not 
 being how simple it was from before from the addition of lot of 
 keywords: `pure`, `nothrow`,  ` nogc`, `scope`, `return`. I 
 don't want any more verbosity than that, so all hail default 
 initialization :D
The nice thing about that clutter is that you can (for now, at least) avoid uglifying your own code with it. I don't use any of them and don't even know what most of them do.
Oct 24 2023
prev sibling next sibling parent Salih Dincer <salihdb hotmail.com> writes:
On Tuesday, 24 October 2023 at 15:39:09 UTC, Hipreme wrote:
 The only problem I ever had with D was float being initialized 
 to nan instead of 0. This has been talked a lot of times now. 
 If you read the post from Sonke, you can see that D is not 
 being how simple it was from before from the addition of lot of 
 keywords: `pure`, `nothrow`,  ` nogc`, `scope`, `return`. I 
 don't want any more verbosity than that, so all hail default 
 initialization :D
I don't like using so many attributes either. Fortunately, your code usually works even when you don't use it :) On Tuesday, 24 October 2023 at 01:35:16 UTC, deadalnix wrote:
  disable this plain doesn't work. It prevent things in some 
 cases, but utltimately fails to enforce the invariant it sets 
 out to enforce.
The default constructor doesn't always work the way I want. Let's talk some code. Test1 and test2 are ok but the third one is something I came across recently: ```d void main() {    string data;    assert(data is null);    /** TEST 1 **/    struct String    {        string data; }    String s;    assert(s.data is null);    auto s2 = String();    assert(s2.data is null);    /** TEST 2 **/    struct Ztring {        string data;        this(string data)        {            this.data = data;        }   }    Ztring z;    assert(z.data is null);    auto z2 = Ztring("D");    assert(!(z2.data is null));    /** TEST 3 **/    struct Foo {        int[] data;        this(int[] data)        {            this.data = data;            if(this.data.capacity < 4)            {                this.data.length = 20;            }        }    }    auto l = Foo([1, 2, 3]);    assert(l.data.capacity > 4); } ``` I don't want my code to run with the default feature, but it shouldn't take any constructor parameters either. What I want is to increase the capacity of one of the members at compile time while it is initialized. SDB 79
Oct 24 2023
prev sibling parent reply Julian Fondren <julian.fondren gmail.com> writes:
On Tuesday, 24 October 2023 at 15:39:09 UTC, Hipreme wrote:
 On Tuesday, 24 October 2023 at 15:30:33 UTC, Guillaume Piolat 
 wrote:
 Sorry don't have any issue with T.init.
 It's not like because it's in D and have not changed for 5 
 years that it must be bad.
Nope, default initialization is the best thing that could have been created. After people created typescript because not having types was a mistake, the second think we got was default initialization. The only problem I ever had with D was float being initialized to nan instead of 0. This has been talked a lot of times now.
There are really different ideas that are getting conflated because the implementation of those ideas is so similar. The justification of NaN is that it makes errors more obvious - because failing to initialize variables is an error - which has strange implications for people deliberately not initializing variables in the presence of the feature. In cases other than NaN, the default value at least results in consistent behavior when not initializing them was a logical error. But, 1. people very naturally rely on this behavior, and deliberately not initialize variables. 2. default initialization prevents tooling like valgrind or libsanitizer from complaining about code relying on uninitialized data. And because also can't be adapted to D now. So I think this error-focused idea is a bad one. Of D's hits and misses, it's really a miss. Maybe that's why Swift and co. are leaving it. Nobody's talked about about their reasons yet. Fortunately, apart from NaN, it is functionally identical to a good idea: zeroing everything and having the zero value be useful and not an error. Zero Is Initialization (ZII, imitating RAII). The zero list is the empty list and you can push new values onto it. The zero vector is the empty vector and you can do likewise. This isn't automatic, of course - it's very easy to write code that segfaults on zero values. And although Go popularized zero values it's still an error to work with the zero value of a Go hash table. So I think this idea also hasn't really arrived yet. It's just a trick that some people like to do, and there are some languages that sort of do it.
Oct 24 2023
parent Julian Fondren <julian.fondren gmail.com> writes:
On Tuesday, 24 October 2023 at 20:38:08 UTC, Julian Fondren wrote:
 So I think this error-focused idea is a bad one. Of D's hits 
 and misses, it's
 really a miss.
I see I've forgotten how to post here. Simpler: error-oriented default initialization fails to account for programmer risk homeostasis. People are too aware of it for it to fulfill its function. But it's also a 'hit' like it's a hit to buy a toy for your cat, take the toy out of the box, and find that the cat ignores the toy and plays with the box.
Oct 24 2023