On Monday, 26 February 2018 at 15:43:54 UTC, Bienlein wrote:
object Scratch extends App {
// compiles:
val list = List(1, 2.4, 5)
val sum = list.sum
println(sum)
// does not compile:
val list2 = List(1, 2.4, 5, "123")
val sum2 = list2.sum
println(sum2)
}
There's nothing in the language or standard library that supports
this. However, it's perfectly possible to make something with
those semantics:
import std.variant;
import std.stdio;
struct List(T) {
T[] values;
alias values this;
}
auto list(T...)(T args)
{
import std.traits : CommonType;
static if (is(CommonType!T == void))
List!Variant result;
else
List!(CommonType!T) result;
result.length = T.length;
foreach (i, e; args) {
result[i] = e;
}
return result;
}
auto sum(T)(List!T lst)
if (is(typeof(lst[0] + lst[0])) && !is(T == Variant))
{
T result = 0;
foreach (e; lst) {
result += e;
}
return result;
}
unittest {
auto list1 = list(1, 2.4, 5);
auto sum1 = list1.sum;
writeln(sum1);
auto list2 = list(1, 2.4, 5, "123");
auto sum2 = list2.sum;
writeln(sum2);
}
Since std.variant.Variant does operator overloads, we have to
explicitly check if T == Variant in the sum function. For
Variant, that's probably the correct choice. We could use
Algebraic instead, but it also does operator overloads, even when
no type in its arguments support them. Again, we could create our
own - Algebraic and Variant are library types, after all.
--
Simen