Thread overview
Why isn't intended class constructor called?
Jan 28, 2019
Zak
Jan 28, 2019
Alex
Jan 28, 2019
Zak
Jan 28, 2019
Zak
Jan 28, 2019
Alex
January 28, 2019
I have defined a class that's meant to represent a data series, which has an index and a set of values.  Sometimes the user wants to specify a particular index of custom type, other times they don't care and we want to default to an array of contiguous "int" starting from 0.

I have attempted to create a class where the index type is a parameter, but defaults to int.  I also tried to create two constructors:  one for if the index values are not specified (in which the constructor makes the array of ints); and one where the user passes in a literal of values that match the specified type.

However, it seems that only the first constructor is getting called, even though I am passing in two parameters instead of one.  Why isn't the call matching the second constructor and behaving as intended?


 import std.stdio;

 class MyClass(T, U = int) {

    T[] values;
    U[] index;

    this(T[] values) {
        this.values = values;
        // Default index of contiguous ints
        for (int i; i < values.length; i++) {
            index ~= i;
        }
    }

    this(T[] values, U[] index) {
        this.values = values;
        this.index = index;
    }
}

void main() {
    auto myc1 = new MyClass!(int)([1,2,-3]);

    auto myc2 = new MyClass!(int, string)([1,2,-3], ["a", "b", "c"]); // Error: cannot append type int to type string[]

}
January 28, 2019
On Monday, 28 January 2019 at 18:34:44 UTC, Zak wrote:
> I have defined a class that's meant to represent a data series, which has an index and a set of values.  Sometimes the user wants to specify a particular index of custom type, other times they don't care and we want to default to an array of contiguous "int" starting from 0.
>
> I have attempted to create a class where the index type is a parameter, but defaults to int.  I also tried to create two constructors:  one for if the index values are not specified (in which the constructor makes the array of ints); and one where the user passes in a literal of values that match the specified type.
>
> However, it seems that only the first constructor is getting called, even though I am passing in two parameters instead of one.  Why isn't the call matching the second constructor and behaving as intended?
>
>
>  import std.stdio;
>
>  class MyClass(T, U = int) {
>
>     T[] values;
>     U[] index;
>
>     this(T[] values) {
>         this.values = values;
>         // Default index of contiguous ints
>         for (int i; i < values.length; i++) {
>             index ~= i;
>         }
>     }
>
>     this(T[] values, U[] index) {
>         this.values = values;
>         this.index = index;
>     }
> }
>
> void main() {
>     auto myc1 = new MyClass!(int)([1,2,-3]);
>
>     auto myc2 = new MyClass!(int, string)([1,2,-3], ["a", "b", "c"]); // Error: cannot append type int to type string[]
>
> }

As the error states:
you are trying to append an int to a string array in the single parameter constructor.

This would work:
´´´
import std.stdio;

 class MyClass(T, U = int) {

    T[] values;
    U[] index;

    this(T[] values) {
        this.values = values;
        // Default index of contiguous ints
        static if(is(U == int))
        {
            for (int i; i < values.length; i++) {
                index ~= i;
            }
        }
    }

    this(T[] values, U[] index) {
        this.values = values;
        this.index = index;
    }
}

void main() {
    auto myc1 = new MyClass!(int)([1,2,-3]);

    auto myc2 = new MyClass!(int, string)([1,2,-3], ["a", "b", "c"]); // Error: cannot append type int to type string[]
}
´´´

If design matters, I would even to expand the static if above the constructor. So, the single parameter constructor would exist iff is(U == int)

´´´
static if(is(U == int))
    {
        this(T[] values) {
        this.values = values;
        // Default index of contiguous ints

            for (int i; i < values.length; i++) {
                index ~= i;
            }
        }
    }
´´´
January 28, 2019
On Monday, 28 January 2019 at 18:50:18 UTC, Alex wrote:
> On Monday, 28 January 2019 at 18:34:44 UTC, Zak wrote:
>> [...]
>
> As the error states:
> you are trying to append an int to a string array in the single parameter constructor.
>
> [...]

Thanks for the response, Alex!  But it's not clear to me why the first constructor is called at all.  Since I called with two parameters, shouldn't it invoke the second constructor?
January 28, 2019
On Monday, 28 January 2019 at 19:15:04 UTC, Zak wrote:
> On Monday, 28 January 2019 at 18:50:18 UTC, Alex wrote:
>> On Monday, 28 January 2019 at 18:34:44 UTC, Zak wrote:
>>> [...]
>>
>> As the error states:
>> you are trying to append an int to a string array in the single parameter constructor.
>>
>> [...]
>
> Thanks for the response, Alex!  But it's not clear to me why the first constructor is called at all.  Since I called with two parameters, shouldn't it invoke the second constructor?

I think I just realized the answer:  this section of code is not called, it just fails compilation since it's not known that runtime doesn't do something like:

auto myc = new MyClass!(int, string)([1,2,-3]);

which "would" invoke this code block with type string.
January 28, 2019
On Monday, 28 January 2019 at 19:24:21 UTC, Zak wrote:
> On Monday, 28 January 2019 at 19:15:04 UTC, Zak wrote:
>> On Monday, 28 January 2019 at 18:50:18 UTC, Alex wrote:
>>> On Monday, 28 January 2019 at 18:34:44 UTC, Zak wrote:
>>>> [...]
>>>
>>> As the error states:
>>> you are trying to append an int to a string array in the single parameter constructor.
>>>
>>> [...]
>>
>> Thanks for the response, Alex!  But it's not clear to me why the first constructor is called at all.  Since I called with two parameters, shouldn't it invoke the second constructor?
>
> I think I just realized the answer:  this section of code is not called, it just fails compilation since it's not known that runtime doesn't do something like:
>
> auto myc = new MyClass!(int, string)([1,2,-3]);
>
> which "would" invoke this code block with type string.

Yes. :)