handful and interval

2012-09-02 Thread Andrei Alexandrescu
I'd like to add a simple function to std called "handful". It would 
return a small, read-only set of which main facility is membership test:


string a = "class";
if (a in handful("struct", "class", "union"))
{
...
}

Would it be generally useful, and if so what module does it belong to?

Same question about "interval", which is a fair amount more interesting 
if done right. An interval is a pair of values from a type that supports 
inequality comparison. It would have a variety of interval-specific 
operations, of which this would probably be quite popular:


int x;
...
if (x in interval(1, 2))
{
...
}


Destroy,

Andrei


Re: handful and interval

2012-09-02 Thread Alex Rønne Petersen

On 02-09-2012 16:22, Andrei Alexandrescu wrote:

I'd like to add a simple function to std called "handful". It would
return a small, read-only set of which main facility is membership test:

string a = "class";
if (a in handful("struct", "class", "union"))
{
 ...
}

Would it be generally useful, and if so what module does it belong to?


Yes! I have wanted this so many times in my code. I think std.algorithm 
is a reasonable place.


Though, maybe just call the function set(). It won't collide with 
anything else anyway (like a Set in std.container or whatever).


Also, please avoid backing it with an AA (I don't know if you wanted to 
do that, but just saying). While it would make the code significantly 
simpler, it means involving the GC, which is undesirable for such a 
simple utility function.


(I still think allowing 'in' on arrays would be a better approach, but 
this is better than nothing!)




Same question about "interval", which is a fair amount more interesting
if done right. An interval is a pair of values from a type that supports
inequality comparison. It would have a variety of interval-specific
operations, of which this would probably be quite popular:

int x;
...
if (x in interval(1, 2))
{
 ...
}


