handful and interval
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
string a = "class"; if (a in tuple("struct", "class", "union")) { ... }
Re: handful and interval
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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