September 03, 2012
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
September 03, 2012
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

September 03, 2012
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
September 03, 2012
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.
September 03, 2012
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
September 03, 2012
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.

September 03, 2012
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
September 03, 2012
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
September 03, 2012
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
1 2 3 4 5 6 7
Next ›   Last »