January 23, 2019
On Saturday, 19 January 2019 at 10:05:22 UTC, Dru wrote:
> What is the idea behind why we can't define default ctor for structs?
>
> In current situation I need to "@disable this()"
> then define a constructor with dummy arguments  (because my constructor does not need arguments)
>
> It is a big pain on syntax

Short answer: make T.init a value, and have your destructor be able to deal with T.init

January 23, 2019
On Wednesday, 23 January 2019 at 13:02:43 UTC, Guillaume Piolat wrote:
> make T.init a value

Erratum: a _valid_ value
January 31, 2019
On Tuesday, 22 January 2019 at 02:18:37 UTC, Jonathan M Davis wrote:
> It also would be bad for porting code to D from languages like C++, because without extra work from the programmer, the code would assume that this() was a default constructor when it wasn't, making it easy to end up with subtle bugs. By outright making this() illegal, D forces the programmer to deal with the situation rather than allowing silent bugs.

D could solve this by only allowing a nullary constructor when there's `@disable this();`. The fact that `@disable this()` exists undermines the reason for a blanket ban on `this(){...}`, and I expect it's this way just because disable this was added later. This is worth having and would support Mutex, HourGlass, etc.

Besides runtime immutable initialization not working in a free function 'constructor' as you mentioned, not allowing a nullary constructor breaks the variadic constructor pattern in generic code when no arguments are passed.

January 31, 2019
On Thursday, January 31, 2019 4:42:35 AM MST Nick Treleaven via Digitalmars- d wrote:
> On Tuesday, 22 January 2019 at 02:18:37 UTC, Jonathan M Davis
>
> wrote:
> > It also would be bad for porting code to D from languages like C++, because without extra work from the programmer, the code would assume that this() was a default constructor when it wasn't, making it easy to end up with subtle bugs. By outright making this() illegal, D forces the programmer to deal with the situation rather than allowing silent bugs.
>
> D could solve this by only allowing a nullary constructor when there's `@disable this();`. The fact that `@disable this()` exists undermines the reason for a blanket ban on `this(){...}`, and I expect it's this way just because disable this was added later. This is worth having and would support Mutex, HourGlass, etc.
>
> Besides runtime immutable initialization not working in a free function 'constructor' as you mentioned, not allowing a nullary constructor breaks the variadic constructor pattern in generic code when no arguments are passed.

The main problem with allowing a constructor with no parameters when you @disable this(); is that it wouldn't act like a default constructor and really couldn't act like one in general, because too much is designed around using init. To make it work, you'd have to start making stuff work one way with init normally and another way when @disable this() was present, which would be confusing and likely error-prone.

And yes, the issues with @disable this(); stem from the fact that it was shoehorned into the language later. D was very much designed around the idea that all types are always default initialized, and any attempt to work around that starts causing problems. @disable this(); is rather similar to = void; in that regard. There are cases where it makes sense to use them, but you need to know what you're doing, and their use should be quite rare. They're basically backdoors to force the language to do something that it's really not designed to do.

Also, it's perfectly possible to use a factory function to create immutable objects. Worst case, you have to cast to immutable in the factory function, but it works just fine. AFAIK, aside from stuff that requires that the type be default-initialized, the only thing that you can't really do with @disable this(); is to completely guarantee that all objects are constructed via the factory method, because the init value for the type still exists and can still be used. It just isn't used for default initialization. So, having a type with @disable this(); that does not take the init value into account can cause bugs. But all of the other stuff with regards to immutable and the like can still be done. It just can't necessarily be done in an @safe manner.

- Jonathan M Davis



February 07, 2019
On Thursday, 31 January 2019 at 15:41:28 UTC, Jonathan M Davis wrote:
> The main problem with allowing a constructor with no parameters when you @disable this(); is that it wouldn't act like a default constructor and really couldn't act like one in general, because too much is designed around using init. To

I'm not asking for a default constructor, only an explicit nullary argument ctor.