I don't deal much in this sort of code, but I can see it being useful 
(it's certainly prettier than writing the checks out manually). I don't 
really know what else I would expect from such a type, though.





Destroy,

Andrei


--
Alex Rønne Petersen
a...@lycus.org
http://lycus.org


Re: handful and interval

2012-09-02 Thread Andrei Alexandrescu

On 9/2/12 4:22 PM, Andrei Alexandrescu wrote:
[snip]

The alternative would be to simply define these as functions:

if (a.among("struct", "class", "union")) { ... }
if (b.between(1, 100)) { ... }


Andrei


Re: handful and interval

2012-09-02 Thread David Nadlinger
On Sunday, 2 September 2012 at 14:42:43 UTC, Alex Rønne Petersen 
wrote:

On 02-09-2012 16:22, Andrei Alexandrescu wrote:

int x;
...
if (x in interval(1, 2))
{
...
}


I don't deal much in this sort of code, but I can see it being 
useful (it's certainly prettier than writing the checks out 
manually). I don't really know what else I would expect from 
such a type, though.


Hm, maybe assert(interval(1, 3) & interval(2, 4) == interval(2, 
3)) and similar operations?


David


Re: handful and interval

2012-09-02 Thread Jacob Carlborg

On 2012-09-02 16:22, Andrei Alexandrescu wrote:

I'd like to add a simple function to std called "handful". It would
return a small, read-only set of which main facility is membership test:

string a = "class";
if (a in handful("struct", "class", "union"))
{
 ...
}

Would it be generally useful, and if so what module does it belong to?


I really don't like the name "handful". What would be the difference 
compared to a regular set container? To me it sounds like we should have 
a standard set container in Phobos, std.container.set.


--
/Jacob Carlborg


Re: handful and interval

2012-09-02 Thread Jacob Carlborg

On 2012-09-02 16:22, Andrei Alexandrescu wrote:


Same question about "interval", which is a fair amount more interesting
if done right. An interval is a pair of values from a type that supports
inequality comparison. It would have a variety of interval-specific
operations, of which this would probably be quite popular:

int x;
...
if (x in interval(1, 2))
{
 ...
}


Isn't this a bit like std.range.iota? Perhaps extending that returned 
value with opIn and other functionality.


--
/Jacob Carlborg


Re: handful and interval

2012-09-02 Thread Andrei Alexandrescu

On 9/2/12 4:50 PM, David Nadlinger wrote:

On Sunday, 2 September 2012 at 14:42:43 UTC, Alex Rønne Petersen wrote:

On 02-09-2012 16:22, Andrei Alexandrescu wrote:

int x;
...
if (x in interval(1, 2))
{
...
}


I don't deal much in this sort of code, but I can see it being useful
(it's certainly prettier than writing the checks out manually). I
don't really know what else I would expect from such a type, though.


Hm, maybe assert(interval(1, 3) & interval(2, 4) == interval(2, 3)) and
similar operations?


Thought about sugar for set operations using arithmetic operators, but 
decided against, because that would create a lot of confusion with 
http://en.wikipedia.org/wiki/Interval_arithmetic.


Andrei


Re: handful and interval

2012-09-02 Thread Tyro[17]

On 9/2/12 11:45 PM, Andrei Alexandrescu wrote:

On 9/2/12 4:22 PM, Andrei Alexandrescu wrote:
[snip]

The alternative would be to simply define these as functions:

if (a.among("struct", "class", "union")) { ... }
if (b.between(1, 100)) { ... }


Andrei


if (a in ["struct", "class", "union"]) { ... }
if (a in someArrayVar) { ... }

works wonders for me. Why not? Somehow I cannot see the disadvantages. 
Please educate.


Andrew


Re: handful and interval

2012-09-02 Thread Alex Rønne Petersen

On 02-09-2012 17:05, Tyro[17] wrote:

On 9/2/12 11:45 PM, Andrei Alexandrescu wrote:

On 9/2/12 4:22 PM, Andrei Alexandrescu wrote:
[snip]

The alternative would be to simply define these as functions:

if (a.among("struct", "class", "union")) { ... }
if (b.between(1, 100)) { ... }


Andrei


if (a in ["struct", "class", "union"]) { ... }
if (a in someArrayVar) { ... }

works wonders for me. Why not? Somehow I cannot see the disadvantages.
Please educate.

Andrew


The argument seems to be that since an array search is O(n) and an AA 
lookup is O(1), this example would be "misleading".


Not that I think this matters at all in practice.

--
Alex Rønne Petersen
a...@lycus.org
http://lycus.org


Re: handful and interval

2012-09-02 Thread deadalnix

Le 02/09/2012 16:51, Jacob Carlborg a écrit :

On 2012-09-02 16:22, Andrei Alexandrescu wrote:

I'd like to add a simple function to std called "handful". It would
return a small, read-only set of which main facility is membership test:

string a = "class";
if (a in handful("struct", "class", "union"))
{
...
}

Would it be generally useful, and if so what module does it belong to?


I really don't like the name "handful". What would be the difference
compared to a regular set container? To me it sounds like we should have
a standard set container in Phobos, std.container.set.



+1, and we are back to the allocator design.


Re: handful and interval

2012-09-02 Thread Andrei Alexandrescu

On 9/2/12 5:05 PM, Tyro[17] wrote:

On 9/2/12 11:45 PM, Andrei Alexandrescu wrote:

On 9/2/12 4:22 PM, Andrei Alexandrescu wrote:
[snip]

The alternative would be to simply define these as functions:

if (a.among("struct", "class", "union")) { ... }
if (b.between(1, 100)) { ... }


Andrei


if (a in ["struct", "class", "union"]) { ... }
if (a in someArrayVar) { ... }

works wonders for me. Why not? Somehow I cannot see the disadvantages.
Please educate.

Andrew


The first could be make to work, the second I am against on a big-oh 
complexity basis. The problem with making the first work is inconsistency.


Andrei


Re: handful and interval

2012-09-02 Thread Andrei Alexandrescu

On 9/2/12 4:56 PM, Jacob Carlborg wrote:

On 2012-09-02 16:22, Andrei Alexandrescu wrote:


Same question about "interval", which is a fair amount more interesting
if done right. An interval is a pair of values from a type that supports
inequality comparison. It would have a variety of interval-specific
operations, of which this would probably be quite popular:

int x;
...
if (x in interval(1, 2))
{
...
}


Isn't this a bit like std.range.iota? Perhaps extending that returned
value with opIn and other functionality.


Iota is a different notion (it has a step).

Andrei



Re: handful and interval

2012-09-02 Thread Andrei Alexandrescu

On 9/2/12 4:51 PM, Jacob Carlborg wrote:

On 2012-09-02 16:22, Andrei Alexandrescu wrote:

I'd like to add a simple function to std called "handful". It would
return a small, read-only set of which main facility is membership test:

string a = "class";
if (a in handful("struct", "class", "union"))
{
...
}

Would it be generally useful, and if so what module does it belong to?


I really don't like the name "handful". What would be the difference
compared to a regular set container? To me it sounds like we should have
a standard set container in Phobos, std.container.set.


The difference is in scale and primitives offered. Handful would be 
read-only and limited to the size of its initializer. Its representation 
would take advantage of that.


Anyhow, I think among would be a simpler solution for this all.


Andrei




Re: handful and interval

2012-09-02 Thread Dmitry Olshansky

On 02-Sep-12 18:22, Andrei Alexandrescu wrote:
> I'd like to add a simple function to std called "handful". It would
> return a small, read-only set of which main facility is membership test:
>
> string a = "class";
> if (a in handful("struct", "class", "union"))
> {
>  ...
> }
>
> Would it be generally useful, and if so what module does it belong to?
>
>
I wouldn't question utility but rather the implementation of the above.
One thing I'd love to see is thing like
handful!("struct", "class", "union")

that does pre-process contents at compile time to speed up search.
In other words it's possible to not only come close to  a series of a == 
"struct" || a == "class" || a == "union" but surpass it.


At the very least handful!(a,b,c) can take expression tuple and make
x in handful!(a,b,c) lower to:
return x == a || x == b || x == c;

even for run-time variables a, b & c.

--
Olshansky Dmitry


Re: handful and interval

2012-09-02 Thread Jakob Ovrum
On Sunday, 2 September 2012 at 14:49:34 UTC, Andrei Alexandrescu 
wrote:

On 9/2/12 4:22 PM, Andrei Alexandrescu wrote:
[snip]

The alternative would be to simply define these as functions:

if (a.among("struct", "class", "union")) { ... }
if (b.between(1, 100)) { ... }


Andrei


I prefer this.

There doesn't seem to be a clear vision for the 'in' operator. 
Let's not make the situation more complicated before we've 
figured that out. How do we know which uses of 'in' are abuse, 
and which are merely exploiting intuition justifiably?




Re: handful and interval

2012-09-02 Thread Andrei Alexandrescu

On 9/2/12 6:22 PM, Jakob Ovrum wrote:

On Sunday, 2 September 2012 at 14:49:34 UTC, Andrei Alexandrescu wrote:

On 9/2/12 4:22 PM, Andrei Alexandrescu wrote:
[snip]

The alternative would be to simply define these as functions:

if (a.among("struct", "class", "union")) { ... }
if (b.between(1, 100)) { ... }


Andrei


I prefer this.


Me too, upon some more thought. (Interval could become a legit numeric 
library, but that's a separate idea.)



There doesn't seem to be a clear vision for the 'in' operator. Let's not
make the situation more complicated before we've figured that out. How
do we know which uses of 'in' are abuse, and which are merely exploiting
intuition justifiably?


Yah, agreed.


Andrei


Re: handful and interval

2012-09-02 Thread Andrei Alexandrescu

On 9/2/12 6:44 PM, Andrei Alexandrescu wrote:
[snip]

The remaining question is where to put among and between. std.functional?

Andrei


Re: handful and interval

2012-09-02 Thread bearophile

Andrei Alexandrescu:

I remember naming the first thing bunch().


if (x in interval(1, 2))
{
...
}


Is interval() for time intervals too? :-)

Bye,
bearophile


Re: handful and interval

2012-09-02 Thread Timon Gehr

On 09/02/2012 06:45 PM, Andrei Alexandrescu wrote:

On 9/2/12 6:44 PM, Andrei Alexandrescu wrote:
[snip]

The remaining question is where to put among and between. std.functional?

Andrei


They are not combinators. std.algorithm.


Re: handful and interval

2012-09-02 Thread Philippe Sigaud
On Sun, Sep 2, 2012 at 5:29 PM, Dmitry Olshansky  wrote:

> I wouldn't question utility but rather the implementation of the above.
> One thing I'd love to see is thing like
> handful!("struct", "class", "union")
>
> that does pre-process contents at compile time to speed up search.
> In other words it's possible to not only come close to  a series of a ==
> "struct" || a == "class" || a == "union" but surpass it.

Dmitry, don't you have a trie implementation since your GSOC project?

In any case, I'd gladly welcome such a function. I just spent hours
trying to find an quick way to search for a string among a handful
(set, group, whatever) of strings known at CT, that works at
compile-time and is swift at runtime. Having that in Phobos would be
very nice.
For strings, some ordering and prefix factorisation can probably work,
but what Andrei proposes is more general I presume?


Re: handful and interval

2012-09-02 Thread Walter Bright

On 9/2/2012 7:45 AM, Andrei Alexandrescu wrote:

On 9/2/12 4:22 PM, Andrei Alexandrescu wrote:
[snip]

The alternative would be to simply define these as functions:

if (a.among("struct", "class", "union")) { ... }
if (b.between(1, 100)) { ... }


Is between inclusive or not of the endpoints?


Re: handful and interval

2012-09-02 Thread SomeDude

On Sunday, 2 September 2012 at 15:09:50 UTC, deadalnix wrote:

Le 02/09/2012 16:51, Jacob Carlborg a écrit :
I really don't like the name "handful". What would be the 
difference
compared to a regular set container? To me it sounds like we 
should have

a standard set container in Phobos, std.container.set.



+1, and we are back to the allocator design.


+2 on the basis of typical "real world" (if I may says so) usage. 
It calls for a set container, both mutable and immutable.


For a "handful" of values (say 5 or less), I'm not even sure the 
O(1) method is faster than the O(n) one.


As for the intervals, I suppose one would have to define open 
intervals, because I think they would be much more useful than 
closed ones when the intervals are contiguous (in particular with 
floats/doubles).
One must be able to translate x0 <= x < x1 in intervals else they 
are practically useless for anything else than integers and other 
discrete values.


Re: handful and interval

2012-09-02 Thread SomeDude
On Sunday, 2 September 2012 at 16:44:40 UTC, Andrei Alexandrescu 
wrote:

On 9/2/12 6:44 PM, Andrei Alexandrescu wrote:
[snip]

The remaining question is where to put among and between. 
std.functional?


Andrei


Without second thought, I'd say std.container.set for the first, 
std.functional for the second (not too sure about it).




Re: handful and interval

2012-09-02 Thread Mehrdad

string a = "class";
if (a in tuple("struct", "class", "union"))
{
...
}


Re: handful and interval

2012-09-02 Thread Simen Kjaeraas
On Sun, 02 Sep 2012 22:24:17 +0200, Walter Bright  
 wrote:



On 9/2/2012 7:45 AM, Andrei Alexandrescu wrote:

On 9/2/12 4:22 PM, Andrei Alexandrescu wrote:
[snip]

The alternative would be to simply define these as functions:

if (a.among("struct", "class", "union")) { ... }
if (b.between(1, 100)) { ... }


Is between inclusive or not of the endpoints?


struct Between(string boundaries = "[]", T) {
...
}

?

--
Simen


Re: handful and interval

2012-09-02 Thread Jonathan M Davis
On Sunday, September 02, 2012 16:22:20 Andrei Alexandrescu wrote:
> I'd like to add a simple function to std called "handful". It would
> return a small, read-only set of which main facility is membership test:
> 
> string a = "class";
> if (a in handful("struct", "class", "union"))
> {
>  ...
> }
> 
> Would it be generally useful, and if so what module does it belong to?

How is this different from

if(canFind(["struct", "class", "union"], a) {...}

Is it because it can be made more efficient? From a usage standpoint, they're 
essentially the same.

> Same question about "interval", which is a fair amount more interesting
> if done right. An interval is a pair of values from a type that supports
> inequality comparison. It would have a variety of interval-specific
> operations, of which this would probably be quite popular:
> 
> int x;
> ...
> if (x in interval(1, 2))
> {
>  ...
> }

I take it that that's a closed interval (opened vs closed would potentially 
complicate this a bit)? If so, then that's the same as

if(x >= 1 && x <= 2) {...}

right? That's kind of nice and kind of pointless. It's slightly less verbose, 
but unless the optimizer does a lot better than it's probably going to do, 
you're gonig to take a performance hit. The only real advantage there that I 
see is that it's a bit more idomatic.

Though, on thinking about it, it _would_ have the advantage of allowing you to 
pass around an interval, which doesn't work anywhere near as well with 
separate values. And if the interval is doing a lot more than in, then that 
could make it valuable as well.

But the example doesn't really do much to show interval's value IMHO.

- Jonathan M Davis


Re: handful and interval

2012-09-02 Thread Jonathan M Davis
On Sunday, September 02, 2012 19:12:30 bearophile wrote:
> Is interval() for time intervals too? :-)

We already have those:

std.dateteme.Interval
std.datetime.PosInfInterval
std.datetime.NegInfInterval

But if all interval needs to work is the comparison operators, then it would 
work with the various time point types in std.datetime.

- Jonathan M Davis


Re: handful and interval

2012-09-02 Thread Andrei Alexandrescu

On 9/2/12 7:31 PM, Timon Gehr wrote:

On 09/02/2012 06:45 PM, Andrei Alexandrescu wrote:

On 9/2/12 6:44 PM, Andrei Alexandrescu wrote:
[snip]

The remaining question is where to put among and between. std.functional?

Andrei


They are not combinators. std.algorithm.


I'd argue they aren't quite algorithms either...

Andrei


Re: handful and interval

2012-09-02 Thread Andrei Alexandrescu

On 9/2/12 10:24 PM, Walter Bright wrote:

On 9/2/2012 7:45 AM, Andrei Alexandrescu wrote:

On 9/2/12 4:22 PM, Andrei Alexandrescu wrote:
[snip]

The alternative would be to simply define these as functions:

if (a.among("struct", "class", "union")) { ... }
if (b.between(1, 100)) { ... }


Is between inclusive or not of the endpoints?


After quite a bit of thought, I think inclusive is the right way. There 
are two reasons:


1. Ranges that end in e.g. float.max or int.max would not be expressible 
if bounds were not included.


2. SQL defines between to include the limits, which sets a precedent.

Ranges are open to the right but I think intervals are quite different.


Andrei


Re: handful and interval

2012-09-02 Thread Jonathan M Davis
On Monday, September 03, 2012 01:37:19 Andrei Alexandrescu wrote:
> On 9/2/12 7:31 PM, Timon Gehr wrote:
> > On 09/02/2012 06:45 PM, Andrei Alexandrescu wrote:
> >> On 9/2/12 6:44 PM, Andrei Alexandrescu wrote:
> >> [snip]
> >> 
> >> The remaining question is where to put among and between. std.functional?
> >> 
> >> Andrei
> > 
> > They are not combinators. std.algorithm.
> 
> I'd argue they aren't quite algorithms either...

Well, from the looks of it, handful (or among or whatever you want to call it) 
is basically a functor for canFind (just with in instead of parens). So, it's 
an algorithm that's been thrown into a struct rather than kept as a separate 
function - kind of like map or other lazy, range-based functions except that 
it's using in instead of the range API. So, I think that it fits in 
std.algorithm reasonably well, but it _is_ also a bit of an odd fit. I think 
that the problem is that you're essentially introducing a new idiom, and it 
doesn't quite fit anywhere in what we have.

- Jonathan M Davis


Re: handful and interval

2012-09-02 Thread Walter Bright

On 9/2/2012 4:40 PM, Andrei Alexandrescu wrote:

On 9/2/12 10:24 PM, Walter Bright wrote:

On 9/2/2012 7:45 AM, Andrei Alexandrescu wrote:

On 9/2/12 4:22 PM, Andrei Alexandrescu wrote:
[snip]

The alternative would be to simply define these as functions:

if (a.among("struct", "class", "union")) { ... }
if (b.between(1, 100)) { ... }


Is between inclusive or not of the endpoints?


After quite a bit of thought, I think inclusive is the right way.


Then there's no way to specify an empty interval. I suppose with "between" that 
would not be relevant.



There are two
reasons:

1. Ranges that end in e.g. float.max or int.max would not be expressible if
bounds were not included.

2. SQL defines between to include the limits, which sets a precedent.

Ranges are open to the right but I think intervals are quite different.


Andrei





Re: handful and interval

2012-09-02 Thread Jonathan M Davis
On Sunday, September 02, 2012 21:47:13 Walter Bright wrote:
> On 9/2/2012 4:40 PM, Andrei Alexandrescu wrote:
> > On 9/2/12 10:24 PM, Walter Bright wrote:
> >> On 9/2/2012 7:45 AM, Andrei Alexandrescu wrote:
> >>> On 9/2/12 4:22 PM, Andrei Alexandrescu wrote:
> >>> [snip]
> >>> 
> >>> The alternative would be to simply define these as functions:
> >>> 
> >>> if (a.among("struct", "class", "union")) { ... }
> >>> if (b.between(1, 100)) { ... }
> >> 
> >> Is between inclusive or not of the endpoints?
> > 
> > After quite a bit of thought, I think inclusive is the right way.
> 
> Then there's no way to specify an empty interval. I suppose with "between"
> that would not be relevant.

It could take a std.aglorithm.openRight as its third, parameter, then you 
could choose to do one or the other. It just becomes a question of which is 
the default.

Certainly, my natural inclination is to go with having intervals be open on 
the right, but if you have a choice, it's less of an issue regardless of which 
is the default.

- Jonathan M Davis


Re: handful and interval

2012-09-02 Thread Sven Torvinger
On Monday, 3 September 2012 at 04:56:54 UTC, Jonathan M Davis 
wrote:


It could take a std.aglorithm.openRight as its third, 
parameter, then you
could choose to do one or the other. It just becomes a question 
of which is

the default.

Certainly, my natural inclination is to go with having 
intervals be open on
the right, but if you have a choice, it's less of an issue 
regardless of which

is the default.

- Jonathan M Davis


http://www.boost.org/doc/libs/1_51_0/libs/icl/doc/html/index.html

Recently at work, I was quite pleasantly surprised by the boost 
solution... it solves a number of problems quite elegantly, 
different policies for handling overlapping ranges and etc... and 
found myself wishing for the same in D.


ex.

typedef std::set guests;
interval_map party;
party += make_pair(interval::right_open(time("20:00"), 
time("22:00")), guests("Mary"));
party += make_pair(interval::right_open(time("21:00"), 
time("23:00")), guests("Harry"));


// party now contains
[20:00, 21:00)->{"Mary"}
[21:00, 22:00)->{"Harry","Mary"} //guest sets aggregated on 
overlap

[22:00, 23:00)->{"Harry"}


Re: handful and interval

2012-09-02 Thread Jacob Carlborg

On 2012-09-02 17:06, Alex Rønne Petersen wrote:


The argument seems to be that since an array search is O(n) and an AA
lookup is O(1), this example would be "misleading".


What would it be for this set type?

--
/Jacob Carlborg


Re: handful and interval

2012-09-02 Thread Jacob Carlborg

On 2012-09-02 17:29, Dmitry Olshansky wrote:


I wouldn't question utility but rather the implementation of the above.
One thing I'd love to see is thing like
handful!("struct", "class", "union")

that does pre-process contents at compile time to speed up search.
In other words it's possible to not only come close to  a series of a ==
"struct" || a == "class" || a == "union" but surpass it.


Sounds like an enhanced tuple?


At the very least handful!(a,b,c) can take expression tuple and make
x in handful!(a,b,c) lower to:
return x == a || x == b || x == c;

even for run-time variables a, b & c.




--
/Jacob Carlborg


Re: handful and interval

2012-09-02 Thread Andrei Alexandrescu

On 9/3/12 6:47 AM, Walter Bright wrote:

On 9/2/2012 4:40 PM, Andrei Alexandrescu wrote:

On 9/2/12 10:24 PM, Walter Bright wrote:

On 9/2/2012 7:45 AM, Andrei Alexandrescu wrote:

On 9/2/12 4:22 PM, Andrei Alexandrescu wrote:
[snip]

The alternative would be to simply define these as functions:

if (a.among("struct", "class", "union")) { ... }
if (b.between(1, 100)) { ... }


Is between inclusive or not of the endpoints?


After quite a bit of thought, I think inclusive is the right way.


Then there's no way to specify an empty interval. I suppose with
"between" that would not be relevant.


Apparently I didn't think enough :o).

Andrei



Re: handful and interval

2012-09-02 Thread Jacob Carlborg

On 2012-09-02 17:16, Andrei Alexandrescu wrote:


Iota is a different notion (it has a step).


Yes, but that is optional, making "iota" a more general form of an interval.

--
/Jacob Carlborg


Re: handful and interval

2012-09-02 Thread Jacob Carlborg

On 2012-09-02 17:17, Andrei Alexandrescu wrote:


The difference is in scale and primitives offered. Handful would be
read-only and limited to the size of its initializer. Its representation
would take advantage of that.

Anyhow, I think among would be a simpler solution for this all.


This doesn't sound like an approach you would take Andrei :) I would 
expect you to say something like:


"This isn't general enough, we need a general set container that is fast 
and efficient enough for this uses cases as well".


--
/Jacob Carlborg


Re: handful and interval

2012-09-02 Thread Andrei Alexandrescu

On 9/3/12 8:29 AM, Jacob Carlborg wrote:

On 2012-09-02 17:16, Andrei Alexandrescu wrote:


Iota is a different notion (it has a step).


Yes, but that is optional, making "iota" a more general form of an
interval.


I think in this case the generalization goes the wrong way.

Andrei



Re: handful and interval

2012-09-02 Thread Andrei Alexandrescu

On 9/3/12 8:28 AM, Jacob Carlborg wrote:

On 2012-09-02 17:29, Dmitry Olshansky wrote:


I wouldn't question utility but rather the implementation of the above.
One thing I'd love to see is thing like
handful!("struct", "class", "union")

that does pre-process contents at compile time to speed up search.
In other words it's possible to not only come close to a series of a ==
"struct" || a == "class" || a == "union" but surpass it.


Sounds like an enhanced tuple?


Tuple is the representation of an interval but that's where commonality 
stops.


Andrei




Re: handful and interval

2012-09-02 Thread Andrei Alexandrescu

On 9/3/12 8:31 AM, Andrei Alexandrescu wrote:

On 9/3/12 8:28 AM, Jacob Carlborg wrote:

On 2012-09-02 17:29, Dmitry Olshansky wrote:


I wouldn't question utility but rather the implementation of the above.
One thing I'd love to see is thing like
handful!("struct", "class", "union")

that does pre-process contents at compile time to speed up search.
In other words it's possible to not only come close to a series of a ==
"struct" || a == "class" || a == "union" but surpass it.


Sounds like an enhanced tuple?


Tuple is the representation of an interval but that's where commonality
stops.


Rats, sorry (no coffee yet). It was about "handful" and I was at 
"interval". I can see how an inclusion for tuple would make sense, even 
in the current notion - i.e. we could add "in" to Tuple and get to write:


if (x in tuple("struct", "class", "union")) { ... }


Andrei




Re: handful and interval

2012-09-02 Thread Simen Kjaeraas

On Mon, 03 Sep 2012 08:29:34 +0200, Jacob Carlborg  wrote:


On 2012-09-02 17:16, Andrei Alexandrescu wrote:


Iota is a different notion (it has a step).


Yes, but that is optional, making "iota" a more general form of an  
interval.


It's not optional, it has a default value.

--
Simen


Re: handful and interval

2012-09-02 Thread Simen Kjaeraas
On Mon, 03 Sep 2012 08:34:33 +0200, Andrei Alexandrescu  
 wrote:



we could add "in" to Tuple and get to write:

if (x in tuple("struct", "class", "union")) { ... }


if (x in tuple(1, new Foo(), "baa!") { ... }

Just kidding.


tuple has the inconvenience that we don't know the values at compile-time.
If we did, we could take advantage of some cleverer tricks for fast
comparison. At the same time, it's a neat and logical solution.


--
Simen


Re: handful and interval

2012-09-03 Thread Don Clugston

On 02/09/12 22:42, SomeDude wrote:

On Sunday, 2 September 2012 at 15:09:50 UTC, deadalnix wrote:

Le 02/09/2012 16:51, Jacob Carlborg a écrit :

I really don't like the name "handful". What would be the difference
compared to a regular set container? To me it sounds like we should have
a standard set container in Phobos, std.container.set.



+1, and we are back to the allocator design.


+2 on the basis of typical "real world" (if I may says so) usage. It
calls for a set container, both mutable and immutable.

For a "handful" of values (say 5 or less), I'm not even sure the O(1)
method is faster than the O(n) one.

As for the intervals, I suppose one would have to define open intervals,
because I think they would be much more useful than closed ones when the
intervals are contiguous (in particular with floats/doubles).
One must be able to translate x0 <= x < x1 in intervals else they are
practically useless for anything else than integers and other discrete
values.


But practically everything on a computer uses discrete values. Floating 
point numbers always do, for example; they are *not* mathematical real 
numbers with infinite precision.
For floats and doubles, any non-empty interval can be expressed using 
closed intervals.


Use the nextUp() and nextDown() to convert between open and closed 
intervals.


[ x .. y ] == ( nextDown(x) .. nextUp(y) )
( x .. y ) == [ nextUp(x) .. nextDown(y) ]


In general:

Fully closed interval: cannot express an empty interval.
Fully open interval: cannot express a maximum-sized interval. Empty 
intervals can be expressed but not uniquely.

Half-open: not closed under negation.

Either of the first two are reasonable choices for arithmetic 
applications. The third is broken for anything that allows negative values.




Re: handful and interval

2012-09-03 Thread Philippe Sigaud
Le 3 sept. 2012 08:42, "Simen Kjaeraas"  a écrit :
>
> On Mon, 03 Sep 2012 08:34:33 +0200, Andrei Alexandrescu <
seewebsiteforem...@erdani.org> wrote:
>
>> we could add "in" to Tuple and get to write:
>>
>> if (x in tuple("struct", "class", "union")) { ... }
>
>
> if (x in tuple(1, new Foo(), "baa!") { ... }
>
> Just kidding.

I was about to say the same, except not kidding :)
I can see value in having this: finding if a value in a struct '.tupleof',
for example. Or finding a range among a tuple of ranges, all of subtly
different types and that cannot be put in an array.
I was imagining 'in' to return a boolean, but if you need it to return a
possible value, then it can return a pointer to CommonType!(Ts) if this
exists, or a pointer to Algebraic!(Types...).

Of course, that would also be a interesting place to use an Option!(T) type.

> tuple has the inconvenience that we don't know the values at compile-time.
> If we did, we could take advantage of some cleverer tricks for fast
> comparison. At the same time, it's a neat and logical solution.

We can try to get a fully-CT version, using template arguments, but I'm not
sure that would be interesting.

People here are talking about sets, but does Andrei really have sets in
mind? That has consequences if you want 'in' to return a pointer to a value.


Re: handful and interval

2012-09-03 Thread Andrei Alexandrescu

On 9/3/12 10:27 AM, Philippe Sigaud wrote:

People here are talking about sets, but does Andrei really have sets in
mind? That has consequences if you want 'in' to return a pointer to a value.


I wanted to define a couple of simple convenience functions. It seems 
we've headed into a paralysis of analysis.


Andrei


Re: handful and interval

2012-09-03 Thread Sven Torvinger
On Monday, 3 September 2012 at 09:01:37 UTC, Andrei Alexandrescu 
wrote:

On 9/3/12 10:27 AM, Philippe Sigaud wrote:
People here are talking about sets, but does Andrei really 
have sets in
mind? That has consequences if you want 'in' to return a 
pointer to a value.


I wanted to define a couple of simple convenience functions. It 
seems we've headed into a paralysis of analysis.


Andrei


I would advocate using, a < x < b, this trivially addresses 
open/closed intervals etc.


I disagree with the porting from other languages argument... 
comparing bool with < > is not a common occurring pattern, and 
even if there is such code in the wild, many coding standards 
would force the use of () if using such an expression anyway... 
so the porting issues would be minimal.





Re: handful and interval

2012-09-03 Thread Andrei Alexandrescu

On 9/3/12 11:37 AM, Sven Torvinger wrote:

On Monday, 3 September 2012 at 09:01:37 UTC, Andrei Alexandrescu wrote:

On 9/3/12 10:27 AM, Philippe Sigaud wrote:

People here are talking about sets, but does Andrei really have sets in
mind? That has consequences if you want 'in' to return a pointer to a
value.


I wanted to define a couple of simple convenience functions. It seems
we've headed into a paralysis of analysis.

Andrei


I would advocate using, a < x < b, this trivially addresses open/closed
intervals etc.

I disagree with the porting from other languages argument... comparing
bool with < > is not a common occurring pattern, and even if there is
such code in the wild, many coding standards would force the use of ()
if using such an expression anyway... so the porting issues would be
minimal.


It's a sensible argument. What about "among"?

Andrei


Re: handful and interval

2012-09-03 Thread Sven Torvinger
On Monday, 3 September 2012 at 10:42:34 UTC, Andrei Alexandrescu 
wrote:
I would advocate using, a < x < b, this trivially addresses 
open/closed

intervals etc.

I disagree with the porting from other languages argument... 
comparing
bool with < > is not a common occurring pattern, and even if 
there is
such code in the wild, many coding standards would force the 
use of ()
if using such an expression anyway... so the porting issues 
would be

minimal.


It's a sensible argument. What about "among"?

Andrei


Since 'among' only is concerned with equality it doesn't suffer 
from the open/closed interval complication... thus in this case, 
the simplest solution is the best imho... 'in' sugar would not 
add much to the readability.


if (a.among("struct", "class", "union")) { ... }



Re: handful and interval

2012-09-03 Thread David Nadlinger

On Monday, 3 September 2012 at 11:20:27 UTC, Sven Torvinger wrote:

if (a.among("struct", "class", "union")) { ... }


Wouldn't that rather be a.among!("struct", "class", "union")? If 
the string is not known at compile-time, I'd prefer to focus on 
optimizing something along the lines of ["struct", "class", 
"union"].canFind(a) (something similar is actually a quite common 
idiom in Ruby).


David


Re: handful and interval

2012-09-03 Thread Andrei Alexandrescu

On 9/3/12 1:24 PM, David Nadlinger wrote:

On Monday, 3 September 2012 at 11:20:27 UTC, Sven Torvinger wrote:

if (a.among("struct", "class", "union")) { ... }


Wouldn't that rather be a.among!("struct", "class", "union")?


I'd rather have a regular function (more generally applicable) that the 
inliner takes care of.


Andrei



Re: handful and interval

2012-09-03 Thread David Nadlinger
On Monday, 3 September 2012 at 12:58:05 UTC, Andrei Alexandrescu 
wrote:

On 9/3/12 1:24 PM, David Nadlinger wrote:
On Monday, 3 September 2012 at 11:20:27 UTC, Sven Torvinger 
wrote:

if (a.among("struct", "class", "union")) { ... }


Wouldn't that rather be a.among!("struct", "class", "union")?


I'd rather have a regular function (more generally applicable) 
that the inliner takes care of.


Where would the real difference to ["struct", "class", 
"union"].canFind(a) then? A sufficiently smart compiler (tm) 
could optimize this to a efficient string "prefix switch 
statement" just as well…


David


Re: handful and interval

2012-09-03 Thread Andrei Alexandrescu

On 9/3/12 3:53 PM, David Nadlinger wrote:

On Monday, 3 September 2012 at 12:58:05 UTC, Andrei Alexandrescu wrote:

On 9/3/12 1:24 PM, David Nadlinger wrote:

On Monday, 3 September 2012 at 11:20:27 UTC, Sven Torvinger wrote:

if (a.among("struct", "class", "union")) { ... }


Wouldn't that rather be a.among!("struct", "class", "union")?


I'd rather have a regular function (more generally applicable) that
the inliner takes care of.


Where would the real difference to ["struct", "class",
"union"].canFind(a) then?


Convenience. I find the other easier to write and read.


A sufficiently smart compiler (tm) could
optimize this to a efficient string "prefix switch statement" just as well…


I agree. But then http://c2.com/cgi/wiki?SufficientlySmartCompiler.


Andrei




Re: handful and interval

2012-09-03 Thread Timon Gehr

On 09/03/2012 01:37 AM, Andrei Alexandrescu wrote:

On 9/2/12 7:31 PM, Timon Gehr wrote:

On 09/02/2012 06:45 PM, Andrei Alexandrescu wrote:

On 9/2/12 6:44 PM, Andrei Alexandrescu wrote:
[snip]

The remaining question is where to put among and between.
std.functional?

Andrei


They are not combinators. std.algorithm.


I'd argue they aren't quite algorithms either...

Andrei


Interesting. What is the Phobos definition of algorithm?


Re: handful and interval

2012-09-03 Thread bearophile

David Nadlinger:

Where would the real difference to ["struct", "class", 
"union"].canFind(a) then? A sufficiently smart compiler (tm) 
could optimize this to a efficient string "prefix switch 
statement" just as well…


I think a smart compiler is not needed.

Maybe a general solution is to introduce a way to define 
overloaded templates callable as functions, that get called if 
the input is a literal (or statically known, but D design 
requires you to asks explicitly for a CT evaluation):


void foo(static int[] a) {}
void foo(int[] a) {}
void main(string[] args) {
foo([1, 2]); // calls first foo
int[] a = [1, 2] ~ args.length;
foo(a); // calls second foo
}


Bye,
bearophile


Re: handful and interval

2012-09-03 Thread ixid

if (a in handful("struct", "class", "union"))

How is this different from

if(canFind(["struct", "class", "union"], a) {...}


It's a lot cleaner without the mess of brackets. You missed a ) 
on the second one, which, without intending snarkiness, perhaps 
demonstrates the greater elegance of the former? Though being 
able to use in on a simple array would be very nice.


if(a in ["struct", "class", "union"])

Wouldn't you expect to search an array at O(n) while an 
associative array would be O(1), making the difference not 
unintuitive?


Re: handful and interval

2012-09-03 Thread David Piepgrass
However I'd use different names: among=>isOneOf, 
between=>isInRange.
I forgot to state the reason, namely, I think boolean functions 
should be named so that you can tell they return bool, as 
"between" could easily be a function that places a value into a 
range rather than tests whether it is in range.


Re: handful and interval

2012-09-03 Thread David Piepgrass

if (a.among("struct", "class", "union")) { ... }
if (b.between(1, 100)) { ... }


Is between inclusive or not of the endpoints?


After quite a bit of thought, I think inclusive is the right 
way.


Then there's no way to specify an empty interval. I suppose 
with "between" that would not be relevant.


Perhaps b.between(1, 0) would always return false.

However I'd use different names: among=>isOneOf, 
between=>isInRange. I would also define another function inRange 
that ensures, rather than tests, that a value is in range:


string userInput = "-7";
int cleanInput = inRange(parse!int(userInput), 1, 100);


Re: handful and interval

2012-09-03 Thread David Nadlinger

On Monday, 3 September 2012 at 15:10:46 UTC, ixid wrote:

if (a in handful("struct", "class", "union"))

How is this different from

if(canFind(["struct", "class", "union"], a) {...}


It's a lot cleaner without the mess of brackets.


I find the difference between »a in handful("struct", "class", 
"union")« and »["struct", "class", "union"].canFind(a)« to be 
largely a matter of taste – to me, the former introduces too 
much of a special case just to for a slightly nicer-looking 
syntax, whereas the other doesn't look bad either and reuses 
existing constructs.


David


Re: handful and interval

2012-09-03 Thread David Nadlinger
On Monday, 3 September 2012 at 14:04:18 UTC, Andrei Alexandrescu 
wrote:

A sufficiently smart compiler (tm) could
optimize this to a efficient string "prefix switch statement" 
just as well…


I agree. But then 
http://c2.com/cgi/wiki?SufficientlySmartCompiler.


This is exactly my point: My feeling is that the increased 
complexity by introducing a second syntax resp. a new special 
case (i.e. among) for such a simple operation is only worth it if 
it leaves no reason to revert to a hand-written replacement for 
performance reason, and I'm not sure if the signature taking 
runtime parameters is enough for that (without assuming such a 
sufficiently smart compiler).


David


Re: handful and interval

2012-09-03 Thread Jonathan M Davis
On Monday, September 03, 2012 19:52:26 David Nadlinger wrote:
> On Monday, 3 September 2012 at 15:10:46 UTC, ixid wrote:
> >>if (a in handful("struct", "class", "union"))
> >>
> >>How is this different from
> >>
> >>if(canFind(["struct", "class", "union"], a) {...}
> >>
> > It's a lot cleaner without the mess of brackets.
> 
> I find the difference between »a in handful("struct", "class",
> "union")« and »["struct", "class", "union"].canFind(a)« to be
> largely a matter of taste – to me, the former introduces too
> much of a special case just to for a slightly nicer-looking
> syntax, whereas the other doesn't look bad either and reuses
> existing constructs.

I agree. If it's purely a matter of aesthetics, then I see no reason to add 
anything like handful. There needs to be a practical reason for it.

- Jonathan M Davis


Re: handful and interval

2012-09-03 Thread Timon Gehr

On 09/03/2012 08:01 PM, David Nadlinger wrote:

On Monday, 3 September 2012 at 14:04:18 UTC, Andrei Alexandrescu wrote:

A sufficiently smart compiler (tm) could
optimize this to a efficient string "prefix switch statement" just as
well…


I agree. But then http://c2.com/cgi/wiki?SufficientlySmartCompiler.


This is exactly my point: My feeling is that the increased complexity


What complexity?


by introducing a second syntax resp. a new special case (i.e. among) for
such a simple operation is only worth it if it leaves no reason to
revert to a hand-written replacement for performance reason,


[ ].canFind( ) allocates on the GC heap without a sufficiently smart 
compiler.



and I'm not sure if the signature taking runtime parameters is enough for that
(without assuming such a sufficiently smart compiler).

David




Re: handful and interval

2012-09-03 Thread Jonathan M Davis
On Monday, September 03, 2012 20:29:27 Timon Gehr wrote:
> On 09/03/2012 08:01 PM, David Nadlinger wrote:
> > On Monday, 3 September 2012 at 14:04:18 UTC, Andrei Alexandrescu wrote:
> >>> A sufficiently smart compiler (tm) could
> >>> optimize this to a efficient string "prefix switch statement" just as
> >>> well…
> >> 
> >> I agree. But then http://c2.com/cgi/wiki?SufficientlySmartCompiler.
> > 
> > This is exactly my point: My feeling is that the increased complexity
> 
> What complexity?

He probably means that adding another function to do exactly what an existing 
function already does is complicating the library. The new function needs to 
bring enoug to the table to be worth it, and the syntactic change of allowing 
you to do

if(value in handful(value1, value2, value3) {}

instead of

if(canFind([value1, value2, value3], value)) {}

isn't worth that.

> > by introducing a second syntax resp. a new special case (i.e. among) for
> > such a simple operation is only worth it if it leaves no reason to
> > revert to a hand-written replacement for performance reason,
> 
> [ ].canFind( ) allocates on the GC heap without a sufficiently smart
> compiler.

That's then a performance issue which make may something like handful worth 
it, but Andrei seems to be arguing based on aesthetics rather than 
performance. And if you're arguing performance, I'd argue that the "in" 
solution is a bad one anyway, because it requires constructing and returning a 
struct, whereas you could just make what you're looking for the first argument. 
e.g.

if(among(value, value1, value2, value3)) {}

The syntax is less clear this way, and perhaps the syntactic convenience of 
the whole in idea outweighs the performcance cost there (particularly since it 
should still be cheaper than a heap allocation), but the only reason to argue 
against canFind that I can see is performance, and if you're arguing 
performance, then I'm not sure that the in idea is necessarily the way to go.

Regardless, the point is that there needs to be a practical reason for 
something like handful, not an aesthetic one.

- Jonathan M Davis


Re: handful and interval

2012-09-03 Thread Timon Gehr

On 09/03/2012 05:05 PM, bearophile wrote:

David Nadlinger:


Where would the real difference to ["struct", "class",
"union"].canFind(a) then? A sufficiently smart compiler (tm) could
optimize this to a efficient string "prefix switch statement" just as
well…


I think a smart compiler is not needed.

Maybe a general solution is to introduce a way to define overloaded
templates callable as functions, that get called if the input is a
literal (or statically known, but D design requires you to asks
explicitly for a CT evaluation):

void foo(static int[] a) {}
void foo(int[] a) {}
void main(string[] args) {
 foo([1, 2]); // calls first foo
 int[] a = [1, 2] ~ args.length;
 foo(a); // calls second foo
}


Bye,
bearophile


It is not general enough. (and static is the wrong keyword.)

This would eventually lead to a solution like

bool among(S,T...)(S needle, auto enum T haystack){
...
foreach(h;haystack) static if(__traits(isConstant, h)){ ... }
...
}

Which is still rather specific.

Anyway, I don't consider among trying to be clever crucial at all.


Re: handful and interval

2012-09-03 Thread sclytrack

On Sunday, 2 September 2012 at 20:24:29 UTC, Walter Bright wrote:

On 9/2/2012 7:45 AM, Andrei Alexandrescu wrote:

On 9/2/12 4:22 PM, Andrei Alexandrescu wrote:
[snip]

The alternative would be to simply define these as functions:

if (a.among("struct", "class", "union")) { ... }
if (b.between(1, 100)) { ... }


Is between inclusive or not of the endpoints?


"between" inclusive
"in between" exclusive


Re: handful and interval

2012-09-03 Thread Timon Gehr

On 09/03/2012 08:53 PM, Jonathan M Davis wrote:

On Monday, September 03, 2012 20:29:27 Timon Gehr wrote:

On 09/03/2012 08:01 PM, David Nadlinger wrote:

On Monday, 3 September 2012 at 14:04:18 UTC, Andrei Alexandrescu wrote:

A sufficiently smart compiler (tm) could
optimize this to a efficient string "prefix switch statement" just as
well…


I agree. But then http://c2.com/cgi/wiki?SufficientlySmartCompiler.


This is exactly my point: My feeling is that the increased complexity


What complexity?


He probably means that adding another function to do exactly what an existing
function already does is complicating the library. The new function needs to
bring enoug to the table to be worth it, and the syntactic change of allowing
you to do

if(value in handful(value1, value2, value3) {}



I am certainly not arguing for that one.


instead of

if(canFind([value1, value2, value3], value)) {}

isn't worth that.


by introducing a second syntax resp. a new special case (i.e. among) for
such a simple operation is only worth it if it leaves no reason to
revert to a hand-written replacement for performance reason,


[ ].canFind( ) allocates on the GC heap without a sufficiently smart
compiler.


That's then a performance issue which make may something like handful worth
it, but Andrei seems to be arguing based on aesthetics rather than
performance. And if you're arguing performance, I'd argue that the "in"
solution is a bad one anyway, because it requires constructing and returning a
struct, whereas you could just make what you're looking for the first argument.
e.g.

if(among(value, value1, value2, value3)) {}

The syntax is less clear this way,


value.among(value1, value2, value3).


and perhaps the syntactic convenience of
the whole in idea outweighs the performcance cost there (particularly since it
should still be cheaper than a heap allocation),


Basic function inlining usually works satisfactorily. Also, optimizing
non-bottlenecks is usually not worth the effort, but I still generally
avoid gratuitous allocations.


but the only reason to argue against canFind that I can see is performance,


There are a couple unimportant ones like:
- "canFind"?
- it is unwritten law that x == 2 is preferred to 2 == x.
  (I have never experienced a bikeshedding discussion on that point,
  which is quite remarkable, as it is completely unimportant and there
  are multiple ways to do it.)
  this is much like x.among(2) vs [2].canFind(x);


and if you're arguing
performance, then I'm not sure that the in idea is necessarily the way to go.

Regardless, the point is that there needs to be a practical reason for
something like handful, not an aesthetic one.



I am arguing against pointless inefficiency. The motivation is almost 
purely aesthetic. (well, it *might* save time in the profiler, better

spent optimizing non-obvious inefficiencies and avoid the application
obtaining a sluggish feel, but I have absolutely no data to back that
up.)

I don't have an opinion on whether or not those specific functions
should be added, but Phobos is certainly lacking many simple functions.



Re: handful and interval

2012-09-03 Thread Andrei Alexandrescu

On 9/3/12 8:01 PM, David Nadlinger wrote:

On Monday, 3 September 2012 at 14:04:18 UTC, Andrei Alexandrescu wrote:

A sufficiently smart compiler (tm) could
optimize this to a efficient string "prefix switch statement" just as
well…


I agree. But then http://c2.com/cgi/wiki?SufficientlySmartCompiler.


This is exactly my point: My feeling is that the increased complexity by
introducing a second syntax resp. a new special case (i.e. among)


"among" is a simple function, not a special case.

Andrei


Re: handful and interval

2012-09-03 Thread Andrei Alexandrescu

On 9/3/12 9:15 PM, Timon Gehr wrote:

This would eventually lead to a solution like

bool among(S,T...)(S needle, auto enum T haystack){
...
foreach(h;haystack) static if(__traits(isConstant, h)){ ... }
...
}

Which is still rather specific.

Anyway, I don't consider among trying to be clever crucial at all.


I'd be happy with:

uint among(S, T...)(S needle, T haystack)
{
foreach (i, straw; haystack)
{
if (needle == straw) return i + 1;
}
return 0;
}

The only issue is that all straws in the haystack are evaluated eagerly, 
even if not needed. I think it's okay to live with that.



Andrei


Re: handful and interval

2012-09-03 Thread David Nadlinger
On Monday, 3 September 2012 at 22:37:30 UTC, Andrei Alexandrescu 
wrote:

"among" is a simple function, not a special case.


I was more thinking of the »in … handful« proposal here, 
which would entail creating a new type (presumably just with a 
single method, opIn_r) just to get a somewhat spiffy syntax for a 
single use case, even if other more conventional designs (like 
among) work just as well. In this case, I think it is 
questionable if the "more interesting" syntax justifies the 
additional cognitive overhead induced by adding such single-use 
types over just using familiar concepts.


As for among, I'm not really opposed to it, even though I'm still 
not quite sure whether template arguments vs. runtime arguments 
are the right design – but maybe I'm just overestimating the 
optimization potential gained by being able to access the 
parameters at compile time (if they are actually evaluatable at 
compile time, that is).


David