This will be a small rant that might be completely unjustified and it is not meant to talk ill about D.

I am new to D and I run into a road blocking issue https://issues.dlang.org/show_bug.cgi?id=10541

So I set myself to fixing it. Asking around the irc, it seems that the biggest problem was that tuples always copy and we need something that can hold references.

I was going to create a TupleRef but I run into some issues.

At first I created something similar to an std::reference_wrapper which I am also not sure was needed in the first place but here it is.


struct RefWrapper(T){
  T* value;

  this(ref T v){
    value = &v;
  }
  ref T get(){
    return *value;
  }
}
auto refWrapper(T)(ref T t){
  return RefWrapper!(T)(t);
}

RefWrapper is probably flawed, but let's pretend it works.


The general idea was to have a tuple of type Tuple!(RefWrapper(T1), RefWrapper(T2), ... , RefWrapper(TN));

It would probably work that way, but D has its own reference semantics with `ref`. I thought it would be nicer if you can reuse `ref` notation. For example:


foreach(t; something){
  t.get();
}

//vs

foreach(ref t; something){
}

That meant I needed to create a wrapper that would automatically unbox every RefWrapper.

struct TupleRef(Ts...){
  import std.meta;
  alias RefTs = staticMap!(RefWrapper, Ts);
  Tuple!RefTs refTs;
  this(ref Ts ts){
    refTs = ????
  }
}

Now we are at the problem that I constantly run into since I started with D.

It seems that D doesn't have a way to express C++'s fold expression/template expansions.


For example in C++ I could write

std::make_tuple(std::ref(ts)...);

and it would expand like

std::make_tuple(std::ref(t1), std::ref(t2), ... , std::ref(tn));

I would love to use staticMap! but it seems to only work for types, it could be altered slightly so that it would also work with normal functions but the values would still have to be read at compile time.


For this case I used my little helper function:

auto mapToTuple(alias f,T...)(){
  import std.typecons;
  static if(T.length == 0)  {
    return tuple();
  }
  else{
    return tuple(f(T[0]), mapToTuple!(f, T[1..$]).expand);
  }
}


TupleRef then became

struct TupleRef(Ts...){
  import std.meta;
  alias RefTs = staticMap!(RefWrapper, Ts);
  Tuple!RefTs refTs;
  this(Ts ts){
    refTs = mapToTuple!(refWrapper, ts);
  }
}


In this case everything seems to work nicely but the problem still exists.

For example I need to be able to expand TupleRef like this

f(someTupleRef.expand);
f(t[0].get(), t[1].get(), ... , t[n].get());
//f takes the arguments by ref

This time I can not use a tuple because it would copy the value. I also can not use `AliasSeq` because it needs it values at compile time.



Another small problem for TupleRef is opIndex. It seems that the [index] notation with opIndex doesn't allow me to express the use of compile time values.

It seems that tuple somehow manages this with

struct Tuple{
  ...
  alias expand this;
  ...
}

But I don't think I can use the same technique here.

I thought I would write a bigger post that explains my thoughts instead of asking in the irc. I hope it didn't sound too harsh which was not my intent.

Reply via email to