April 09, 2014
Am 09.04.2014 20:42, schrieb Walter Bright:
> On 4/9/2014 7:59 AM, Benjamin Thaut wrote:
>> What do you think? C&C welcome.
>
> Or you could use a factory function:
>
>    struct Foo {
>      static Foo factory() { ... }
>      ...
>    }
>
>    auto foo = Foo.factory();
>
>

But I don't want the construction  to be syntacically any different. I know there are workarounds, but after all they are workarounds.
April 09, 2014
Am 09.04.2014 19:05, schrieb Jacob Carlborg:
>
> What's the advantage over using a static opCall, that it works with "new"?
>


That you can use it together with @disable this();
April 09, 2014
On Wednesday, 9 April 2014 at 18:47:41 UTC, Benjamin Thaut wrote:
> Thats easy to answer. What would it do if you replace the "struct" with "class" and the "void" with nothing?

This thread is giving me some fun ideas for static analysis rules.
April 09, 2014
Am 09.04.2014 20:33, schrieb Timon Gehr:
> On 04/09/2014 04:59 PM, Benjamin Thaut wrote:

> Why not just:
>
> struct Foo{
>      this(){
>          // do stuff here
>      }
> }
>
> void main(){
>      Foo foo1; // error, no init value
>      auto foo2=Foo(); // ok
> }

Because then the user might think, that the default constructor gets called implicitly by the compiler. Just like in C++. But as that is not the case the syntax should be different to indicate that a struct might still be instaniated just using T.init.

Kind Regards
Benjamin Thaut
April 09, 2014
Am 09.04.2014 20:53, schrieb Brian Schott:
> On Wednesday, 9 April 2014 at 18:47:41 UTC, Benjamin Thaut wrote:
>> Thats easy to answer. What would it do if you replace the "struct"
>> with "class" and the "void" with nothing?
>
> This thread is giving me some fun ideas for static analysis rules.

Just saying, if you do the same with a class, the default constructor is picked and not the one with the default argument. So it should do the same for structs.
April 09, 2014
On 04/09/2014 08:53 PM, Benjamin Thaut wrote:
> Am 09.04.2014 20:33, schrieb Timon Gehr:
>> On 04/09/2014 04:59 PM, Benjamin Thaut wrote:
>
>> Why not just:
>>
>> struct Foo{
>>      this(){
>>          // do stuff here
>>      }
>> }
>>
>> void main(){
>>      Foo foo1; // error, no init value
>>      auto foo2=Foo(); // ok
>> }
>
> Because then the user might think, that the default constructor gets
> called implicitly by the compiler.

This would be pointed out by the compiler. (i.e. it is an error instead of an implicit call.)

> Just like in C++. But as that is not
> the case the syntax should be different to indicate that a struct might
> still be instaniated just using T.init.
>
> Kind Regards
> Benjamin Thaut

What would be an use case for a bypassable default constructor?
April 09, 2014
On Wednesday, 9 April 2014 at 18:53:20 UTC, Brian Schott wrote:
> On Wednesday, 9 April 2014 at 18:47:41 UTC, Benjamin Thaut wrote:
>> Thats easy to answer. What would it do if you replace the "struct" with "class" and the "void" with nothing?
>
> This thread is giving me some fun ideas for static analysis rules.

As of a minute ago D-Scanner will warn about the following code:

class TestClass
{
	this() { i = 10; }
	this(int i = 20) { this.i = i; }
	int i;
}

struct Bogus
{
	this(int x = 0) {}
}

