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;

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:

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:

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;
        get =>
        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.


Reply via email to