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.