Jump to page: 1 2
Thread overview
Struct constructor, opCall mess.
Feb 24, 2014
Remo
Feb 24, 2014
Tobias Pankrath
Feb 24, 2014
Remo
Feb 24, 2014
Stanislav Blinov
Feb 24, 2014
Remo
Feb 24, 2014
Remo
Feb 25, 2014
Jesse Phillips
Feb 25, 2014
Tobias Pankrath
Feb 25, 2014
Maxim Fomin
Feb 24, 2014
monarch_dodra
Feb 24, 2014
Remo
Feb 25, 2014
Jesse Phillips
Feb 25, 2014
Maxim Fomin
Feb 25, 2014
Remo
February 24, 2014
Hi,

right now I am truing to figure out how the constructors behave in D2.

Question 1: why it is not possible to create custom ctor for struct?
I know this is not really necessary because you can initialize fields like this.
struct S{ int i = 1; }

But this is a big problem if one tries to port C++ code to D2 and default ctor call some important initialization code.

Question 2: is there a way to mimic compiler generated ctor (that work in CTFE)?

Question 3: why it is possible to call static opCall like this?
VectorC v5 = v4(1.0);

Right now opCall seems to be better as this(...) because it work in CTFE but because of unwanted calls this is not well at all.

Question 4: why this(...) does not work in CTFE mode?

Here is highly simplified test code.
http://melpon.org/wandbox/permlink/ofvNby99mKqOBQBf

I am asking this because I am learning D2 now by porting and warping/connecting some big C++ (C++11) project to D2.

February 24, 2014
On Monday, 24 February 2014 at 13:56:01 UTC, Remo wrote:
> Hi,
>
> right now I am truing to figure out how the constructors behave in D2.
>
> Question 1: why it is not possible to create custom ctor for struct?

The design of D relies on the fact that every type has a T.init property that is known to the compiler and used when in C++ the default ctor would get called. In constructors you can rely on (this == T.init), for example.

You need to pick one T.init or default constructors and D picked T.init.

February 24, 2014
On Monday, 24 February 2014 at 14:14:43 UTC, Tobias Pankrath wrote:
> On Monday, 24 February 2014 at 13:56:01 UTC, Remo wrote:
>> Hi,
>>
>> right now I am truing to figure out how the constructors behave in D2.
>>
>> Question 1: why it is not possible to create custom ctor for struct?
>
> The design of D relies on the fact that every type has a T.init property that is known to the compiler and used when in C++ the default ctor would get called. In constructors you can rely on (this == T.init), for example.
>
> You need to pick one T.init or default constructors and D picked T.init.


Well fortunately it seems to be possible to override init property.
But it still does not called at struct construction.
http://melpon.org/wandbox/permlink/9EvcdzKUKoufqbJa

So what is proper/best way to mimic default constructor for struct ?

February 24, 2014
On Monday, 24 February 2014 at 17:15:10 UTC, Remo wrote:

> Well fortunately it seems to be possible to override init property.

Fortunately? I think not. It's an abomination that, IMO, has to be annihilated. Recently Andrei suggested adding more explicit semantics to .init that may give some leeway in this matter, although this was concerning classes and non-null default values, so it may not concern structs at all. Regardless, my advice - don't try to override .init, i.e. don't invite trouble into your code :)

> But it still does not called at struct construction.
> http://melpon.org/wandbox/permlink/9EvcdzKUKoufqbJa

Yup.

> So what is proper/best way to mimic default constructor for struct ?

Don't do it. Default construction for struct *is* initialization of its fields.
If you want to do something other that initialize fields - create a function and call it explicitly. D is not C++, don't expect it to behave identically. To make it easier when porting code, you can always temporarily @disable this() so the compiler will stop whenever you'd use your "special" default construction in C++.

As you've mentioned, the code from your example doesn't need any special default constructors at all, this will work just fine:

struct Vector(T) {
    T x = 0, y = 0, z = 0;