> Also, it's perfectly possible to use a factory function to create immutable objects. Worst case, you have to cast to immutable in the factory function, but it works just fine.

Have you changed your opinion? You said only that "in some situations" casts can be used:

"The only downside that I can think of at the moment for using a factory function over having this() as a non-default constructor is that when constructing immutable objects, the constructor usually has to do it (though in some situations, casts could be used - that depends primarily on whether the data is guaranteed to be unique). So, such a factory function would require a special constructor with dummy arguments or something similar in order to construct immutable objects."

> AFAIK, aside from stuff that requires that the type be default-initialized, the only thing that you can't really do with @disable this(); is to completely guarantee that all objects are constructed via the factory method, because the init value for the type still exists and can still be used. It just isn't used for default initialization. So, having a type with @disable this(); that does not take the init value into account can cause bugs.

struct S
{
    static @disable S init;
    ...

> But all of the other stuff with regards to immutable and the like can still be done. It just can't necessarily be done in an @safe manner.

This is a significant downside, you can't have a @safe struct that requires runtime calls for its construction but no arguments.

February 07, 2019
On Thursday, 7 February 2019 at 11:14:47 UTC, Nick Treleaven wrote:
> On Thursday, 31 January 2019 at 15:41:28 UTC, Jonathan M Davis wrote:
>> The main problem with allowing a constructor with no parameters when you @disable this(); is that it wouldn't act like a default constructor and really couldn't act like one in general, because too much is designed around using init. To
>
> I'm not asking for a default constructor, only an explicit nullary argument ctor.
>
>> Also, it's perfectly possible to use a factory function to create immutable objects. Worst case, you have to cast to immutable in the factory function, but it works just fine.
>
> Have you changed your opinion? You said only that "in some situations" casts can be used:
>
> "The only downside that I can think of at the moment for using a factory function over having this() as a non-default constructor is that when constructing immutable objects, the constructor usually has to do it (though in some situations, casts could be used - that depends primarily on whether the data is guaranteed to be unique). So, such a factory function would require a special constructor with dummy arguments or something similar in order to construct immutable objects."
>
>> AFAIK, aside from stuff that requires that the type be default-initialized, the only thing that you can't really do with @disable this(); is to completely guarantee that all objects are constructed via the factory method, because the init value for the type still exists and can still be used. It just isn't used for default initialization. So, having a type with @disable this(); that does not take the init value into account can cause bugs.
>
> struct S
> {
>     static @disable S init;
>     ...
>
>> But all of the other stuff with regards to immutable and the like can still be done. It just can't necessarily be done in an @safe manner.
>
> This is a significant downside, you can't have a @safe struct that requires runtime calls for its construction but no arguments.

It seems to me that the only argument I've heard to not allow default construction is because people will get confused as to why array initialization doesn't use the constructor, and maybe some other cases. But, at the same time, the difference between construction and initialization is a said to be a "core concept" of D. So this seems quite reasonably solved with some documentation and just being more explicit about the separation between construction and initialization?

It certainly beat the (exaggerated) weekly forum posts asking for default struct construction and why it's not allowed (speaking of confusing people) :)

Cheers,
- Ali
February 08, 2019
On Thursday, February 7, 2019 4:14:47 AM MST Nick Treleaven via Digitalmars- d wrote:
> On Thursday, 31 January 2019 at 15:41:28 UTC, Jonathan M Davis
>
> wrote:
> > The main problem with allowing a constructor with no parameters when you @disable this(); is that it wouldn't act like a default constructor and really couldn't act like one in general, because too much is designed around using init. To
>
> I'm not asking for a default constructor, only an explicit nullary argument ctor.
>
> > Also, it's perfectly possible to use a factory function to create immutable objects. Worst case, you have to cast to immutable in the factory function, but it works just fine.
>
> Have you changed your opinion? You said only that "in some situations" casts can be used:
>
> "The only downside that I can think of at the moment for using a factory function over having this() as a non-default constructor is that when constructing immutable objects, the constructor usually has to do it (though in some situations, casts could be used - that depends primarily on whether the data is guaranteed to be unique). So, such a factory function would require a special constructor with dummy arguments or something similar in order to construct immutable objects."

At the moment, the only situations that I can think of where casting to immutable would not work are actually situations where you couldn't use a constructor anyway. The problem is that you can't cast data that's not guaranteed to be unique to immutable, or you risk violating the type system. With a constructor that did no casting, that would mean that you could only accept data that was either immutable or implicitly convertible to immutable. Anything else wouldn't compile. So, to get around that, you would have to cast just like you'd need to do with a factory function, and you'd then be at risk of violating the type system whenever the data was not actually unique.

Because the factory function would have to cast, the programmer would have to be more careful about making sure that they didn't cast anything that wasn't guaranteed to be unique (whereas in a constructor with no casts, you wouldn't have to worry about that), so it's @trusted and riskier, but it works so long as you're appropriately careful.

Having a pure factory function would potentially fix the need for casting, but if you're trying to create a default constructor, odds are that it can't be pure anyway. If it could, then it's almost guaranteed that you could just put everything in the init value and not need a constructor - though there are some situations where that still wouldn't work - e.g. initializing a member variable that was an AA (since AA's don't currently travel from compile time to runtime) or when you wanted a dynamic array with known values but where each instance of the struct gets a dynamic array referring to unique memory rather than all instances sharing the same memory like you get with the init value.


> > AFAIK, aside from stuff that requires that the type be default-initialized, the only thing that you can't really do with @disable this(); is to completely guarantee that all objects are constructed via the factory method, because the init value for the type still exists and can still be used. It just isn't used for default initialization. So, having a type with @disable this(); that does not take the init value into account can cause bugs.
>
> struct S
> {
>      static @disable S init;
>      ...

I'm surprised that you can do that at the moment. I thought that that was at least deprecated by now. TypeInfo was specifically fixed a while back so that it didn't have an init function so that we could deprecate the ability to declare any kind of override for init, because allowing it causes problems. One example is that it causes serious problems with metaprogramming, because init is _the_ reliable way to get your hands on an instance of a type. It was quite purposefully the case that @disable this(); had no effect on the ability to reference this, because too much relies on being able to access it. Trying to make it so that you cannot rely on init existing would be extremely disruptive.

Now, even then, @disabling init doesn't actually get rid of the init value. It's still there and used to do stuff like initialize the struct prior to the constructor being called.

Also, interestingly, I just tried

struct S
{
    @disable this();
    static @disable S init;
}

and it won't compile, because that init variable uses default initialization. That can be gotten around be declaring something like

static @disable S init();

instead, but really, trying to get around the fact that types have init values in D is like trying to plug holes in a cheese grater.

Anyone who wants to try to add default constructors to D is free to create a DIP to do so, but I expect that anyone who attempted it would have a serious battle ahead of them. You would need an extremely good understanding of exactly how the init value works and everywhere that it is used and why to even attempt to come up with a proposal to inject default constructors that would work (assuming that it's even possible to make init and default constructors interact in a sane manner). And even assuming that you had the appropriate technical knowledge to correctly indicate exactly how default constructors would work to be able to integrate with the existing language, I expect that convincing Walter and Andrei that it was worth it would not be an easy task.

> > But all of the other stuff with regards to immutable and the like can still be done. It just can't necessarily be done in an @safe manner.
>
> This is a significant downside, you can't have a @safe struct that requires runtime calls for its construction but no arguments.

It could be @trusted. It's just that it's up to the programmer to verify it. And sure, that's not ideal, but @safe can't be used everywhere without the programmer having to deal with @trusted to make it work occasionally, and we're talking about a pretty niche situation here with trying to have something similar to a default constructor for an immutable object. Regardless, with how D relies on init, that's just the way that it is.

- Jonathan M Davis



1 2 3
Next ›   Last »