On Friday, 9 March 2018 at 23:34:56 UTC, Mike Franklin wrote:
On Friday, 9 March 2018 at 14:46:04 UTC, Simen Kjærås wrote:
1) Wrong return type:
unittest {
S s;
auto a = s.field;
// Fails - typeof(a) is Property!((get) => this.n, (set)
=> this.n = set)
assert(is(typeof(a) == int));
}
This looks like a related issue:
https://issues.dlang.org/show_bug.cgi?id=16657. That's is a
deal-breaker for me, but I think it could be fixed.
This has nothing to do with alias this, opCmp, or opEquals. It's
simply that instead of returning an int, like the original
property did, s.field returns a wrapper type. There's no real way
around this.
Actually, there may be a more interesting way to implement the
DIP I mentioned - what if named mixin templates could have
overloaded operators and alias this? What if this worked:
struct S {
int n;
mixin property!(get => n, set => n = set) field;
}
template property(fns...) {
alias getter = findGetter!fns;
alias setter = findSetter!fns;
auto get() { return getter(DummyType.init); }
alias get this;
alias setter opAssign;
auto opOpAssign(string op, T)(T value) { /* ... */ }
// other overloads
}
unittest {
S s;
auto a = s.field; // Not a type, so alias this is used.
assert(is(typeof(a) == int));
// overloaded operators
s.field += 4;
++s.field;
}
From what I can see, the only necessary change would be that
alias this and operator overloads be looked for in named mixin
templates. Sounds doable. This would both enable
auto-decaying/rvalue types, and allow for a bunch of interesting
stuff with operator overloads.
...but there's an issue with this compared to real rvalue types -
you can't return them from a function. One use case for rvalue
types is short-circuiting when (a op1 b op2 c) can be done faster
than ((a op1 b) op2 c), for instance when a, b, and c are
BigInts, and op1 = ^^, op2 = %. Named mixin templates with
overloaded operators cannot do this.
2) Noisy syntax:
If I had my druthers, mixin templates would be mixin'd
automatically, and eponymous mixin templates would be a thing.
Yes, this would be nice, but I don't think it's a deal-breaker.
Agreed. I filed an issue on the eponymous mixin templates:
https://issues.dlang.org/show_bug.cgi?id=18586
3) Stringy functions:
The string literal functions are an eyesore, but would require
some compiler work to fix.
Yeah, that's quite unfortunate; writing code in strings stinks.
I actually prefer the DIP for this issue alone.
I'm not sure how fixable this is, but I am sure that there's
plenty of benefit to being able to write code like this:
struct S {
int n, m;
SomeType!(() => n + m) a;
}
over this:
struct S {
int n, m;
auto a() { return SomeType!(() => n + m)(); }
}
Anyways, I filed a bug for it:
https://issues.dlang.org/show_bug.cgi?id=18587
If all of the issues you've identified were addressed, you'd
end up with something like this (formatted in a C# way).
struct S {
int n;
property!
(
get =>
{
n
},
set =>
{
n = set
}
) field;
}
That's actually pretty darn good. It makes me wonder if I
should work on fixing those issues or continue with the DIP.
The real benefit to doing it outside the DIP is that the features
can be used in other contexts. Rvalue types definitely have some
more uses, the 'this.n' issue is simply a bug, eponymous mixin
templates seem useful to me, and being able to use delegates as
template parameters outside of member functions would make many
things clearer.
If you don't have any objections I'd like to incorporate this
implementation and your analysis into the DIP.
Of course.
Thank you again for doing this; you've saved me a awful lot of
time, and have done more than I probably could have.
Pleasure. I've been spending some time on this myself, so it's
not the first time I've tried to make a palatable implementation.
--
Simen