On Sunday, 18 November 2018 at 20:10:52 UTC, Dennis wrote:
On Sunday, 18 November 2018 at 18:17:54 UTC, Stanislav Blinov wrote:

Q log2(Q)(inout Q num) if (is(Q : q16) || is(Q : q32)) { /* ... */ }

Being able to jam mutable/const/immutable implementation in one function like that should tell you that you shouldn't mutate the argument. Then, the necessity to Unqual will go away on it's own ;)

Different overloads sounds like a lot of boilerplate.
inout still results in "cannot modify `inout` expression `input`"

You just dismissed that second to last sentence, did you? :)

My goal is to be able to write straightforward and correct signatures for fixed point functions that receive mutable copies of whatever they are fed. This isn't even limited to my custom types:

```
T f0(T)(T x, T y) {return x += y;}
int  f1(int  x, int  y) {return x += y;}
long f1(long x, long y) {return x += y;}
```
The explicit overloads of f1 work fine, but the generic f0 does not.

```
T f0(T)(inout T x, inout T y) { return x + y; }
```

;)

But if you really really want to mutate the argument, then handling different mutability for T is the only way:

```
T f0(T)(T x, T y) {
    import std.traits : isMutable;
    static if (isMutable!T) return x += y;
    else return x + y;
}
```

I know it's a bit painful though. In fact, Phobos also suffers from it. In std.numeric:

T gcd(T)(T a, T b)
if (isIntegral!T)
{
    static if (is(T == const) || is(T == immutable))
    {
        return gcd!(Unqual!T)(a, b);
    }
    // ...
}

Not only that looks ugly, but (with DMD) it makes gcd a doulbe function call :D

Reply via email to