    this(T v) { x = y = z = v; }
    this(T x, T y, T z) { this.x = x; this.y = y; this.z = z; }
}


unittest {
    Vector!double v;
    auto v2 = Vector!double(1);
    auto v3 = Vector!double(1,2,3);

    assert(v.x == v.y && v.y == v.z && v.z == 0);
    assert(v2.x == v2.x && v2.y == v2.z && v2.z == 1);
    assert(v3.x == 1 && v3.y == 2 && v3.z == 3);
}


Also please take a look at those:

https://d.puremagic.com/issues/show_bug.cgi?id=3438
https://d.puremagic.com/issues/show_bug.cgi?id=6080
https://d.puremagic.com/issues/show_bug.cgi?id=7066
https://d.puremagic.com/issues/show_bug.cgi?id=7597
https://d.puremagic.com/issues/show_bug.cgi?id=8816
https://d.puremagic.com/issues/show_bug.cgi?id=8817
https://d.puremagic.com/issues/show_bug.cgi?id=10413
https://d.puremagic.com/issues/show_bug.cgi?id=11307

There may be some others I've missed; the sheer amount and unresolved state is terrifying.
February 24, 2014
> Fortunately?
Yes I think it is. Of course it could be made a more safe in some way.

I think the big advantage of D is that it has 'bridge' to C and C++.
This way it appears to be easy to port some C++ code to D.
And it appears to be easy to interconnect C++ and D code. (via Dll for example)

> @disable this()
Yes this is possible.
But then why it is not possible to use something like this ?
@default this();

For Vector example this works pretty well this way.
But my main problem is more complicated.

extern(C)  int init(ref CWrapper p);
extern(C) void free(ref CWrapper p);

struct CWrapper
{
  //some data that must be the same at C side.
  Data m_data;

  this() {
     init(&this);
  }
  ~this() {
     free(&this);
  }
}

How to do something like this in D ?
Using class appears for me to be wrong direction.


On Monday, 24 February 2014 at 18:13:02 UTC, Stanislav Blinov wrote:
> On Monday, 24 February 2014 at 17:15:10 UTC, Remo wrote:
>
>> Well fortunately it seems to be possible to override init property.
>
> Fortunately? I think not. It's an abomination that, IMO, has to be annihilated. Recently Andrei suggested adding more explicit semantics to .init that may give some leeway in this matter, although this was concerning classes and non-null default values, so it may not concern structs at all. Regardless, my advice - don't try to override .init, i.e. don't invite trouble into your code :)
>
>> But it still does not called at struct construction.
>> http://melpon.org/wandbox/permlink/9EvcdzKUKoufqbJa
>
> Yup.
>
>> So what is proper/best way to mimic default constructor for struct ?
>
> Don't do it. Default construction for struct *is* initialization of its fields.
> If you want to do something other that initialize fields - create a function and call it explicitly. D is not C++, don't expect it to behave identically. To make it easier when porting code, you can always temporarily @disable this() so the compiler will stop whenever you'd use your "special" default construction in C++.
>
> As you've mentioned, the code from your example doesn't need any special default constructors at all, this will work just fine:
>
> struct Vector(T) {
>     T x = 0, y = 0, z = 0;
>
>     this(T v) { x = y = z = v; }
>     this(T x, T y, T z) { this.x = x; this.y = y; this.z = z; }
> }
>
>
> unittest {
>     Vector!double v;
>     auto v2 = Vector!double(1);
>     auto v3 = Vector!double(1,2,3);
>
>     assert(v.x == v.y && v.y == v.z && v.z == 0);
>     assert(v2.x == v2.x && v2.y == v2.z && v2.z == 1);
>     assert(v3.x == 1 && v3.y == 2 && v3.z == 3);
> }
>
>
> Also please take a look at those:
>
> https://d.puremagic.com/issues/show_bug.cgi?id=3438
> https://d.puremagic.com/issues/show_bug.cgi?id=6080
> https://d.puremagic.com/issues/show_bug.cgi?id=7066
> https://d.puremagic.com/issues/show_bug.cgi?id=7597
> https://d.puremagic.com/issues/show_bug.cgi?id=8816
> https://d.puremagic.com/issues/show_bug.cgi?id=8817
> https://d.puremagic.com/issues/show_bug.cgi?id=10413
> https://d.puremagic.com/issues/show_bug.cgi?id=11307
>
> There may be some others I've missed; the sheer amount and unresolved state is terrifying.

