Search
Page
Named constructors
Jan 09
Dru
Jan 09
Alex
Jan 09
bauss
Jan 09
JN
Jan 09
JN
Jan 10
evilrat
Jan 10
Dru
Jan 10
evilrat
Jan 10
evilrat
Jan 10
JN
Jan 10
JN
4 days ago
aliak
4 days ago
Atila Neves
4 days ago
12345swordy
4 days ago
Olivier FAURE
3 days ago
Atila Neves
4 days ago
Jacob Carlborg
4 days ago
aliak
Jan 11
JN
Jan 11
JN
5 days ago
Jacob Carlborg
4 days ago
Atila Neves
4 days ago
Jacob Carlborg
4 days ago
Atila Neves
Jan 10
jmh530
```Another way to distinguish between constructors is needed.
Because it is possible to have two different constructors that take the same arguments.
Adding dummy arguments that are unused hurts code clarity.

```
```On Wednesday, 9 January 2019 at 07:47:02 UTC, Dru wrote:
> Another way to distinguish between constructors is needed.
> Because it is possible to have two different constructors that take the same arguments.
> Adding dummy arguments that are unused hurts code clarity.

Couldn't this problem be solved by a factory method? I mean, either this, or something like this: http://www.cs.technion.ac.il/users/yechiel/c++-faq/named-ctor-idiom.html

´´´
import std.stdio;
import std.math;

void main()
{
auto pr = Point.rectangular(2,3);

assert(approxEqual(pr.x_, 2));
assert(approxEqual(pr.y_, 3));

auto pp = Point.polar(1,PI);

assert(approxEqual(pp.x_, -1));
assert(approxEqual(pp.y_, 0));
}

struct Point {
public:
static Point rectangular(real x, real y)      // Rectangular coord's
{
return Point(x,y);
}
static Point polar(real radius, real angle)   // Polar coordinates
{
return Point(radius * cos(angle), radius * sin(angle));
}

private:
this(real x, real y)
{
x_ = x;
y_ = y;
}
real x_, y_;
}
´´´
```
```On Wednesday, 9 January 2019 at 08:53:40 UTC, Alex wrote:
> On Wednesday, 9 January 2019 at 07:47:02 UTC, Dru wrote:
>> Another way to distinguish between constructors is needed.
>> Because it is possible to have two different constructors that take the same arguments.
>> Adding dummy arguments that are unused hurts code clarity.
>
> Couldn't this problem be solved by a factory method? I mean, either this, or something like this: http://www.cs.technion.ac.il/users/yechiel/c++-faq/named-ctor-idiom.html
>
> ´´´
> import std.stdio;
> import std.math;
>
> void main()
> {
>     auto pr = Point.rectangular(2,3);
>
>     assert(approxEqual(pr.x_, 2));
>     assert(approxEqual(pr.y_, 3));
>
>     auto pp = Point.polar(1,PI);
>
>     assert(approxEqual(pp.x_, -1));
>     assert(approxEqual(pp.y_, 0));
> }
>
>
> struct Point {
> public:
>   static Point rectangular(real x, real y)      // Rectangular coord's
>   {
>       return Point(x,y);
>   }
>   static Point polar(real radius, real angle)   // Polar coordinates
>   {
>       return Point(radius * cos(angle), radius * sin(angle));
>   }
>
> private:
>   this(real x, real y)
>   {
>       x_ = x;
>       y_ = y;
>   }
>   real x_, y_;
> }
> ´´´

I like this approach to it and you're entirely correct.

It would be nice with support for this in the language without having to create factory methods.

Basically something like the following could be lowered to your code.

´´´
import std.stdio;
import std.math;

void main()
{
auto pr = Point.rectangular(2,3);

assert(approxEqual(pr.x_, 2));
assert(approxEqual(pr.y_, 3));

auto pp = Point.polar(1,PI);

assert(approxEqual(pp.x_, -1));
assert(approxEqual(pp.y_, 0));
}

struct Point {
public:
this(real x, real y)
{
this.x = x;
this.y = y;
}

this rectangular(real x, real y)
{
this(x,y);
}

this polar(real radius, real angle)
{
}

real x, y;
}
´´´
```
```On Wed, 09 Jan 2019 08:53:40 +0000, Alex wrote:
> On Wednesday, 9 January 2019 at 07:47:02 UTC, Dru wrote:
>> Another way to distinguish between constructors is needed. Because it
>> is possible to have two different constructors that take the same
>> arguments.
>> Adding dummy arguments that are unused hurts code clarity.
>
> Couldn't this problem be solved by a factory method? I mean,
> either this, or something like this:
> http://www.cs.technion.ac.il/users/yechiel/c++-faq/named-ctor-idiom.html

A constructor can alter const fields, but a factory method can't, so they're not exactly equivalent. I was hoping you could add a template parameter to a constructor to give a "name" to it, like:

class Foo
{
const int i;
this(string name: "shift")(int i) { this.i = 1 << i; }
this(string name: "direct")(int i) { this.i = i; }
}
new Foo!"shift"(3);

But that doesn't work; there is no way to explicitly provide template parameters to a constructor.
```
```On Wednesday, 9 January 2019 at 07:47:02 UTC, Dru wrote:
> Another way to distinguish between constructors is needed.
> Because it is possible to have two different constructors that take the same arguments.
> Adding dummy arguments that are unused hurts code clarity.

Adding dummy arguments is unecessary. Just use the type system:

struct Person {
this(FirstName firstName, LastName lastName) { /* ... */ }
}

struct FirstName { string value; }
struct LastName  { string value; }

C++ even has two libraries to do this, but D doesn't need that given that structs in D are much more useful (no need to write a constructor).
```
```On Wed, Jan 09, 2019 at 05:30:32PM +0000, Atila Neves via Digitalmars-d wrote:
> On Wednesday, 9 January 2019 at 07:47:02 UTC, Dru wrote:
> > Another way to distinguish between constructors is needed.  Because it is possible to have two different constructors that take the same arguments.  Adding dummy arguments that are unused hurts code clarity.
>
> Adding dummy arguments is unecessary. Just use the type system:
>
> struct Person {
>     this(FirstName firstName, LastName lastName) { /* ... */ }
> }
>
> struct FirstName { string value; }
> struct LastName  { string value; }

+1. That's what the type system is for.  Dummy arguments are NEVER a good idea unless there's a need for the API to be uniform.

It also makes the calling code self-documenting without needing language support for named arguments:

auto myPerson = Person(FirstName("John"), LastName("Doe"));

rather than the opaque (and thus error-prone):

// Bug 1234: hmm, is it first name first, or last name first?
//auto myPerson = Person("Doe", "John");
auto myPerson = Person("John", "Doe");

T

--
Bare foot: (n.) A device for locating thumb tacks on the floor.
```
```On Wed, Jan 9, 2019 at 5:50 PM Neia Neutuladh via Digitalmars-d < digitalmars-d@puremagic.com> wrote:

> On Wed, 09 Jan 2019 08:53:40 +0000, Alex wrote:
> > On Wednesday, 9 January 2019 at 07:47:02 UTC, Dru wrote:
> >> Another way to distinguish between constructors is needed. Because it
> >> is possible to have two different constructors that take the same
> >> arguments.
> >> Adding dummy arguments that are unused hurts code clarity.
> >
> > Couldn't this problem be solved by a factory method? I mean,
> > either this, or something like this:
> > http://www.cs.technion.ac.il/users/yechiel/c++-faq/named-ctor-idiom.html
>
> A constructor can alter const fields, but a factory method can't, so they're not exactly equivalent. I was hoping you could add a template parameter to a constructor to give a "name" to it, like:
>
> class Foo
> {
>   const int i;
>   this(string name: "shift")(int i) { this.i = 1 << i; }
>   this(string name: "direct")(int i) { this.i = i; }
> }
> new Foo!"shift"(3);
>
> But that doesn't work; there is no way to explicitly provide template parameters to a constructor.
>

import std.stdio;
import std.math;

void main()
{
auto sa = S.constructorA(3,4);
auto sb = S.constructorB(3,4);
writeln(sa);
writeln(sb);
}

struct S {
public:
this(string name: "constructorA")(real x, real y)
{
this.x = x;
this.y = y;
}

this(string name: "constructorB")(real x, real z)
{
this.x = x;
this.z = z;
}

static constructorA(Args...)(Args args)
{
S s;
s.__ctor!"constructorA"(args);
return s;
}

static constructorB(Args...)(Args args)
{
S s;
s.__ctor!"constructorB"(args);
return s;
}
const real x, y, z;
}

```
```On Wednesday, 9 January 2019 at 18:19:35 UTC, Daniel Kozak wrote:
> On Wed, Jan 9, 2019 at 5:50 PM Neia Neutuladh via Digitalmars-d < digitalmars-d@puremagic.com> wrote:
>
>>[...]
>
> import std.stdio;
> import std.math;
>
> void main()
> {
>     auto sa = S.constructorA(3,4);
>     auto sb = S.constructorB(3,4);
>     writeln(sa);
>     writeln(sb);
> }
>
>
> struct S {
> public:
>    this(string name: "constructorA")(real x, real y)
>    {
>        this.x = x;
>        this.y = y;
>    }
>
>    this(string name: "constructorB")(real x, real z)
>    {
>        this.x = x;
>        this.z = z;
>    }
>
>    static constructorA(Args...)(Args args)
>    {
>        S s;
>        s.__ctor!"constructorA"(args);
>        return s;
>    }
>
>    static constructorB(Args...)(Args args)
>    {
>        S s;
>        s.__ctor!"constructorB"(args);
>        return s;
>    }
>    const real x, y, z;
> }
That solution has a compile time cost.
```
```On Wednesday, 9 January 2019 at 18:24:28 UTC, 12345swordy wrote:
> That solution has a compile time cost.

I do not see any compile time cost, what do you mean?

```
```On Wednesday, 9 January 2019 at 10:02:12 UTC, bauss wrote:
>
> I like this approach to it and you're entirely correct.
>
> It would be nice with support for this in the language without having to create factory methods.
>
> Basically something like the following could be lowered to your code.

I was going to say that this post will be mostly ignored and people will present some template magic to partially implement such feature (just add few imports and some boilerplate code), but I guess I got beaten to it :)
```
« First   ‹ Prev