www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Tuple [] operator

reply Christian Manning <cmanning999 gmail.com> writes:
Hi,
I'm receiving this error with dmd 2.054:
"tmp.d(7): Error: no [] operator overload for type Tuple!(int,short)" for 
the following test case

import std.typecons;
void main() {
auto x = 1;
Tuple!(int,short) a;
a[0] = 1;
a[x] = 2;
}

If I use a value instead of a variable ie. a[1] = 2; it compiles fine.

A search turned up http://d.puremagic.com/issues/show_bug.cgi?id=6273 and 
http://d.puremagic.com/issues/show_bug.cgi?id=6342 though they specifically 
mention the use of pure functions which I'm not using. Is this the same 
problem anyway?

Chris
Aug 08 2011
next sibling parent reply Philippe Sigaud <philippe.sigaud gmail.com> writes:
Hi Chris,

 import std.typecons;
 void main() {
 auto x = 1;
 Tuple!(int,short) a;
 a[0] = 1;
 a[x] = 2;
 }

 If I use a value instead of a variable ie. a[1] = 2; it compiles fine.

The index need to be a compile-time constant, you cannot index a tuple with a runtime value. Try using enum x = 1; Philippe
Aug 08 2011
parent reply Christian Manning <cmanning999 gmail.com> writes:
Philippe Sigaud wrote:

 Hi Chris,
 
 import std.typecons;
 void main() {
 auto x = 1;
 Tuple!(int,short) a;
 a[0] = 1;
 a[x] = 2;
 }

 If I use a value instead of a variable ie. a[1] = 2; it compiles fine.

The index need to be a compile-time constant, you cannot index a tuple with a runtime value. Try using enum x = 1; Philippe

Ah I didn't know this, thanks. That makes a tuple pretty useless for what I was doing now as I was reading the "index" in from a file. Guess I'll find another way round it. Thanks Chris
Aug 08 2011
parent Christian Manning <cmanning999 gmail.com> writes:
Philippe Sigaud wrote:

 On Mon, Aug 8, 2011 at 21:55, Steven Schveighoffer <schveiguy yahoo.com>
 wrote:
 
 You still can do it, but you have to do it by still using compile-time
 constants as indexes:

 auto x = 1;
 Tuple!(int, short) a;

 a[0] = 1;
 switch(x)
 {
 case 0:
 a[0] = 2;
 break;
 case 1:
 a[1] = 2;
 break;
 default:
 assert(0, "does not compute!");
 }

Christian, I think Steven even suggested in an article some months ago that this big switch could be generated at compile time. Steven, do you have a link somewhere? I mean, the tuple length is known as C-T. It's easy to loop on it and build a string of cases. If you wrap it in a function, it becomes a runtime switcher. Proof of concept: import std.typecons; string generateSwitches(T...)() { string result = "switch(x) {\n"; foreach(i,Type; T) { result ~= "case " ~ to!string(i) ~ ":\n" ~ "fun(tup[" ~ to!string(i) ~ "]);\n" ~ "break;\n"; } return result ~ "default:\n" ~ "assert(0, q{Bad index: } ~ to!string(x));\n}"; } void actOnTuple(alias fun, T...)(int x, ref Tuple!T tup) { mixin(generateSwitches!(T)); } void foo(T)(ref T t) { writeln(t); t = T.init;} void main() { auto tup = tuple(1, 3.14, "abc"); auto x = 1; actOnTuple!foo(x, tup); writeln(tup); } Philippe

I haven't used string mixins before so I suppose this is a good time to learn! Thanks for the help, Steven and Philippe. Chris
Aug 08 2011
prev sibling next sibling parent Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On 08.08.2011 23:27, Christian Manning wrote:
 Hi,
 I'm receiving this error with dmd 2.054:
 "tmp.d(7): Error: no [] operator overload for type Tuple!(int,short)" for
 the following test case

 import std.typecons;
 void main() {
 auto x = 1;
 Tuple!(int,short) a;
 a[0] = 1;
 a[x] = 2;
 }

 If I use a value instead of a variable ie. a[1] = 2; it compiles fine.

 A search turned up http://d.puremagic.com/issues/show_bug.cgi?id=6273 and
 http://d.puremagic.com/issues/show_bug.cgi?id=6342 though they specifically
 mention the use of pure functions which I'm not using. Is this the same
 problem anyway?

