www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - A problem with AAs

reply bearophile <bearophileHUGS lycos.com> writes:
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
Jan 24 2008
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"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[].
Jan 24 2008
parent reply bearophile <bearophileHUGS lycos.com> writes:
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
Jan 24 2008
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"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..
Jan 24 2008
parent Robert Fraser <fraserofthenight gmail.com> writes:
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.
Jan 24 2008