Thread overview
A problem with AAs
Jan 24, 2008
bearophile
Jan 24, 2008
bearophile
Jan 25, 2008
Robert Fraser
January 24, 2008
Sometimes it can be useful a function that returns a light iterable that yields the keys or values of an AA, so such iterable can be given to templated functions that blindly iterate on their input using a foreach. So I've tried to create an xvalues (and xkeys) iterable, like this:

Xvalues!(TK, TV) xvalues(TK, TV)(TV[TK] aa) {
  return new Xvalues!(TK, TV)(aa);
}

class Xvalues(TK, TV) {
  TV[TK] aa;
  this(TV[TK] aa) { this.aa = aa; }

  int opApply(int delegate(ref TV) dg) {
    int result;
    foreach(val; aa) {
      result = dg(val);
      if (result) break;
    }
    return result;
  }
}

void main() {
  xvalues(["ab":"AB"]);
}


But as you probably know that doesn't work, it gives:
xtest.d(10): Error: cannot have out or ref parameter of type char[2u]
xtest.d(1): template instance xtest.Xvalues!(char[2u],char[2u]) error instantiating

So far the only way I have found to solve that is something like this:

template IsArray(T) {
    const bool IsArray = is(typeof(T.length)) && is(typeof(T.sort)) &&
                         is(typeof(T.reverse)) && is(typeof(T.dup));
}

template ArrayType1(T: T[]) {
    alias T ArrayType1;
}

template DeconstArrType(T) {
    static if (IsArray!(T))
        alias ArrayType1!(T)[] DeconstArrType;
    else
        alias T DeconstArrType;
}

class Xvalues(TK, TV) {
  TV[TK] aa;
  alias DeconstArrType!(TV) TyItem;
  this(TV[TK] aa) { this.aa = aa; }

  int opApply(int delegate(ref TyItem) dg) {
    int result;
    foreach(val; aa.values) {
      TyItem item = val;
      result = dg(item);
      if (result) break;
    }
    return result;
  }
}

But I can't accept that because it changes the type of the values (from a static to a dynamic array). (If this problem can't be solved then I think I'll just restrict the xvalues/xkeys to AAs that don't have static arrays as keys/values).

Bye,
bearophile
January 24, 2008
"bearophile" <bearophileHUGS@lycos.com> wrote in message news:fn9rkq$210u$1@digitalmars.com...

> But I can't accept that because it changes the type of the values (from a static to a dynamic array). (If this problem can't be solved then I think I'll just restrict the xvalues/xkeys to AAs that don't have static arrays as keys/values).

That's probably the best you _can_ do.  The issue, as usual, arises from AA literals being weird.

> void main() {
>  xvalues(["ab":"AB"]);
> }

If you use ["ab"[] : "AB"[]] instead, it works, as the key and value types are now interpreted as char[].


January 24, 2008
Jarrett Billingsley:
> That's probably the best you _can_ do.  The issue, as usual, arises from AA literals being weird.

Thank you for your answer, then I'll probably restrict the usage of those functions, refusing at compile time the AAs with static arrays.

But I think that can't be classified as a problem of AA literals, a literal is a way to define something in the code. I think the problem there is that the opApply() doesn't allow you to yield a reference to a static array (regardless the way you have defined the AA in your source code... I may want an AA with a static array as values anyway). (I don't fully understand still the inner workings of opApply, do you know why it has such limitation?)

Bye,
bearophile
January 24, 2008
"bearophile" <bearophileHUGS@lycos.com> wrote in message news:fnabcn$qhs$1@digitalmars.com...
> Jarrett Billingsley:
>> That's probably the best you _can_ do.  The issue, as usual, arises from
>> AA
>> literals being weird.
>
> Thank you for your answer, then I'll probably restrict the usage of those functions, refusing at compile time the AAs with static arrays.
>
> But I think that can't be classified as a problem of AA literals, a literal is a way to define something in the code. I think the problem there is that the opApply() doesn't allow you to yield a reference to a static array (regardless the way you have defined the AA in your source code... I may want an AA with a static array as values anyway). (I don't fully understand still the inner workings of opApply, do you know why it has such limitation?)
>
> Bye,
> bearophile

It's not opApply, it's that static arrays are second-class types.  They are bizarre.

They are the only types whose .init is not the same type as themselves (try it!  their .init is their element type).

They cannot be returned from functions because they are allocated on the stack.

Although they are allocated on the stack like value types, they are never passed by value: passing a static array to a function actually passes the pointer to it, so if you modify a static array parameter in a function you're actually modifying the array that was passed in.

Finally, they cannot be 'ref' or 'out' (hence the issue with opApply).  I don't know why the compiler can't do this.

Most of this stems from them trying to be binary-compatible with C arrays. They are allocated on the stack, you can't return them from functions, and passing them passes a pointer.  I have no idea what's up with .init (D1's std.traits actually takes advantage of this oddity to determine if a type is a static array!), and the no-ref-out thing is weird.  I mean, it's because you can't reassign what a static array variable points to..


January 25, 2008
Jarrett Billingsley wrote:
> Most of this stems from them trying to be binary-compatible with C arrays. They are allocated on the stack, you can't return them from functions, and passing them passes a pointer.  I have no idea what's up with .init (D1's std.traits actually takes advantage of this oddity to determine if a type is a static array!), and the no-ref-out thing is weird.  I mean, it's because you can't reassign what a static array variable points to.. 
> 

I'd be fine with all that if string (and other array) literals were dynamic by default.