December 17, 2013
On Tuesday, 17 December 2013 at 00:53:07 UTC, Walter Bright wrote:
> It definitely is a good idea for the compiler to recognize:
>
>    if (s == "foo" || s == "bar" || s == "baz")
>
> and generate special code for it.

I guess that would work in this case if among() is inlined since
the integer is then used as a boolean and can be reduced to the
same value (true). If it isn't inlined you would deal with (pseudo):

r=0;
if(s=="foo"){ r=1; goto e;}
if(s=="bar"){ r=2; goto e;}
if(s=="baz"){ r=3; goto e;}
e:
return r

So it would be more general to optimize conditionals that test
the same (unchanged) variable into a switch() and then if
possible reduce that to a table lookup if each basic block in the
switch sets the same variables to a constant value…

I guess a fast bool variation could be something like (pseudo):

// skip the length test if s[2] on an empty string doesn't core-dump.
if(s.length<3) return false;
return lut[ (s[2]-'o') & MASK] == s;


(the NNTP server or the web-interface seemed to be dead for 12 hours?)
December 17, 2013
On 17.12.2013 15:36, Marco Leise wrote:
> 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.

findAmong? I find 'among' ambiguous - both a boolean result and an index result would fit the name, IMO.

-- 
  Simen
December 17, 2013
On 17.12.2013 16:22, Francesco Cattoglio wrote:
> 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?

One problem of OTI (One True Iota) is floating-point inaccuracies. What does this function return? (hint: it's not 16777217)

float foo() {
    return 16777216f + 1.0f;
}

So if you want iota(16777217f, 16777245f, 1.0f) to not go into an infinite loop, you will probably need to special-case floating-point. If you assume that you can duplicate whatever is passed to iota, you could do something like this:


T _front;
size_t _index;
U _step;

void popFront() {
   ++_index;
   if (_front + _index * _step != _front) {
       _front += _index * _step;
       _index = 0;
   }
}

I don't think even this covers all bases (consider the case where the inaccuracy of real is > size_t.max).

I'm playing with writing a new iota now too. Could be fun to see what different solutions people come up with.

-- 
  Simen
December 17, 2013
Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> writes:

> bool between(T, U1, U2)(T v, U1 lo, U2 hi)
> {
>     return v >= lo && v <= hi;
> }

+1

> uint among(T, Us...)(T v, Us vals)
> {
>     foreach (i, U; Us)
>     {
>         if (v == vals[i]) return i + 1;
>     }
>     return 0;
> }

This seems less useful to me.  What was the example where you found it useful?

Jerry
December 17, 2013
On Tuesday, 17 December 2013 at 14:36:38 UTC, Marco Leise wrote:
>> > 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.

But it might not be free if the backend is incapable of reducing it because it lacks information. Sometimes just using gotos can lead to faster code (if they disappear in the IR of the backend after loop-unrolling). So testing and tweaking on different backends is kind of important (removing structures that inhibit optimization).

Some CPUs also will generate 1 as true for you when doing tests, which you in turn can use for indexing to avoid branching, so what is free depends on the hardware…

> 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 .. $];

Yep, that is neat, but then you really should name the function indexOfCharOrEnd() so you can forget about it when you look at the code again. I personally prefer to have boolean alternatives, I find the code becomes more readable. And it is sometimes easier to optimize a decision-problem than a search-problem.

Still, what is useful depends on what is the common case. When writing string validators I just want exceptions and don't even care about the result, because the code becomes very easy to maintain that way. The result is implied by being able to proceed to the next line:

