www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Generic comparison

reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
I want to implement a generic function for "a < f(x) < b" that 
will give the same result as "(a < f(x)) && (f(x) < b)" for any 
conceivable mix of types. Except if that "f(x)" should only be 
evaluated once.

Is it sufficient to use "scope ref" in parameters?

I don't want to assume _anything_ about the definition of the 
types and the implementation of the comparison operator (can be 
overloaded).
Nov 10 2020
parent reply Paul Backus <snarwin gmail.com> writes:
On Tuesday, 10 November 2020 at 16:55:11 UTC, Ola Fosheim Grøstad 
wrote:
 I want to implement a generic function for "a < f(x) < b" that 
 will give the same result as "(a < f(x)) && (f(x) < b)" for any 
 conceivable mix of types. Except if that "f(x)" should only be 
 evaluated once.

 Is it sufficient to use "scope ref" in parameters?

 I don't want to assume _anything_ about the definition of the 
 types and the implementation of the comparison operator (can be 
 overloaded).
bool between(Value, Bound)(auto ref Value value, auto ref Bound low, auto ref Bound high) { return (low < value) && (value < high); } You need `auto ref` because either Bound or Value may have copying disabled. Because the function is a template, attributes like `scope` will be inferred when applicable (modulo compiler bugs).
Nov 10 2020
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Tuesday, 10 November 2020 at 17:09:00 UTC, Paul Backus wrote:
 bool between(Value, Bound)(auto ref Value value, auto ref Bound 
 low, auto ref Bound high)
 {
     return (low < value) && (value < high);
 }

 You need `auto ref` because either Bound or Value may have 
 copying disabled. Because the function is a template, 
 attributes like `scope` will be inferred when applicable 
 (modulo compiler bugs).
Interesting, so "auto ref T" is the go-to type specifier for generic code then? I guess I also should conditionally add things like pure, nogc, nothrow... I assume I would have to test the comparison operator. I actually want to implement (low <= value) && (value < high) So I guess I need to test both. But how...? compiles-trait?
Nov 10 2020
parent reply Paul Backus <snarwin gmail.com> writes:
On Tuesday, 10 November 2020 at 17:19:09 UTC, Ola Fosheim Grøstad 
wrote:
 Interesting, so "auto ref T" is the go-to type specifier for 
 generic code then?  I guess I also should conditionally add 
 things like pure, nogc, nothrow... I assume I would have to 
 test the comparison operator. I actually want to implement
The compiler infers pure, nogc, nothrow etc. for template functions automatically. It's actually better if you don't add them by hand.
 (low <= value) && (value < high)

 So I guess I need to test both. But how...? compiles-trait?
You could add a template constraint, if you wanted. Something like: alias isOrderingComparableWith(T, U) = __traits(compiles, (T t, U u) => t < u); bool between(Value, Bound)(...) if (isOrderingComparaibleWith!(Value, Bound)) For a function this short, though, I don't think it's really necessary.
Nov 10 2020
next sibling parent Paul Backus <snarwin gmail.com> writes:
On Tuesday, 10 November 2020 at 20:32:40 UTC, Paul Backus wrote:
     alias isOrderingComparableWith(T, U) = __traits(compiles, 
 (T t, U u) => t < u);
My bad, should be `enum`, not `alias`.
Nov 10 2020
prev sibling parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Tuesday, 10 November 2020 at 20:32:40 UTC, Paul Backus wrote:
 The compiler infers pure,  nogc, nothrow etc. for template 
 functions automatically. It's actually better if you don't add 
 them by hand.
Ok, thanks :-).
Nov 10 2020