test.d(1:7)[warn]: This class has a zero-argument constructor as well as a constructor with one default argument. This can be confusing
test.d(10:2)[warn]: This struct constructor can never be called with its default argument.
April 09, 2014
Am 09.04.2014 21:02, schrieb Timon Gehr:
> On 04/09/2014 08:53 PM, Benjamin Thaut wrote:
>> Am 09.04.2014 20:33, schrieb Timon Gehr:
>>> On 04/09/2014 04:59 PM, Benjamin Thaut wrote:
>>
>>> Why not just:
>>>
>>> struct Foo{
>>>      this(){
>>>          // do stuff here
>>>      }
>>> }
>>>
>>> void main(){
>>>      Foo foo1; // error, no init value
>>>      auto foo2=Foo(); // ok
>>> }
>>
>> Because then the user might think, that the default constructor gets
>> called implicitly by the compiler.
>
> This would be pointed out by the compiler. (i.e. it is an error instead
> of an implicit call.)
>
>> Just like in C++. But as that is not
>> the case the syntax should be different to indicate that a struct might
>> still be instaniated just using T.init.
>>
>> Kind Regards
>> Benjamin Thaut
>
> What would be an use case for a bypassable default constructor?

I don't know any use case. But AFAIK the reason there is no default constructor for structs in D has to do something with exception safetey. So whatever cases those are, they might need a bypassable default constructor.
April 09, 2014
On 2014-04-09 19:10, Brian Schott wrote:

> Really? What does this program print using a current version of DMD?
>
> import std.stdio;
>
> struct SomeStruct
> {
>      this(int i = 10)
>      {
>          this.i = i;
>      }
>      int i;
> }
>
> void main(string[] args)
> {
>      auto s = SomeStruct();
>      writeln("s.i = ", s.i);
> }
>
> I don't think it would be ambiguous at all :-)

Yeah, because currently DMD doesn't have the proposed feature. If it's added I can imagine it's similar to writing this:

void foo ();
void foo (int i = 0);

-- 
/Jacob Carlborg
April 10, 2014
On Wednesday, 9 April 2014 at 18:41:57 UTC, Walter Bright wrote:
> On 4/9/2014 7:59 AM, Benjamin Thaut wrote:
>> What do you think? C&C welcome.
>
> Or you could use a factory function:
>
>   struct Foo {
>     static Foo factory() { ... }
>     ...
>   }
>
>   auto foo = Foo.factory();

Yeah. For sure.

Or a named function: auto foo = foo();
Or a make template:  auto foo = make!Foo();
Or a dummy argument: auto foo = Foo(Foo.dummy);
Or ditto with a global dummy:  auto foo = Foo(dummyArg);
Or use a static opCall:        auto foo = Foo();
Or use an initialize function: Foo foo; foo.initialize();

I mean: Why complain when there are at least 10 *different* solutions at our disposal? Who doesn't love re-inventing the same functionality over and over and over again? But more importantly, who doesn't just *love* reading the documentation that explains *which* approach the damn type chose for run-time initialization. Yummy!

Also, any kind of "Factory" solution has a postblit overhead if you try to emplace it. Or would require a temporary with some complex "uninitializedMove". No postblit, but still overhead.

--------

Being serious again, if the language isn't going to do something to address the issue, we *should* have a uniform library solution.

I think the "make" template could be a good approach. It could be a universal construction scheme, with "opt-in" no-arg construction:

static struct NoArg {}
enum noArgToken;

template make(T)
{
    //And some switches to handle non-struct types too.

    T make(Args...)(auto ref Args args)
    {
        static if (Args.length)
            return T(args);
        else
        {
            static if (is(typeof(T(noArgToken))));
                return T(noArgToken);
            else
                return T();
        }
    }
}

struct S1
{
    int* p;
    @disable this();
    this(NoArg) //Opt-in no-arg constructor
    {p = new int;}
}
struct S2
{
    int i;
}

void main()
{
    S1 s11; //FAils to compile (disabled this());
    auto s12 = S1.init; //Explicit request for static default initialization;
    auto s13 = make!S1(); //run-time construction request.

    auto s2 = make!S2(); //run-time construction request. Does nothing particular.
}

This has the advantage (IMO) of being explicit and universal. Also, it's an actual construction scheme, so `emplace(noArgToken)` would call an actual constructor.

Furthermore, it could also allow a universal construction scheme for items, regardless of struct/class/integral etc...