Jump to page: 1 2
Thread overview
Allow struct constructors with all parameters optional
Aug 27
Ogi
Aug 27
IchorDev
Aug 28
Ogi
Aug 29
Ogi
Aug 29
ryuukk_
Aug 29
Ogi
Aug 29
IchorDev
Aug 30
ryuukk_
August 27

It is valid to overload a function with all parameters optional with a function that takes no parameters. The parameterless overload is called if no arguments are passed:

import std.stdio;
void fun(int x = 0, int y = 0) {
    writeln(i"fun($(x), $(y))");
}
void fun() {
    writeln("fun()");
}

fun(y:42); // fun(0, 42)
fun(); // fun()

Same rules apply to class constructors:

import std.stdio;
class C {
    this(int x = 0, int y = 0) {
         writeln(i"C($(x), $(y))");
    }
    this() {
        writeln("C()");
    }
}

auto c1 = new C(y:42); // C(0, 42)
auto c2 = new C(); // C()

D disallows parameterless constructors for structs, and there are good reasons for this. But constructors with all parameters optional are prohibited too. This restriction doesn’t make much sense, especially now when D supports named arguments. This should be valid:

struct S {
    this(int x = 0, int y = 0) {
         writeln(i"S($(x), $(y))");
    }
}
auto s1 = S(y:42); // S(0, 42)
auto s2 = S(); // default initialization
August 27

On Tuesday, 27 August 2024 at 08:48:19 UTC, Ogi wrote:

>

D disallows parameterless constructors for structs, and there are good reasons for this. But constructors with all parameters optional are prohibited too. This restriction doesn’t make much sense

I can’t remember exactly what the reasons for that were, but I thought those reasons applied equally to any constructors that could be called with 0 parameters? Could you also elaborate about how named parameters affect this situation?

August 28

On Tuesday, 27 August 2024 at 22:53:45 UTC, IchorDev wrote:

>

I can’t remember exactly what the reasons for that were, but I thought those reasons applied equally to any constructors that could be called with 0 parameters?

The reasons are that, AFAIK, language designers decided that S s and auto s = S() producing different results would be too confusing.

Speaking of constructors that could be called with zero parameters. All kinds of variadic constructors are perfectly fine, despite the fact that regular variadic functions can be called with zero parameters:

struct A {
    this(Args...)(Args) { writeln("ctor"); }
}
 struct B {
    this(...) { writeln("ctor"); }
}
struct C {
    this(int[]...) { writeln("ctor"); }
}
struct D {
    this(Object...) { writeln("ctor"); }
}

All these structs are default-initialized with zero arguments and call their constructor with non-zero number of arguments. Exactly how I expect a constructor with all optional parameters to behave.

>

Could you also elaborate about how named parameters affect this situation?

Consider this function:

void fun(int a = 0, int b = 0, int c = 0)

Before introduction of named arguments it wasn’t possible to call fun by only passing c. You had to pass all preceding arguments as well: fun(0, 0, 42). So even if you could define a struct constructor with all optional parameters, this wouldn’t make any difference. You always had to pass at least the first argument anyway.

Nowadays, thanks to named arguments, you actually can call fun by only passing c: fun(c:42). With this change struct constructors with all optional parameters became useful, but they are still prohibited.

August 28

On Tuesday, 27 August 2024 at 08:48:19 UTC, Ogi wrote:

>

D disallows parameterless constructors for structs, and there are good reasons for this. But constructors with all parameters optional are prohibited too. This restriction doesn’t make much sense, especially now when D supports named arguments. This should be valid:

struct S {
    this(int x = 0, int y = 0) {
         writeln(i"S($(x), $(y))");
    }
}
auto s1 = S(y:42); // S(0, 42)
auto s2 = S(); // default initialization

I'll point out that you can already write a library that makes your code run. I'd like a way to do it directly without jumping through these hoops.

foo.d:

import std;
struct S {
    this(int x, int y = 0) {
         writeln(i"S($(x), $(y))");
    }
}

bar.d:

import foo;
alias _S = foo.S;
_S S() {
  return _S(0, 0);
}

baz.d:

public import foo, bar;
alias S = bar.S;

call.d:

import baz;
void main() {
  auto s2 = S();
}
August 29

On Wednesday, 28 August 2024 at 15:26:47 UTC, Lance Bachmeier wrote:

>

This proposal is not about allowing default struct constructors. Under this proposal, S() would still be initialized with S.init.

August 29

On Thursday, 29 August 2024 at 09:37:53 UTC, Ogi wrote:

>

On Wednesday, 28 August 2024 at 15:26:47 UTC, Lance Bachmeier wrote:

>

This proposal is not about allowing default struct constructors. Under this proposal, S() would still be initialized with S.init.

I'm not sure I understand. This is what you wrote:

>

D disallows parameterless constructors for structs, and there are good reasons for this. But constructors with all parameters optional are prohibited too. This restriction doesn’t make much sense, especially now when D supports named arguments. This should be valid:

My example shows that it is valid, but only if you jump through unnecessary hoops.

August 29

On Thursday, 29 August 2024 at 13:20:04 UTC, Lance Bachmeier wrote:

>

My example shows that it is valid, but only if you jump through unnecessary hoops.

I don't mean valid, I mean you can already write code that is equivalent to the caller.

August 29

On Wednesday, 28 August 2024 at 15:26:47 UTC, Lance Bachmeier wrote:

>

On Tuesday, 27 August 2024 at 08:48:19 UTC, Ogi wrote:

>

D disallows parameterless constructors for structs, and there are good reasons for this. But constructors with all parameters optional are prohibited too. This restriction doesn’t make much sense, especially now when D supports named arguments. This should be valid:

struct S {
    this(int x = 0, int y = 0) {
         writeln(i"S($(x), $(y))");
    }
}
auto s1 = S(y:42); // S(0, 42)
auto s2 = S(); // default initialization

I'll point out that you can already write a library that makes your code run. I'd like a way to do it directly without jumping through these hoops.

foo.d:

import std;
struct S {
    this(int x, int y = 0) {
         writeln(i"S($(x), $(y))");
    }
}

bar.d:

import foo;
alias _S = foo.S;
_S S() {
  return _S(0, 0);
}

baz.d:

public import foo, bar;
alias S = bar.S;

call.d:

import baz;
void main() {
  auto s2 = S();
}

Are you seriously telling people to write a library to be able to do what C already provides for decades?

This is why nobody takes D seriously, all that code just to initialize a struct

Unbelievable, seriously

August 29

On Thursday, 29 August 2024 at 13:57:05 UTC, ryuukk_ wrote:

>

Are you seriously telling people to write a library to be able to do what C already provides for decades?

Real yakuza use static opCall.

(I’m kidding. Don’t use opCall, kids)

August 29

On Thursday, 29 August 2024 at 13:57:05 UTC, ryuukk_ wrote:

>

Are you seriously telling people to write a library to be able to do what C already provides for decades?

This is why nobody takes D seriously, all that code just to initialize a struct

Unbelievable, seriously

I'm saying the opposite. An intermediate-level D programmer can use modules and aliases in a straightforward way to accomplish the same thing, even on a third-party library that someone else wrote and that you don't want to change. The restriction isn't actually a restriction but an annoyance. It should be possible to do this within the struct itself.

« First   ‹ Prev
1 2