Thread overview
Arrays of variants, C++ vs D
Jun 17, 2021
JN
Jun 17, 2021
H. S. Teoh
Jun 17, 2021
Ali Çehreli
June 17, 2021

This C++ code compiles:

#include <variant>
#include <string>
#include <map>

int main()
{
    using Foo = std::variant<int, std::string>;
    std::map<int, Foo> foos =  {{0, "abc"}, {1, 5}};
}

This code doesn't:

```d
import std.variant;

void main()
{
    alias Foo = Algebraic!(int, string);
    Foo[int] foos = [
        0: "abc",
        1: 5
    ];
}

but this does:

import std.variant;

void main()
{
    alias Foo = Algebraic!(int, string);
    Foo[int] foos = [
        0: Foo("abc"),
        1: Foo(5)
    ];
}

Why does D need the explicit declarations whereas C++ can infer it?

June 17, 2021
On Thu, Jun 17, 2021 at 07:44:31PM +0000, JN via Digitalmars-d-learn wrote: [...]
>     Foo[int] foos = [
>         0: Foo("abc"),
>         1: Foo(5)
>     ];
> }
> ```
> 
> Why does D need the explicit declarations whereas C++ can infer it?

Because D does not support implicit construction. The array literal is parsed as-is, meaning string[int] is inferred rather than Foo[int]. So the initialization fails because of a type mismatch.

Implicit construction has been asked for many times, but Walter has been adamant about not allowing implicit construction in D.


T

-- 
Music critic: "That's an imitation fugue!"
June 17, 2021
On 6/17/21 4:15 PM, H. S. Teoh wrote:
> On Thu, Jun 17, 2021 at 07:44:31PM +0000, JN via Digitalmars-d-learn wrote:
> [...]
>>      Foo[int] foos = [
>>          0: Foo("abc"),
>>          1: Foo(5)
>>      ];
>> }
>> ```
>>
>> Why does D need the explicit declarations whereas C++ can infer it?
> 
> Because D does not support implicit construction. The array literal is
> parsed as-is, meaning string[int] is inferred rather than Foo[int]. So
> the initialization fails because of a type mismatch.

Implicit construction is supported:

struct Foo
{
   int x;
   this(int y) { x = y; }
}

Foo f = 5; // ok implicit construction

What is happening here though is that the construction is being done as an AA literal. This works for *some* types, but not all.

e.g.:

Foo[int] f = [5 : 5]; // error
double[int] f = [5 : 5]; // ok

It really should work IMO.

-Steve
June 17, 2021
On 6/17/21 1:46 PM, Steven Schveighoffer wrote:

> Implicit construction is supported:
>
> struct Foo
> {
>     int x;
>     this(int y) { x = y; }
> }
>
> Foo f = 5; // ok implicit construction

That's so unlike the rest of the language that I consider it to be a bug. :) Really, why? What if the expression is more complicated:

int i() {
  return 1;
}

  Foo f = i();

OK, that works as well. Wow!

But the following doesn't and is what I think Walter has been trying to prevent:

struct Foo
{
   int x;
   this(int y) { x = y; }
}

void foo(Foo) {
}

void main() {
  foo(42);    // COMPILATION ERROR
}

What's the difference? In both cases an int is being converted to a Foo. I think the "working" case is against the design of D.

Likely there is a subtlety that I am missing...

Ali

June 17, 2021
On 6/17/21 5:01 PM, Ali Çehreli wrote:

> 
> What's the difference? In both cases an int is being converted to a Foo. I think the "working" case is against the design of D.
> 
> Likely there is a subtlety that I am missing...

The difference might be that construction has only one set of overloads -- the constructor of the item being created. With your example, there's the set of overloads to create a Foo and the set of overloads to call foo.

Imagine this:

struct Foo
{
   int x;
   this(int y) { x = y; }
}

struct Bar
{
   int x;
   this(int y) { x = y; }
}

void foo(Foo f){}
void foo(Bar b){}

void main()
{
   foo(42); // which one?
}

But I don't know. I know that there are all kinds of subtle problems with C++ implicit conversions, and D is right to avoid all that. But this might be one case where the decision tree is easy.

-Steve