Jump to page: 1 2
Thread overview
[Issue 11206] New: static array can be implicitly built from items, when nested in aggregate
Oct 09, 2013
Maxim Fomin
Oct 09, 2013
Maxim Fomin
Oct 09, 2013
Maxim Fomin
Oct 10, 2013
Kenji Hara
Oct 10, 2013
Maxim Fomin
Oct 10, 2013
Maxim Fomin
Oct 10, 2013
Kenji Hara
Oct 10, 2013
Maxim Fomin
Oct 10, 2013
Maxim Fomin
Oct 10, 2013
Kenji Hara
Oct 10, 2013
Kenji Hara
Nov 03, 2013
Kenji Hara
October 09, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=11206

           Summary: static array can be implicitly built from items, when
                    nested in aggregate
           Product: D
           Version: D2
          Platform: All
        OS/Version: All
            Status: NEW
          Keywords: accepts-invalid
          Severity: normal
          Priority: P2
         Component: DMD
        AssignedTo: nobody@puremagic.com
        ReportedBy: monarchdodra@gmail.com


--- Comment #0 from monarchdodra@gmail.com 2013-10-09 07:22:40 PDT ---
Just to be clear, I'm not talking about "initial construction", where, eg, this is correct:

//----
alias ARR = int[1];
struct S{int i;this(int){}}

struct AGG(T)
{
    T t;
}

void main()
{
    S s1 = S(1); //Explicit, OK
    S s2 = 1; //Implicit, OK
    ARR arr1 = [1]; //Explicit, OK
    ARR arr2 = 1; //Implicit, OK
}
//----

This is OK: The table makes an implicit construction, thanks to an explicit type declaration.

However, if the table is nested inside an aggregate, then this should not happen: Aggregate construction requires an exact type match (possibly via alias this), *However*, individual elements *may not* be implicitly constructed from pass in arguments:

//----
void main()
{
    AGG!S ts2 = AGG!S(S(2)); //Explicit. Good.
    AGG!S ts1 = AGG!S(1); //NO! ILLEGAL REQUEST FOR IMPLICIT CONSTRUCTION!

    AGG!ARR tarr1 = AGG!ARR([1]); //Explicit is good
    AGG!ARR tarr1 = AGG!ARR(1); //This works...? [HERE]
}
//----

[HERE]: This is a violation of the type system. With aggregate initialization, each argument is supposed to match the type of the aggregated element, or be *implicitly*castable* to said element. In the case of "element => static array element", we have neither.

static arrays are the *only* type that allow this. I think making an exception for static arrays is surprising and wrong. It should be rejected.

Related: http://d.puremagic.com/issues/show_bug.cgi?id=10973

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
October 09, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=11206


Maxim Fomin <maxim@maxim-fomin.ru> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
                 CC|                            |maxim@maxim-fomin.ru
         Resolution|                            |INVALID


--- Comment #1 from Maxim Fomin <maxim@maxim-fomin.ru> 2013-10-09 08:45:45 PDT ---
So, what?

Basically you are complainig about:

import std.stdio;

struct AGG
{
    int[1] t;
    double d;
}

void main()
{
    AGG tarr2 = AGG(1);
    writeln(tarr2);
}

which prints AGG([1], nan).

AGG(1) is a struct literal which is valid in D. Integer literal is a valid
initializer for static array. Statement "AGG!S ts1 = AGG!S(1);" is rejected
because (unfortunately) 1 is not convertible to struct.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
October 09, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=11206


monarchdodra@gmail.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|RESOLVED                    |REOPENED
         Resolution|INVALID                     |