February 24, 2014
>> Also please take a look at those:
>>
>> https://d.puremagic.com/issues/show_bug.cgi?id=7066
>>
>> There may be some others I've missed; the sheer amount and unresolved state is terrifying.

IMHO  Issue 7066 is not a bug but a feature.
Of course it could be handled i a bit more safe way.

This looks like D2 is still in Beta stadium and not really ready for production use !?
February 24, 2014
On Monday, 24 February 2014 at 17:15:10 UTC, Remo wrote:
> So what is proper/best way to mimic default constructor for struct ?

Honestly, you can't, and you shouldn't try either. There "used" to be the static opCall that allowed:
----
auto a = T();
----

But:
a) This is being phased out: If T has a constructor, it will seize to compile.
b) It's not "default": "T a;" will still compile, but not construct.

The feedback I've been getting is that the "correct" way to guarantee construction is to do it via a named factory pattern. You disable the this(), so as to "force" initialization, and make the constructors private. You'll get something along the lines of:

T a; //Nope.
T a = T(); //Nope
T a = T.build(); //OK!
T a = T(1, 2); //Nope!
T a = T.build(1, 2); //OK!
T a = T.init; //OK! Special explicit requrest for non-initialisation.

With D's move semantics and (N)RVO, there should be 0 overhead to do this.
February 24, 2014
On Monday, 24 February 2014 at 21:06:03 UTC, monarch_dodra wrote:
> On Monday, 24 February 2014 at 17:15:10 UTC, Remo wrote:
>> So what is proper/best way to mimic default constructor for struct ?
>
> Honestly, you can't, and you shouldn't try either. There "used" to be the static opCall that allowed:
> ----
> auto a = T();
> ----
>
> But:
> a) This is being phased out: If T has a constructor, it will seize to compile.
> b) It's not "default": "T a;" will still compile, but not construct.
>
> The feedback I've been getting is that the "correct" way to guarantee construction is to do it via a named factory pattern. You disable the this(), so as to "force" initialization, and make the constructors private. You'll get something along the lines of:
>
> T a; //Nope.
> T a = T(); //Nope
> T a = T.build(); //OK!
> T a = T(1, 2); //Nope!
> T a = T.build(1, 2); //OK!
> T a = T.init; //OK! Special explicit requrest for non-initialisation.
>
> With D's move semantics and (N)RVO, there should be 0 overhead to do this.


Thanks, I will try to make this this way and look how well it will work.  But it could complicate connection from C++ to D and back.

Where I can find more info about 'D's move semantics'?
Apparently it is not the same as rvalue reference and move semantics in C++11 ?

February 25, 2014
On Monday, 24 February 2014 at 23:34:51 UTC, Remo wrote:
> Where I can find more info about 'D's move semantics'?
> Apparently it is not the same as rvalue reference and move semantics in C++11 ?

Here is the place I know of:
http://dconf.org/2013/talks/cehreli.html
February 25, 2014
On Monday, 24 February 2014 at 20:35:54 UTC, Remo wrote:
> This looks like D2 is still in Beta stadium and not really ready for production use !?

I believe it is ready for production, but you can't expect it to be ready in all cases. Mostly its lack of readiness isn't because of the language though. For example it isn't ready for production Android/iOS development, because it hasn't been done yet. It isn't ready for Epic to write Unreal 5 Engine in it. However if Valve believed in D I'd say it was ready for them to take on the challenge and write Source 2 in D.
« First   ‹ Prev
1 2