Thread overview
Tuple opAssign type deduction
Dec 24, 2014
aldanor
Dec 24, 2014
ketmar
Dec 24, 2014
ketmar
Dec 24, 2014
ketmar
Dec 24, 2014
bearophile
Dec 24, 2014
ketmar
December 24, 2014
alias T = Tuple!(int, "a", double, "b");
T foo = [1, 2]; // works
T bar;
bar = [1, 2]; // doesn't?

Wonder if there's an obvious reason to this?
December 24, 2014
On Wed, 24 Dec 2014 00:16:33 +0000
aldanor via Digitalmars-d <digitalmars-d@puremagic.com> wrote:

> alias T = Tuple!(int, "a", double, "b");
> T foo = [1, 2]; // works
> T bar;
> bar = [1, 2]; // doesn't?
> 
> Wonder if there's an obvious reason to this?

you mean "other than the fact that `T foo = [1, 2];` is initalization, not assigning"? ;-)

you just stepped into two operations that looking almost the same, but does very different things.

the thing is that Tuple supports assigning only from another Tuple. it is possible to build `opAssign` templates to support the case you shown, but it will be cumbersome and will bloat the code.

tl;dr: nobody wrote the proper `opAssign` generator. ;-)


December 24, 2014
On Wed, 24 Dec 2014 00:16:33 +0000
aldanor via Digitalmars-d <digitalmars-d@puremagic.com> wrote:

> alias T = Tuple!(int, "a", double, "b");
> T foo = [1, 2]; // works
> T bar;
> bar = [1, 2]; // doesn't?
> 
> Wonder if there's an obvious reason to this?

to clarify "different operations" a little. take a look at this code:

  import std.stdio;

  struct S {
    string v;
    this (string vv) { writeln("ctor!"); v = vv; }
    void opAssign (string vv) { writeln("assign!"); v = vv; }
  }

  void main () {
    S a = "hello"; // (1) outputs "ctor!"
    S b;
    b = "hey!"; // (2) outputs "assign!"
  }

see, (1) is transformed to: `S a = S("hello");`. so your first case is
calling Tuple ctor, and your second case is calling Tuple `opAssign`.

Tuple ctor is defined like this:

  /**
    * Constructor taking a compatible array.
    *
    * Examples:
    * ----
    * int[2] ints;
    * Tuple!(int, int) t = ints;
    * ----
   */
   this(U, size_t n)(U[n] values)
   if (n == Types.length && allSatisfy!(isBuildableFrom!U, Types))

and Type `opAssign` is defined like this:

  void opAssign(R)(auto ref R rhs)
  if (areCompatibleTuples!(typeof(this), R, "="))

i.e. we can construct Tuple from array, but can't assign array to Tuple.


December 24, 2014
On Wed, 24 Dec 2014 00:16:33 +0000
aldanor via Digitalmars-d <digitalmars-d@puremagic.com> wrote:

> alias T = Tuple!(int, "a", double, "b");
> T foo = [1, 2]; // works
> T bar;
> bar = [1, 2]; // doesn't?
> 
> Wonder if there's an obvious reason to this?
as for "why it's not working"... i honestly don't know. adding simple `opAssign` overload to Tuple struct solves it:

  void opAssign(U, size_t n)(U[n] values)
  if (n == Types.length && allSatisfy!(isBuildableFrom!U, Types))
  {
      foreach (i, _; Types)
      {
          field[i] = values[i];
      }
  }

i guess that this was simply overlooked, so i think that you can create ER for this.


December 24, 2014
ketmar:

> i guess that this was simply overlooked, so i think that you can create ER for this.

Often tuple fields have different types, like a string and int.

And better to stop and wait for built-in tuple syntax instead of messing up more and more the Phobos tuples. The rabbit hole is deep enough already.

Bye,
bearophile
December 24, 2014
On Wed, 24 Dec 2014 01:00:08 +0000
bearophile via Digitalmars-d <digitalmars-d@puremagic.com> wrote:

> > i guess that this was simply overlooked, so i think that you can create ER for this.
> 
> Often tuple fields have different types, like a string and int.
sure, but then you can't initialize it from an array either. yet we have convient initializer for "convertable" arrays and have no `opAssign` for the same.

> And better to stop and wait for built-in tuple syntax instead of messing up more and more the Phobos tuples. The rabbit hole is deep enough already.
built-in tuple syntax may not arrive for another two years. or five. or... ;-) adding `opAssign` for arrays is just a convience feature: as we have ctor for this operation, it would be logical to have `opAssign` for it too.