December 17, 2013
On Monday, 16 December 2013 at 23:04:09 UTC, Andrei Alexandrescu wrote:
> It's a good idea, but unfortunately we don't have partial evaluation. We'd need to move whatever compile-time work is to be done in the template arguments area, i.e.

When I think of it, it might be better to let the compiler detect it and do this as a general optimization. Because you might be able to collapse two consecutive among() into a single lookup if the code-structure allows for it. So an early library optimization could reduce the ability to optimize at a later stage… *shrug*

December 17, 2013
On Tue, Dec 17, 2013 at 12:50:21AM +0100, digitalmars-d-bounces@puremagic.com wrote:
> On Monday, 16 December 2013 at 23:01:36 UTC, Walter Bright wrote:
> >I hate to say it, but often when I read the Phobos library documentation I wind up having to check the source code. Yes, I should follow my own advice and do PRs.
> 
> You should consider having direct links to html-formatted source code from the documentation. Like this:
> 
> http://webapp-improved.appspot.com/api/webapp2_extras/json.html
> 
> I find that simple "[source]"-link to be a very helpful solution. It is very difficult to make good enough documentation to cover things like assumptions that you need to know about when doing inheritance related stuff. So easy access to code is very nice, and that also means that the real documentation can be less detailed and verbose and easier to comprehend.

I agree it's a nifty trick, but I think it's solving the wrong problem. Documentation should document the *API*, and user code shouldn't depend on quirks in the current implementation, because it may change later (bugfixes, optimizations, etc.).


T

-- 
You have to expect the unexpected. -- RL
December 17, 2013
On Tuesday, 17 December 2013 at 00:29:29 UTC, H. S. Teoh wrote:
> Documentation should document the *API*, and user code shouldn't depend
> on quirks in the current implementation, because it may change later
> (bugfixes, optimizations, etc.).

Yes… but when there are quirks that cause your code to not work it is much easier to locate the problem if you can easily jump around in the library code. I don't use it much for initial coding, unless the documentation is missing or if the documentation lacks proper examples that show how the different part interact or if the documentation is too verbose. I use it when I need more insight (like when doing debugging or if I have to hook into handlers etc).
December 17, 2013
On 12/16/2013 4:01 PM, "Ola Fosheim Grøstad" <ola.fosheim.grostad+dlang@gmail.com>" wrote:
> When I think of it, it might be better to let the compiler detect it and do this
> as a general optimization. Because you might be able to collapse two consecutive
> among() into a single lookup if the code-structure allows for it. So an early
> library optimization could reduce the ability to optimize at a later stage… *shrug*

It definitely is a good idea for the compiler to recognize:

   if (s == "foo" || s == "bar" || s == "baz")

and generate special code for it.

December 17, 2013
On Monday, 16 December 2013 at 20:38:52 UTC, Andrei Alexandrescu wrote:
> bool between(T, U1, U2)(T v, U1 lo, U2 hi)
> {
>     return v >= lo && v <= hi;
> }

I realize this is, at this point, being retracted. But it would open up some interesting ideas. It seems a lot like iota, but it could look pretty cool for some purposes. Consider an alternative API where you could do things like this:

---
if(x in between(2, 7)) {
   //...
}
---

and

---
// for random number generation...
auto a = uniform(between(30, 100));
---

A slight bit more verbose but more readable, maybe. It also shifts the code that checks that it's a valid range (not in the D InputRange sense) to between instead.

So code like
https://github.com/D-Programming-Language/phobos/blob/master/std/random.d#L1318
could be taken out and isolated in the "between" code. This could have some slight positive performance implications for cases where you generate a lot of random numbers in the same range, but its main value would probably come improved readability and reduced code duplication (but, admittedly, I've not looked around enough to know if there are more opportunities to use such a between object in phobos...).

Also, kinda going along with what bearophile said, something like this might be possible to add to iota. But I'd like to see a different name for it since `uniform(iota(30,100))` isn't exactly as nice to read.

And I think a default for the range of numbers between represents probably should be "[)" but obviously being customizable is important too.
December 17, 2013
Am Mon, 16 Dec 2013 14:59:43 -0800
schrieb Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org>:

> On 12/16/13 2:38 PM, Andrej Mitrovic wrote:
> > On 12/16/13, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
> >> There's quite a bit of evidence in support of among (not as much for between) in the source code of Facebook's cpplint, soon to be open sourced. Here are some relevant quotes:
> >
> >>From first glance it seems you're always using among when needing a
> > boolean result, so why does among have to return an index instead of a boolean true/false?
> 
> More info is better than less info, especially if it comes for free. We already use this idiom in a couple of places in Phobos.
> 
> Andrei

I've always preferred findCharInString() to return the "end" of the string in case the char isn't found instead of e.g. -1, for two reasons:

a) With an index to the end (equal to the length) you can do
   more useful stuff like:

   auto idx = findCharInString(' ', str);
   str = str[idx .. $];

   -1 requires an explicit if()-branch in any case.

   auto idx = findCharInString(' ', str);
   if (idx == -1) {
     str = ""
   } else {
     str = str[idx .. $];
   }