--- Comment #2 from monarchdodra@gmail.com 2013-10-09 09:02:30 PDT ---
(In reply to comment #1)
> So, what?
> 
> Basically you are complainig about:
> 
> import std.stdio;
> 
> struct AGG
> {
>     int[1] t;
>     double d;
> }
> 
> void main()
> {
>     AGG tarr2 = AGG(1);
>     writeln(tarr2);
> }
> 
> which prints AGG([1], nan).

...Unsure what you are trying to show? the "AGG(1)".

> AGG(1) is a struct literal which is valid in D.

I'm arguing that AGG should not be constructible taking a 1.

> Integer literal is a valid
> initializer for static array. Statement "AGG!S ts1 = AGG!S(1);" is rejected
> because (unfortunately) 1 is not convertible to struct.

Yes, integer is a valid initializer for a static array, and it is also a valid initializer for a struct that holds an int.

However, 1 is not convertible to a struct, not is it convertible to a static
array. AGG(1) should not compile, because 1 is not convertible to
typeof(AGG.tupleof[0]);

What's happening is an implicit *construction* of a static array, in a context where implicit construction is not allowed.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
October 09, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=11206



--- Comment #3 from Maxim Fomin <maxim@maxim-fomin.ru> 2013-10-09 09:38:00 PDT ---
(In reply to comment #2)
> (In reply to comment #1)
> > So, what?
> > 
> > Basically you are complainig about:
> > 
> > import std.stdio;
> > 
> > struct AGG
> > {
> >     int[1] t;
> >     double d;
> > }
> > 
> > void main()
> > {
> >     AGG tarr2 = AGG(1);
> >     writeln(tarr2);
> > }
> > 
> > which prints AGG([1], nan).
> 
> ...Unsure what you are trying to show? the "AGG(1)".

actually the AGG([1], nan) to show struct literal behavior.

> > AGG(1) is a struct literal which is valid in D.
> 
> I'm arguing that AGG should not be constructible taking a 1.

That's clear, but if you want to break the language you need to consider writing to newsgroup. Silent language change based on some issue in bugzilla is evil.

> > Integer literal is a valid
> > initializer for static array. Statement "AGG!S ts1 = AGG!S(1);" is rejected
> > because (unfortunately) 1 is not convertible to struct.
> 
> Yes, integer is a valid initializer for a static array, and it is also a valid initializer for a struct that holds an int.

Right.

> 
> However, 1 is not convertible to a struct,

Right. It is sad fact but in this context it is irrelevant because in the example there is no conversion from 1 to struct, there is struct literal with partial initializer which match initializer for first field.

> not is it convertible to a static array.

Wrong. int[1] ai = 1; ai = 1; is fine with the language so far. However in this case we speak about struct initializer so having integer literal to be initializer for static integer array is sufficient.

> AGG(1) should not compile, because 1 is not convertible to
> typeof(AGG.tupleof[0]);

Please refer to the spec or argue if spec is incomplete for a particular case. Making up rules is not good. Adressing your point - this is incorrect because typeof(AGG.tupleof[0]) has type int[1] and initializaing or assigning 1 to int[1] is legal in D. I deliberatly unwrapped all templates to show that you are effectivelly protesting against int[1] = 1;

> What's happening is an implicit *construction* of a static array, in a context where implicit construction is not allowed.

This is not the case. Here is struct literal with partial list of initializers which match respective type initializers which is fine as far D is concern. If you are complaining because this breaks some assumption of a brilliant phobos ideom, this should be mentioned explicitly so some solution without damaging language can be found (personally I object to break the language for the sake of writing cute template in phobos).

Please don't reopen issue: CLOSED->REOPENED->CLOSED war is not good either.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
October 09, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=11206



--- Comment #4 from monarchdodra@gmail.com 2013-10-09 13:03:47 PDT ---
(In reply to comment #3)
> (In reply to comment #2)
> > I'm arguing that AGG should not be constructible taking a 1.
> 
> That's clear, but if you want to break the language you need to consider writing to newsgroup. Silent language change based on some issue in bugzilla is evil.

Filing it in buzilla is the first step.

> > > Integer literal is a valid
> > > initializer for static array. Statement "AGG!S ts1 = AGG!S(1);" is rejected
> > > because (unfortunately) 1 is not convertible to struct.
> > 
> > Yes, integer is a valid initializer for a static array, and it is also a valid initializer for a struct that holds an int.
> 
> Right.
> 
> > 
> > However, 1 is not convertible to a struct,
> 
> Right. It is sad fact but in this context it is irrelevant because in the example there is no conversion from 1 to struct, there is struct literal with partial initializer which match initializer for first field.
> 
> > not is it convertible to a static array.
> 
> Wrong. int[1] ai = 1; ai = 1; is fine with the language so far. However in this case we speak about struct initializer so having integer literal to be initializer for static integer array is sufficient.

That doesn't mean convertible. It just means constructible and assignable:
struct S
{
    this(int);
    void opAssign(int);
}
S s = 1; s = 1;

Does that mean int is convertible to S? it doesn't.

Also:
is(int : int[1]); //FALSE

Also:
void foo(int[1]);
void main()
{
    foo(1); //HERE
}
Error: function foo (int[1]) is not callable using argument types (int)

> > AGG(1) should not compile, because 1 is not convertible to
> > typeof(AGG.tupleof[0]);
> 
> Please refer to the spec or argue if spec is incomplete for a particular case. Making up rules is not good. Adressing your point - this is incorrect because typeof(AGG.tupleof[0]) has type int[1] and initializaing or assigning 1 to int[1] is legal in D. I deliberatly unwrapped all templates to show that you are effectivelly protesting against int[1] = 1;

I will indeed lookup the exact spec. Please let me sleep on it. Do they make any mention about special behavior for static arrays?

> > What's happening is an implicit *construction* of a static array, in a context where implicit construction is not allowed.
> 
> This is not the case. Here is struct literal with partial list of initializers which match respective type initializers which is fine as far D is concern.

Except the type "int" doesn't match nor is convertible to the type "int[1]"

int[1] *can* be *initialized* from an int, yes. But so can a struct. Yet doing the same for a struct that is both constructible and assignable doesn't work (as I believe the spec says it shouldn't).

> If
> you are complaining because this breaks some assumption of a brilliant phobos
> ideom, this should be mentioned explicitly so some solution without damaging
> language can be found (personally I object to break the language for the sake
> of writing cute template in phobos).

That's definitely not the reason. However, that piece of code "shows" that static arrays get a special treatment, that I do not believe they should get.

> Please don't reopen issue: CLOSED->REOPENED->CLOSED war is not good either.

Works for me if you agree to rebuke my points and prove me wrong :)

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
October 09, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=11206



--- Comment #5 from Maxim Fomin <maxim@maxim-fomin.ru> 2013-10-09 13:33:42 PDT ---
Let's start from the basics.

import std.stdio;

struct AGG
{
    int[1] t;
    double d;
}

void main()
{
    AGG tarr2 = AGG(1);
    writeln(tarr2);
}

Claim is follows: this is a D valid code.

Backing:
1) AGG(1) is a struct literal (struct spec page). Note, that struct literal
really means struct literal, not "default struct constructor" or "implicit
function call" or "call expression" or any other 'creative' understaning of
language rules.
2) Struct literal contains member initializers which should match in order and
type to struct member initializer (struct spec page + TDPL).
3) Integer literal is valid initializer for static array of ints (TDPL).

