Thread overview | ||||||
---|---|---|---|---|---|---|
|
December 06, 2019 opCmp with and without const | ||||
---|---|---|---|---|
| ||||
In std.typecons, in Tuple there are two opCmp functions, that are almost identical; they only differ by one being const and the other not: int opCmp(R)(R rhs) if (areCompatibleTuples!(typeof(this), R, "<")) { static foreach (i; 0 .. Types.length) { if (field[i] != rhs.field[i]) { return field[i] < rhs.field[i] ? -1 : 1; } } return 0; } int opCmp(R)(R rhs) const if (areCompatibleTuples!(typeof(this), R, "<")) { static foreach (i; 0 .. Types.length) { if (field[i] != rhs.field[i]) { return field[i] < rhs.field[i] ? -1 : 1; } } return 0; } What is the reason for having this? (I guess, that it's because the function may indirectly call opCmp of other types which may or may not be const.) My real question is: Can this code duplication be avoided somehow? (I ask, because I've got a PR running, which increases the size of these functions and it doesn't feel good to have two long, almost identical functions.) |
December 06, 2019 Re: opCmp with and without const | ||||
---|---|---|---|---|
| ||||
Posted in reply to berni44 | On Friday, 6 December 2019 at 07:03:45 UTC, berni44 wrote: > My real question is: Can this code duplication be avoided somehow? (I ask, because I've got a PR running, which increases the size of these functions and it doesn't feel good to have two long, almost identical functions.) You can use a template this parameter [1] to have a new copy of opCmp generated for each qualified version of Tuple it's called with: int opCmp(R, this This)(R rhs) const if (areCompatibleTuples!(typeof(this), R, "<")) { ... } This may lead to binary bloat, though, since you can potentially have separate instantiations for mutable, const, immutable, inout, shared, etc. [1] https://dlang.org/spec/template.html#template_this_parameter |
December 06, 2019 Re: opCmp with and without const | ||||
---|---|---|---|---|
| ||||
Posted in reply to berni44 | On Friday, 6 December 2019 at 07:03:45 UTC, berni44 wrote: > In std.typecons, in Tuple there are two opCmp functions, that are almost identical; they only differ by one being const and the other not: > > int opCmp(R)(R rhs) > if (areCompatibleTuples!(typeof(this), R, "<")) > { > static foreach (i; 0 .. Types.length) > { > if (field[i] != rhs.field[i]) > { > return field[i] < rhs.field[i] ? -1 : 1; > } > } > return 0; > } > > int opCmp(R)(R rhs) const > if (areCompatibleTuples!(typeof(this), R, "<")) > { > static foreach (i; 0 .. Types.length) > { > if (field[i] != rhs.field[i]) > { > return field[i] < rhs.field[i] ? -1 : 1; > } > } > return 0; > } > > > What is the reason for having this? (I guess, that it's because the function may indirectly call opCmp of other types which may or may not be const.) > > My real question is: Can this code duplication be avoided somehow? Usually `inout` is used. I'm pretty sure this is not possible here otherwise it would be done to avoid the dup. > (I ask, because I've got a PR running, which increases the size of these functions and it doesn't feel good to have two long, almost identical functions.) Well the content of body could be mixed in |
December 06, 2019 Re: opCmp with and without const | ||||
---|---|---|---|---|
| ||||
Posted in reply to berni44 | On Friday, December 6, 2019 12:03:45 AM MST berni44 via Digitalmars-d-learn wrote:
> In std.typecons, in Tuple there are two opCmp functions, that are almost identical; they only differ by one being const and the other not:
>
> int opCmp(R)(R rhs)
> if (areCompatibleTuples!(typeof(this), R, "<"))
> {
> static foreach (i; 0 .. Types.length)
> {
> if (field[i] != rhs.field[i])
> {
> return field[i] < rhs.field[i] ? -1 : 1;
> }
> }
> return 0;
> }
>
> int opCmp(R)(R rhs) const
> if (areCompatibleTuples!(typeof(this), R, "<"))
> {
> static foreach (i; 0 .. Types.length)
> {
> if (field[i] != rhs.field[i])
> {
> return field[i] < rhs.field[i] ? -1 : 1;
> }
> }
> return 0;
> }
>
>
> What is the reason for having this? (I guess, that it's because the function may indirectly call opCmp of other types which may or may not be const.)
>
> My real question is: Can this code duplication be avoided somehow? (I ask, because I've got a PR running, which increases the size of these functions and it doesn't feel good to have two long, almost identical functions.)
The issue is that there's no guarantee that the types being wrapped have a const opCmp. So, you can't just slap const or inout on Tuple's opCmp and have it work, but you do want it to be const if it can be const. So, two overloads are declared, and the template constraint takes care of checking whether that particular overload can be instantiated.
A mixin could be used for the function bodies to avoid duplicating the internals, and it may be possible to use template this parameters as Paul Backus suggested (I'm not very familiar with template this parameters, so I don't know how well they'll work in this particular case), but ultimately, one way or another, you need to have a non-const opCmp declared for when the wrapped types don't have an opCmp that works with const and a const or inout opCmp for when the wrapped types do have an opCmp that works with const.
- Jonathan M Davis
|
Copyright © 1999-2021 by the D Language Foundation