b) The index becomes size_t again, which is the correct type.

Now similarly I would prefer if among() could do anything else but shift indexes by +1. Indexes in D are 0 based. Since we are talking about a verbatim set of options here instead of a linear string, I could live with -1 as "not in list" and a zero based index, but then among would have to be renamed to something that doesn't imply a result that converts to boolean. "optionIndex" or something.

-- 
Marco

December 17, 2013
Am Mon, 16 Dec 2013 14:31:16 -0800
schrieb "H. S. Teoh" <hsteoh@quickfur.ath.cx>:

> On Mon, Dec 16, 2013 at 01:45:38PM -0800, Walter Bright wrote:
> > On 12/16/2013 12:38 PM, Andrei Alexandrescu wrote:
> > >bool between(T, U1, U2)(T v, U1 lo, U2 hi)
> > >{
> > >     return v >= lo && v <= hi;
> > >}
> > 
> > You'd need 4 such functions, < <, < <=, <= <, <= <=, and it just seems like trivia.
> [...]
> 
> 	bool between(string op1=">=", string op2="<=", T, U1, U2)
> 		    (T v, U1, lo, U2 hi)
> 	{
> 		return mixin("v" ~ op1 ~ "lo") &&
> 			mixin("v" ~ op2 ~ "hi");
> 	}
> 
> 	x.between(y, z);	// y <= x <= z
> 	x.between!(">", "<")(y, z);	// y < x < z
> 	// etc.
> 
> 
> T

Compare:

a) import std.something; x.between!(">", "<")(y, z);
b) y < x && x < z

now which would you use? :-)

-- 
Marco

December 17, 2013
On Monday, 16 December 2013 at 20:38:52 UTC, Andrei Alexandrescu wrote:
> bool between(T, U1, U2)(T v, U1 lo, U2 hi)
> {
>     return v >= lo && v <= hi;
> }

Careful:

assert(between(0u, -1, 1)); // fails

Assuming no overflows, a faster implementation would be:

return v-lo <= hi-lo;
December 17, 2013
Am Mon, 16 Dec 2013 15:04:09 -0800
schrieb Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org>:

> On 12/16/13 2:55 PM, "Ola Fosheim Grøstad" <ola.fosheim.grostad+dlang@gmail.com>" wrote:
> > On Monday, 16 December 2013 at 21:45:40 UTC, Walter Bright wrote:
> >>> uint among(T, Us...)(T v, Us vals)
> >>> {
> >>>     foreach (i, U; Us)
> >>>     {
> >>>         if (v == vals[i]) return i + 1;
> >>>     }
> >>>     return 0;
> >>> }
> >>
> >> This has O(n) behavior, which might be unexpected for the user.
> >
> > I would expect one table-lookup for this if vals contains strings, not N ifs. If you look at the example, most of them could be done with perfect hashing on a single character.
> >
> > Is it possible for the compiler/template system to turn this into a switch/dictionary? Or is there something in the language/compiler that makes that impossible?
> 
> It's a good idea, but unfortunately we don't have partial evaluation. We'd need to move whatever compile-time work is to be done in the template arguments area, i.e.
> 
> value.among!("foo", "bar", "baz")
> 
> as opposed to
> 
> value.among("foo", "bar", "baz")
> 
> Now that I think of it we can easily support both forms.
> 
> 
> 
> Andrei

This works well in general. I did the same for writing bits to a stream:

writeBits()(uint bits, uint value)
writeBits(uint bits)(uint value)

(Now with 2.064 the empty template parenthesis can be omitted.) Knowing that the bit count is 9 or less, you can optimize for a case that only writes to two bytes. The one bit case doesn't even need branching at all.

-- 
Marco

December 17, 2013
On Monday, 16 December 2013 at 22:53:24 UTC, H. S. Teoh wrote:
>> What's wrong with having it implemented analogous to
>> std.random.uniform -- taking a bounds parameter which allows for
>> open and/or closed at either end, with the default being "[)" ... ?
>> 
>> By the way, I'd also like to see that open/closed-at-either-end
>> specialization extended to std.range.iota().
>
> Oooh, do I hear a volunteer for cleaning up iota? ;-)
>
> While you're at it, you might as well implement:
>
> 	https://d.puremagic.com/issues/show_bug.cgi?id=10762
>
> :-P
>
>
> T

Well, I might actually volunteer :)
Any pointer about implementing that enhancement? Can one just forgot about the different versions (one for integrals, one for floating points) and just implement the One True Iota?