You can either refute the backing or make contra point that although the code is valid, it shouldn't be because the code is bad/wrong/unsafe (but I don't see how you can convince that reasoning is wrong or the code is unsafe).

Before you write again about assignment, call expressions or implicit type conversion, please note, that whether integeral expression is convertible to struct, whether integer expression is convertible to static array in call expression, whether is(int: int[10]) is true, all of this is irrelevant to the initialization case.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
October 09, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=11206



--- Comment #6 from monarchdodra@gmail.com 2013-10-09 14:11:33 PDT ---
(In reply to comment #5)
> Claim is follows: this is a D valid code.

OK.

> Backing:
> 1) AGG(1) is a struct literal (struct spec page). Note, that struct literal
> really means struct literal, not "default struct constructor" or "implicit
> function call" or "call expression" or any other 'creative' understaning of
> language rules.
> 2) Struct literal contains member initializers which should match in order and
> type to struct member initializer (struct spec page + TDPL).
> 3) Integer literal is valid initializer for static array of ints (TDPL).

How do you define "is a valid initializer"? The struct page (http://dlang.org/struct.html ?) doesn't actually define it (nor does it define much on what is or isn't a valid construction type.

In my original case, S can be initialized by int, so isn't int a valid initializer for S? If not, why not? Just because? This is what is throwing me off.

Seems the root argument is that static arrays are the *only* type that can be initialized form a type that is not implicitly "it", and that this special rule applies *only* during aggregate construction.

I see neither of the two points explained in struct.html, nor array.html ?

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
October 10, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=11206



--- Comment #7 from Kenji Hara <k.hara.pg@gmail.com> 2013-10-09 21:54:03 PDT ---
The inconsistency comes from the incomplete fix of bug 7019.

struct Agg(T) { T val; }
void main()
{
    int[3] sa = 1;                // 1a, OK
    auto agg1 = Agg!(int[3])(1);  // 1b, OK

    struct S { this(int) {} }
    S s = 1;                      // 2a, OK, by fixing issue 7019
    auto agg2 = Agg!S(1);         // 2b
}

Since long time ago, 1a and 1b has been allowed.

On the other hand, from 2.061, 2a has formally become a part of the language spec, by fixing issue 7019.

However, currently 2b is still disallowed.

Because, when I had wrote a compiler patch for bug 7019, I had thought that accepting it might cause some ambiguity on multi-dimentional array initializing.

  struct S { this(int) {} }
  S[2][2] sa = [1, 2];
  // exactly same as:
  //      sa = [[S(1), S(2)], [S(1), S(2)]]
  // or:  sa = [[S(1), S(1)], [S(2), S(2)]]
  // ?

But recently, I found a new consistent rule to resolve the ambiguity. Based on the rule in my brain, the 2b case would also be accepted.

Therefore, the current inconsistency is a bug to me. If T t = val; is accepted, the struct literal syntax Aggr!T(val) should also be accepted.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
October 10, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=11206



--- Comment #8 from Maxim Fomin <maxim@maxim-fomin.ru> 2013-10-09 23:19:45 PDT ---
(In reply to comment #6)
> (In reply to comment #5)
> > Claim is follows: this is a D valid code.
> 
> OK.
> 
> > Backing:
> > 1) AGG(1) is a struct literal (struct spec page). Note, that struct literal
> > really means struct literal, not "default struct constructor" or "implicit
> > function call" or "call expression" or any other 'creative' understaning of
> > language rules.
> > 2) Struct literal contains member initializers which should match in order and
> > type to struct member initializer (struct spec page + TDPL).
> > 3) Integer literal is valid initializer for static array of ints (TDPL).
> 
> How do you define "is a valid initializer"? The struct page (http://dlang.org/struct.html ?) doesn't actually define it (nor does it define much on what is or isn't a valid construction type.

TDPL has explicit example in the beginning of fixed array chapter.

> In my original case, S can be initialized by int, so isn't int a valid initializer for S? If not, why not? Just because? This is what is throwing me off.

struct S{int i;this(int){}}

struct AGG(T)
{
    T t;
}

void main()
{
    AGG!S ts2 = AGG!S(S(2)); //Explicit. Good.
    AGG!S ts1 = AGG!S(1); //NO! ILLEGAL REQUEST FOR IMPLICIT CONSTRUCTION!
}

Second does not work because S(1) is not a struct literal but a constructor
call. AGG!S(1) initializer now would require function call S.__ctor(1) which is
not currently supported.

> Seems the root argument is that static arrays are the *only* type that can be initialized form a type that is not implicitly "it", and that this special rule applies *only* during aggregate construction.

It seems you starting to understand the issue (but I haven't thought whether static arrays are only types supporting this).

> I see neither of the two points explained in struct.html, nor array.html ?

It is in TDPL. Anyway this feature was working for years.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
October 10, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=11206



--- Comment #9 from Maxim Fomin <maxim@maxim-fomin.ru> 2013-10-09 23:31:12 PDT ---
(In reply to comment #7)
> The inconsistency comes from the incomplete fix of bug 7019.
> 
> struct Agg(T) { T val; }
> void main()
> {
>     int[3] sa = 1;                // 1a, OK
>     auto agg1 = Agg!(int[3])(1);  // 1b, OK
> 
>     struct S { this(int) {} }
>     S s = 1;                      // 2a, OK, by fixing issue 7019
>     auto agg2 = Agg!S(1);         // 2b
> }
> 
> Since long time ago, 1a and 1b has been allowed.
> 
> On the other hand, from 2.061, 2a has formally become a part of the language spec, by fixing issue 7019.
> 
> However, currently 2b is still disallowed.

Formally this is right because struct initializers are not recursive. If
Add!int(1) is a valid struct literal doesn't mean that Agg!S(1) is also valid
because S(1) is valid (by the way, here you placed constructor not literal).
Unfortunately there is no implicit conversion between basic type to struct type
even if the latter is constructable from the former.

> Because, when I had wrote a compiler patch for bug 7019, I had thought that accepting it might cause some ambiguity on multi-dimentional array initializing.
> 
>   struct S { this(int) {} }
>   S[2][2] sa = [1, 2];
>   // exactly same as:
>   //      sa = [[S(1), S(2)], [S(1), S(2)]]
>   // or:  sa = [[S(1), S(1)], [S(2), S(2)]]
>   // ?
> 
> But recently, I found a new consistent rule to resolve the ambiguity. Based on the rule in my brain, the 2b case would also be accepted.
> 
> Therefore, the current inconsistency is a bug to me. If T t = val; is accepted, the struct literal syntax Aggr!T(val) should also be accepted.

As I have mentioned previously, there is no inconsistency because you implicitly assuming that struct literal/constructors can be recursive or 'nested' in some sense. If you mean allowing AGG!S ts1 = AGG!S(1); in original example, then this is a minor enhancement.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
« First   ‹ Prev
1 2