validate_number(record.age);
validate_email(record.email);
database.store(record);
December 17, 2013
On Tue, Dec 17, 2013 at 04:58:10PM +0100, Simen Kjærås wrote:
> On 17.12.2013 16:22, Francesco Cattoglio wrote:
> >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?
> 
> One problem of OTI (One True Iota) is floating-point inaccuracies.
> What does this function return? (hint: it's not 16777217)
> 
> float foo() {
>     return 16777216f + 1.0f;
> }
> 
> So if you want iota(16777217f, 16777245f, 1.0f) to not go into an infinite loop, you will probably need to special-case floating-point. If you assume that you can duplicate whatever is passed to iota, you could do something like this:
> 
> 
> T _front;
> size_t _index;
> U _step;
> 
> void popFront() {
>    ++_index;
>    if (_front + _index * _step != _front) {
>        _front += _index * _step;
>        _index = 0;
>    }
> }
> 
> I don't think even this covers all bases (consider the case where the inaccuracy of real is > size_t.max).
> 
> I'm playing with writing a new iota now too. Could be fun to see what different solutions people come up with.
[...]

Maybe this should be a community effort. Let each of us come up with a new iota, and we can compare and incorporate each other's ideas to produce the best implementation. How's that?


T

-- 
Life is unfair. Ask too much from it, and it may decide you don't deserve what you have now either.
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;
> }
>
> uint among(T, Us...)(T v, Us vals)
> {
>     foreach (i, U; Us)
>     {
>         if (v == vals[i]) return i + 1;
>     }
>     return 0;
> }
>
> Add?
>
>
> Andrei


I don't know why we can do this instead:

if(foo in ["alpha", "beta", "delta"] ) {

}

basically have an opIn operator  x in y -> y.opIn(x)
U* opIn(T, U)(T key)
can define in runtime for arrays, and allow custom ones to be defines

and

if(1 < x <= 10) {

}

I remember this being shot down before...




Both of these are easier to read, and are more natural.  They also cover more cases.
December 17, 2013
Jerry <jlquinn@optonline.net> writes:

> Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> writes:
>
>> uint among(T, Us...)(T v, Us vals)
>> {
>>     foreach (i, U; Us)
>>     {
>>         if (v == vals[i]) return i + 1;
>>     }
>>     return 0;
>> }
>
> This seems less useful to me.  What was the example where you found it useful?

Being bad and following myself up...

I think this proposal is highlighting that Phobos more generally lacks set operations.  It seems to me that among() is roughly equivalent to:

auto i = v in vals;

but this is only currently used for builtin hash tables.  Since this syntax already exists, does it make sense to see if it can be done as something like:

auto i = v in (val, val, val ...);

?

I've been playing with porting some code where we use hash tables and sets quite a bit and end up creating a lot of bool[string] objects.  It works, but I do wish there was a more explicit set.  This allows for blah["entry"] = false, which isn't really what I'm trying to model :-)

Would it make sense to create a Set object in std.container?

Jerry
December 17, 2013
On 12/17/13, Byron <byron.heads@gmail.com> wrote:
> I don't know why we can't do this instead:
>
> if (foo in ["alpha", "beta", "delta"] ) {

You can come pretty close with:

if (foo in A["alpha", "beta", "delta"] )

Here's the code:

http://forum.dlang.org/thread/mailman.111.1325867961.16222.digitalmars-d@puremagic.com#post-mailman.111.1325867961.16222.digitalmars-d:40puremagic.com
December 17, 2013
On Tuesday, 17 December 2013 at 17:17:39 UTC, Andrej Mitrovic wrote:
> On 12/17/13, Byron <byron.heads@gmail.com> wrote:
>> I don't know why we can't do this instead:
>>
>> if (foo in ["alpha", "beta", "delta"] ) {
>
> You can come pretty close with:
>
> if (foo in A["alpha", "beta", "delta"] )
>
> Here's the code:
>
> http://forum.dlang.org/thread/mailman.111.1325867961.16222.digitalmars-d@puremagic.com#post-mailman.111.1325867961.16222.digitalmars-d:40puremagic.com

Wow that is a lot of hoops to jump through to simulate a fairly simple operator.  Probably not something anyone new to D is going to do.
the in operator needs some real love.  I would think you could do even more with in

if("ello" in "Hello World") { // I would think that this could return a slice

}

LinkedList!int list = makeList();
enforce(45 in list, "oh no we must have 45 in the linked list or all is lost");

!in would be nice, not sure how it could work if in returns pointers/refs/slices