index, only with something known at compile time. Replace auto with enum and you are fine, you can even call a function using CTFE to get an index. -- Dmitry Olshansky
Aug 08 2011
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 08 Aug 2011 15:47:36 -0400, Christian Manning  
<cmanning999 gmail.com> wrote:

 Philippe Sigaud wrote:

 Hi Chris,

 import std.typecons;
 void main() {
 auto x = 1;
 Tuple!(int,short) a;
 a[0] = 1;
 a[x] = 2;
 }

 If I use a value instead of a variable ie. a[1] = 2; it compiles fine.

The index need to be a compile-time constant, you cannot index a tuple with a runtime value. Try using enum x = 1; Philippe

Ah I didn't know this, thanks. That makes a tuple pretty useless for what I was doing now as I was reading the "index" in from a file. Guess I'll find another way round it.

You still can do it, but you have to do it by still using compile-time constants as indexes: auto x = 1; Tuple!(int, short) a; a[0] = 1; switch(x) { case 0: a[0] = 2; break; case 1: a[1] = 2; break; default: assert(0, "does not compute!"); } the point is, the compiler has no idea what the lvalue expression's type should be when you do: a[x] = 1; is it short or int? so the compiler must *know* what type x is at compile time in order for this to be valid. -Steve
Aug 08 2011
prev sibling next sibling parent Ali =?iso-8859-1?q?=C7ehreli?= <acehreli yahoo.com> writes:
On Mon, 08 Aug 2011 15:55:38 -0400, Steven Schveighoffer wrote:

 On Mon, 08 Aug 2011 15:47:36 -0400, Christian Manning
 <cmanning999 gmail.com> wrote:

[...]
 auto x = 1;
 Tuple!(int, short) a;
 
 a[0] = 1;
 switch(x)
 {
 case 0:
     a[0] = 2;
     break;
 case 1:
     a[1] = 2;

Those assignments are now bound at compile time.
     break;
 default:
     assert(0, "does not compute!");
 }
 
 the point is, the compiler has no idea what the lvalue expression's type
 should be when you do:
 
 a[x] = 1;
 
 is it short or int?
 
 so the compiler must *know* what type x is at compile time in order for
 this to be valid.

