On Tuesday, 17 December 2013 at 18:06:27 UTC, Andrei Alexandrescu wrote:
That's problematic. "Between" is a preposition. Naming a function as a preposition is fine as long as a verb is implied (e.g. "a in b" really means "a _is_ in b", or "a.between(b, c)" really means "a _is_ between b and c" etc).

I see... interesting. But this doesn't suggest that the concept is bad, just the name.

"x in between(2, 7)" is cute but just that - it's a lucky strike that relies on word ordering in a particular phrase and is unlikely to work in many other places.

I agree it's cute and just lucky. I'm not attached to the name, but I'd like some sort of name that evokes the purpose like that does (as an example of something I wouldn't like reading, `x in iota(2, 7)` ...)

Reifying "between" to the status of object is weird. One constructs a "between" object and then what are its primitives? How can one even talk about it? "Yeah I have a between here and I copy it to another between"...

To be honest, I'm just the kind of person to come up with very weird ideas, so it's not surprising people might find my idea weird. It doesn't necessarily have to be called "between" but some sort of object (being able to contain the state is important) could contain the concept of a range of values ("inclusive lowerbound", "exclusive upperbound", support things like "opIn" or an opCall to test a value for membership). It'd also be needed for it to have a simple way to get the smallest acceptable type for the range of values the "between" object could represent. So a for a Between!(uint, int) that would be a uint, and a Between!(int, uint) that would be a long, and so on. Obviously some things _don't_ have acceptable types, such as a Between!(long, ulong) (no integral type currently can actually hold all of those values).

Something like this, like I showed, could be used to pass to other functions like std.random.uniform which request a range to generate. Or you should be able to pass it to something like std.algorithm.find, std.algorithm.count, etc (predicates that take one parameter).

On Tuesday, 17 December 2013 at 01:02:28 UTC, Chris Cain wrote:
but its main value would probably come improved readability and reduced code duplication

Actually, I thought about this a bit more and its value might be
greater than previously thought... what about the issues people
have with unsigned vs signed comparisons? (consider, someone in this very topic corrected your proposed code because of this very issue):

---
int a = -1;
uint b = 0;
assert(a < b); // oops, fails.
---

This isn't a new revelation or anything, and the solution, of
course, is to do more complex tests like `assert(a < 0 || a <
b);` but the compiler doing those sorts of things automatically
is questionable. Instead, covering the use-cases with
functions/objects like `between` where template magic can insert
these extra tests automatically might be a viable strategy.

And as another example of something falling prey to this "unexpected" behavior, look no further than the example I've already given: std.random.uniform ...

---
writeln(uniform(-1, 1u));
// std.random.uniform(): invalid bounding interval [-1, 1)
// Wat?
foreach(_; 0..5) {
    writeln(uniform(-2, uint.max));
    // Oops! Always prints out 4294967294
    // as if the bounding interval was [-2u, -1u)
}
---

https://d.puremagic.com/issues/show_bug.cgi?id=11758


These types of things are apparently very common issues. Having an object encapsulating the behavior needed to check this stuff and using it is preferable to reimplementing the checks each time (and potentially failing each time in subtle ways).

Reply via email to