Jump to page: 1 2
Thread overview
Tuple [] operator
Aug 08, 2011
Christian Manning
Aug 08, 2011
Philippe Sigaud
Aug 08, 2011
Christian Manning
Aug 08, 2011
Ali Çehreli
Aug 08, 2011
Ali Çehreli
Aug 08, 2011
Philippe Sigaud
Aug 08, 2011
Christian Manning
Aug 09, 2011
Andrej Mitrovic
Aug 09, 2011
Philippe Sigaud
Aug 09, 2011
Philippe Sigaud
Aug 08, 2011
Dmitry Olshansky
August 08, 2011
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
August 08, 2011
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
August 08, 2011
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?
>
Your case seems simple, it means you can't index tuple with variable as 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

August 08, 2011
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
August 08, 2011
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
August 08, 2011
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
August 08, 2011
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
August 08, 2011
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
August 08, 2011
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
August 08, 2011
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
« First   ‹ Prev
1 2