I think it's more import for the compiler to know what type a[x] is. The assignment operators of different types are different. On the other hand, I don't think a short vs int would make a difference when it comes to indexing (it shouldn't anyway).
 
 -Steve

Ali
Aug 08 2011
prev sibling next sibling parent Ali =?iso-8859-1?q?=C7ehreli?= <acehreli yahoo.com> writes:
On Mon, 08 Aug 2011 20:32:03 +0000, Ali Çehreli wrote:

 the point is, the compiler has no idea what the lvalue expression's
 type should be when you do:
 
 a[x] = 1;
 
 is it short or int?
 
 so the compiler must *know* what type x is at compile time in order for
 this to be valid.

I think it's more import for the compiler to know what type a[x] is. The assignment operators of different types are different. On the other hand, I don't think a short vs int would make a difference when it comes to indexing (it shouldn't anyway).
 -Steve

Ali

I correct myself before Steve does: I missed the "lvalue" above. Steve meant a[x] anyway. Ali
Aug 08 2011
prev sibling next sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Mon, Aug 8, 2011 at 21:55, Steven Schveighoffer <schveiguy yahoo.com> wr=
ote:

 You still can do it, but you have to do it by still using compile-time
 constants as indexes:

 auto x =3D 1;
 Tuple!(int, short) a;

 a[0] =3D 1;
 switch(x)
 {
 case 0:
 =C2=A0 a[0] =3D 2;
 =C2=A0 break;
 case 1:
 =C2=A0 a[1] =3D 2;
 =C2=A0 break;
 default:
 =C2=A0 assert(0, "does not compute!");
 }

Christian, I think Steven even suggested in an article some months ago that this big switch could be generated at compile time. Steven, do you have a link somewhere? I mean, the tuple length is known as C-T. It's easy to loop on it and build a string of cases. If you wrap it in a function, it becomes a runtime switcher. Proof of concept: import std.typecons; string generateSwitches(T...)() { string result =3D "switch(x) {\n"; foreach(i,Type; T) { result ~=3D "case " ~ to!string(i) ~ ":\n" ~ "fun(tup[" ~ to!string(i) ~ "]);\n" ~ "break;\n"; } return result ~ "default:\n" ~ "assert(0, q{Bad index: } ~ to!string(x));\n}"; } void actOnTuple(alias fun, T...)(int x, ref Tuple!T tup) { mixin(generateSwitches!(T)); } void foo(T)(ref T t) { writeln(t); t =3D T.init;} void main() { auto tup =3D tuple(1, 3.14, "abc"); auto x =3D 1; actOnTuple!foo(x, tup); writeln(tup); } Philippe
Aug 08 2011
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 08 Aug 2011 16:50:48 -0400, Philippe Sigaud  
<philippe.sigaud gmail.com> wrote:

 On Mon, Aug 8, 2011 at 21:55, Steven Schveighoffer <schveiguy yahoo.com>  
 wrote:

 You still can do it, but you have to do it by still using compile-time
 constants as indexes:

 auto x = 1;
 Tuple!(int, short) a;

 a[0] = 1;
 switch(x)
 {
 case 0:
   a[0] = 2;
   break;
 case 1:
   a[1] = 2;
   break;
 default:
   assert(0, "does not compute!");
 }

Christian, I think Steven even suggested in an article some months ago that this big switch could be generated at compile time. Steven, do you have a link somewhere?

Sorry, wasn't me...
 I mean, the tuple length is known as C-T. It's easy to loop on it and
 build a string of cases. If you wrap it in a function, it becomes a
 runtime switcher.

 Proof of concept:

 import std.typecons;

 string generateSwitches(T...)()
 {
     string result = "switch(x) {\n";
     foreach(i,Type; T)
     {
         result ~= "case " ~ to!string(i) ~ ":\n"
                 ~ "fun(tup[" ~ to!string(i) ~ "]);\n"
                 ~ "break;\n";
     }
     return result ~ "default:\n"
                   ~ "assert(0, q{Bad index: } ~ to!string(x));\n}";
 }

 void actOnTuple(alias fun, T...)(int x, ref Tuple!T tup)
 {
     mixin(generateSwitches!(T));
 }

 void foo(T)(ref T t) { writeln(t); t = T.init;}

 void main()
 {
     auto tup = tuple(1, 3.14, "abc");
     auto x = 1;
     actOnTuple!foo(x, tup);
     writeln(tup);
 }

I like this idea. I think it belongs in phobos somewhere, if not already. -Steve
Aug 08 2011
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 8/8/11, Steven Schveighoffer <schveiguy yahoo.com> wrote:
 I like this idea.  I think it belongs in phobos somewhere, if not already.

 -Steve

Allow me to +1 on that, I've had a need for this (but now I can't remember why, hah!).
Aug 08 2011
prev sibling next sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
 Sorry, wasn't me...

Oops, sorry.
 I like this idea. =C2=A0I think it belongs in phobos somewhere, if not al=

I remember getting the idea in one of the articles written to win an iPad2 a few months ago. Philippe
Aug 08 2011
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 09 Aug 2011 01:34:34 -0400, Philippe Sigaud  
<philippe.sigaud gmail.com> wrote:

 Sorry, wasn't me...

Oops, sorry.
 I like this idea.  I think it belongs in phobos somewhere, if not  
 already.

I remember getting the idea in one of the articles written to win an iPad2 a few months ago.

Maybe Nick's (something about efficiency vs. flexibility?), mine was about array appending, David's and Robert's were about concurrency/parallelism, and Jonathan's was about migrating to std.datetime from std.date. There were also a couple that were suggested but did not officially enter, could have been one of those? -Steve
Aug 09 2011
prev sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Tue, Aug 9, 2011 at 17:43, Steven Schveighoffer <schveiguy yahoo.com> wrote:

 Maybe Nick's (something about efficiency vs. flexibility?), mine was about
 array appending, David's and Robert's were about concurrency/parallelism,
 and Jonathan's was about migrating to std.datetime from std.date.

Yes, that was Nick's: [5] Have Your Efficiency, and Flexibility Too by Nick SAbalausky http://www.semitwist.com/articles/EfficientAndFlexible/SinglePage/#part6-3 (Converting a Runtime Value to Compile-Time)
Aug 09 2011