digitalmars.D.learn - opCmp with and without const
- berni44 (34/34) Dec 05 2019 In std.typecons, in Tuple there are two opCmp functions, that are
- Paul Backus (13/17) Dec 05 2019 You can use a template this parameter [1] to have a new copy of
- Basile B. (4/39) Dec 06 2019 Usually `inout` is used. I'm pretty sure this is not possible
- Jonathan M Davis (15/49) Dec 06 2019 The issue is that there's no guarantee that the types being wrapped have...
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.)
Dec 05 2019
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
Dec 05 2019
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
Dec 06 2019
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
Dec 06 2019