between and among: worth Phobosization?

Chris Cain clcain at uncg.edu
Tue Dec 17 13:29:22 PST 2013


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).


More information about the Digitalmars-d mailing list