Choosing arity of a template function

2016-02-26 Thread Andrei Alexandrescu via Digitalmars-d
A generic function receives an argument called "partition" by alias. 
That may work in one of the following ways:


partition(range);

partition!less(range);

partition!less(range, n); // n is a number

I tried this:

static if (is(partition == function) || is(partition == delegate))
  partition(r);
else if (__traits(compiles, partition!less(r, n)))
  partition!less(r, n);
else
  partition!less(r);

The first test works very nice. The second does not; the compiler 
attempts to instantiate the template wrongly and spits a bunch of errors 
before giving up, in spite of the whole "let me know silently whether 
this compiles" thing.


So, what's an elegant solution to this? I looked up std.traits but 
nothing seems to help. (Tried arity, no avail.)



Thanks,

Andrei


Re: Choosing arity of a template function

2016-02-26 Thread Andrei Alexandrescu via Digitalmars-d

On 02/26/2016 06:09 PM, Andrei Alexandrescu wrote:

A generic function receives an argument called "partition" by alias.
That may work in one of the following ways:

partition(range);

partition!less(range);

partition!less(range, n); // n is a number

I tried this:

static if (is(partition == function) || is(partition == delegate))
   partition(r);
else if (__traits(compiles, partition!less(r, n)))
   partition!less(r, n);
else
   partition!less(r);

The first test works very nice. The second does not; the compiler
attempts to instantiate the template wrongly and spits a bunch of errors
before giving up, in spite of the whole "let me know silently whether
this compiles" thing.

So, what's an elegant solution to this? I looked up std.traits but
nothing seems to help. (Tried arity, no avail.)


Urgh, forgot the "static" in front of the second "if". It does work now. 
Nevertheless, I'm still on lookout for a more elegant solution! I have 
this mindset that using __traits(compiles) is some sort of cheating.



Andrei



Re: Choosing arity of a template function

2016-02-26 Thread Era Scarecrow via Digitalmars-d
On Friday, 26 February 2016 at 23:11:32 UTC, Andrei Alexandrescu 
wrote:
Urgh, forgot the "static" in front of the second "if". It does 
work now.


 Perhaps that should be an error instead; Going from a static if 
to an else if... seems easy enough to spot and insist a fix (much 
like assignment inside an if statement is illegal).


Re: Choosing arity of a template function

2016-02-26 Thread cym13 via Digitalmars-d

On Friday, 26 February 2016 at 23:18:30 UTC, Era Scarecrow wrote:
On Friday, 26 February 2016 at 23:11:32 UTC, Andrei 
Alexandrescu wrote:
Urgh, forgot the "static" in front of the second "if". It does 
work now.


 Perhaps that should be an error instead; Going from a static 
if to an else if... seems easy enough to spot and insist a fix 
(much like assignment inside an if statement is illegal).


What about automatically inferring it? It sounds reasonnable, 
much like saying that "static" actually is for the whole 
if/elseif block.


Re: Choosing arity of a template function

2016-02-26 Thread Chris Wright via Digitalmars-d
On Fri, 26 Feb 2016 23:46:11 +, cym13 wrote:

> On Friday, 26 February 2016 at 23:18:30 UTC, Era Scarecrow wrote:
>> On Friday, 26 February 2016 at 23:11:32 UTC, Andrei Alexandrescu wrote:
>>> Urgh, forgot the "static" in front of the second "if". It does work
>>> now.
>>
>>  Perhaps that should be an error instead; Going from a static
>> if to an else if... seems easy enough to spot and insist a fix (much
>> like assignment inside an if statement is illegal).
> 
> What about automatically inferring it? It sounds reasonnable, much like
> saying that "static" actually is for the whole if/elseif block.

  static if (oggSupportEnabled)
playOggFile();
  else
if (config.loggingEnabled)
  info("ogg support not enabled; skipping playback");

So, no, unless you want to make curly braces mandatory for conditional 
bodies.


Re: Choosing arity of a template function

2016-02-26 Thread Jonathan M Davis via Digitalmars-d
On Friday, 26 February 2016 at 23:11:32 UTC, Andrei Alexandrescu 
wrote:
Urgh, forgot the "static" in front of the second "if". It does 
work now. Nevertheless, I'm still on lookout for a more elegant 
solution! I have this mindset that using __traits(compiles) is 
some sort of cheating.


There's nothing cheating about using __traits(compiles). It's 
basically the same as using is(typeof(foo)) and 
is(typeof({statement;})), albeit arguably a bit more explicit 
about the fact that it's testing what compiles. And there are 
plenty of cases where one of those is exactly what code should be 
doing.


Now, if it's a test that needs to be done frequently, then it 
makes sense to create a wrapper for it that makes using it 
cleaner, so I think that you're right in the sense that we should 
be looking to have reusable traits to test with rather than using 
__traits(compiles) or is(typeof(blah)) heavily, but they're still 
fine to use when the occasion calls for it - especially if the 
test in question isn't something that's going to need to be done 
in much code. So, to a great extent, the question is whether what 
you're trying to do here is something that very many folks are 
going to want to do, and if it is, then we should find a way to 
do it without __traits(compiles), but if not, then I'm not sure 
that I'd worry much about it.


- Jonathan M Davis


Re: Choosing arity of a template function

2016-02-26 Thread Era Scarecrow via Digitalmars-d

On Friday, 26 February 2016 at 23:53:06 UTC, Chris Wright wrote:

On Fri, 26 Feb 2016 23:46:11 +, cym13 wrote:
On Friday, 26 February 2016 at 23:18:30 UTC, Era Scarecrow 
wrote:
On Friday, 26 February 2016 at 23:11:32 UTC, Andrei 
Alexandrescu wrote:
Urgh, forgot the "static" in front of the second "if". It 
does work now.


 Perhaps that should be an error instead; Going from a static 
if to an else if... seems easy enough to spot and insist a 
fix (much like assignment inside an if statement is illegal).


What about automatically inferring it? It sounds reasonnable, 
much like saying that "static" actually is for the whole 
if/elseif block.


  static if (oggSupportEnabled)
playOggFile();
  else
if (config.loggingEnabled)
  info("ogg support not enabled; skipping playback");

So, no, unless you want to make curly braces mandatory for 
conditional bodies.


 Only for switching between static and non-static code. Besides 
with the static if's, 1 level of bracing doesn't make a new scope 
anyways (if i remember correctly).


Re: Choosing arity of a template function

2016-02-26 Thread Chris Wright via Digitalmars-d
On Sat, 27 Feb 2016 01:25:31 +, Era Scarecrow wrote:

> On Friday, 26 February 2016 at 23:53:06 UTC, Chris Wright wrote:
>> On Fri, 26 Feb 2016 23:46:11 +, cym13 wrote:
>>> On Friday, 26 February 2016 at 23:18:30 UTC, Era Scarecrow wrote:
 On Friday, 26 February 2016 at 23:11:32 UTC, Andrei Alexandrescu
 wrote:
> Urgh, forgot the "static" in front of the second "if". It does work
> now.

  Perhaps that should be an error instead; Going from a static
 if to an else if... seems easy enough to spot and insist a fix (much
 like assignment inside an if statement is illegal).
>>> 
>>> What about automatically inferring it? It sounds reasonnable,
>>> much like saying that "static" actually is for the whole if/elseif
>>> block.
>>
>>   static if (oggSupportEnabled)
>> playOggFile();
>>   else
>> if (config.loggingEnabled)
>>   info("ogg support not enabled; skipping playback");
>>
>> So, no, unless you want to make curly braces mandatory for conditional
>> bodies.
> 
>   Only for switching between static and non-static code. Besides
> with the static if's, 1 level of bracing doesn't make a new scope
> anyways (if i remember correctly).

This would be a great thing for a lint tool to check, but for a language 
change, it's breaking, and the justification is a bit short.


Re: Choosing arity of a template function

2016-02-26 Thread Meta via Digitalmars-d
It isn't cheating but IMO it's bad form. If you can do it without 
__traits(compiles) (or is(typeof()), etc.) you should, because 
there are many reasons why something will not compile, and only 
one of those reasons is the one you want to know. If there's no 
way around using it, you should still try to limit what is passed 
to __traits(compiles).


enum hasFront(T) = __traits(compiles, { auto _ = T.init.font; });

It's fairly easy to spot such a typo when it's only one line, but 
the risk of having some other compiler error being the reason 
your static if branch isn't taken grows very quickly with each 
additional line or bit of complexity.


Re: Choosing arity of a template function

2016-02-27 Thread Walter Bright via Digitalmars-d

On 2/26/2016 3:09 PM, Andrei Alexandrescu wrote:

(Tried arity, no avail.)


Get the type of the function, the tuple of its parameter types, and the .length 
of that tuple.




Re: Choosing arity of a template function

2016-02-27 Thread Marc Schütz via Digitalmars-d
On Friday, 26 February 2016 at 23:11:32 UTC, Andrei Alexandrescu 
wrote:

On 02/26/2016 06:09 PM, Andrei Alexandrescu wrote:
static if (is(partition == function) || is(partition == 
delegate))

   partition(r);
else if (__traits(compiles, partition!less(r, n)))
   partition!less(r, n);
else
   partition!less(r);

Nevertheless, I'm still on lookout for a more elegant solution! 
I have this mindset that using __traits(compiles) is some sort 
of cheating.


I don't see it as cheating; in fact it is more elegant, because 
it checks for exactly the thing you depend on, namely that 
`partition` is callable. Your explicit check above rejects 
structs with opCall(), for example, which is probably not what 
you intended.


Re: Choosing arity of a template function

2016-02-27 Thread Andrei Alexandrescu via Digitalmars-d

On 02/27/2016 07:38 AM, Marc Schütz wrote:

I don't see it as cheating; in fact it is more elegant, because it
checks for exactly the thing you depend on, namely that `partition` is
callable. Your explicit check above rejects structs with opCall(), for
example, which is probably not what you intended.


Good point. Unrelated: I also noticed that if the template has an error 
inside, the error messages when using it with __traits(compiles) are 
mightily confusing. -- Andrei


Re: Choosing arity of a template function

2016-02-27 Thread Timon Gehr via Digitalmars-d

On 27.02.2016 01:03, Jonathan M Davis wrote:


There's nothing cheating about using __traits(compiles). It's basically
the same as using is(typeof(foo)) and is(typeof({statement;})), albeit
arguably a bit more explicit about the fact that it's testing what compiles.


The two are subtly different and only __traits(compiles,...) reliably 
checks for compilability. Never use is(typeof(...)) unless you know 
exactly what you are doing.


void main(){
int x;
static void foo(){
static assert(is(typeof({return x;})));
static assert(!__traits(compiles,{return x;}));
//auto a={return x;}; // error
}
}



Re: Choosing arity of a template function

2016-02-29 Thread Dicebot via Digitalmars-d
On 02/27/2016 01:09 AM, Andrei Alexandrescu wrote:
> static if (is(partition == function) || is(partition == delegate))
>   partition(r);
> else if (__traits(compiles, partition!less(r, n)))
>   partition!less(r, n);
> else
>   partition!less(r);
> 
> The first test works very nice. The second does not; the compiler
> attempts to instantiate the template wrongly and spits a bunch of errors
> before giving up, in spite of the whole "let me know silently whether
> this compiles" thing.
> 
> So, what's an elegant solution to this? I looked up std.traits but
> nothing seems to help. (Tried arity, no avail.)

Untested:

bool hasArityOverload ( alias F ) ( )
{
import std.traits;
if (!isSomeFunction!(F!less))
return false;
alias ParamTypes = Parameters!(F!less);
if (ParamTypes.length != 2)
return false;
return isInputRange!(ParamTypes[0]) && is(ParamTypes[0] : uint);
}

Much more verbose but kess chance of accidental passing/failing by
unrelated reasons. In "casual" application code I'd still probably go
with `__traits(compiles)`.


Re: Choosing arity of a template function

2016-03-03 Thread Meta via Digitalmars-d
On Friday, 26 February 2016 at 23:09:52 UTC, Andrei Alexandrescu 
wrote:
So, what's an elegant solution to this? I looked up std.traits 
but nothing seems to help. (Tried arity, no avail.)


There's this[1] PR which implements exactly what you want, but 
it's currently not passing the auto-tester.


1. https://github.com/D-Programming-Language/dmd/pull/5201




Re: Choosing arity of a template function

2016-03-03 Thread Andrei Alexandrescu via Digitalmars-d

On 03/03/2016 02:54 PM, Meta wrote:

On Friday, 26 February 2016 at 23:09:52 UTC, Andrei Alexandrescu wrote:

So, what's an elegant solution to this? I looked up std.traits but
nothing seems to help. (Tried arity, no avail.)


There's this[1] PR which implements exactly what you want, but it's
currently not passing the auto-tester.

1. https://github.com/D-Programming-Language/dmd/pull/5201


Thanks! That will push introspection considerably further. I toggled 
auto-pull. -- Andrei


Re: Choosing arity of a template function

2016-03-03 Thread Meta via Digitalmars-d
On Thursday, 3 March 2016 at 21:06:12 UTC, Andrei Alexandrescu 
wrote:
Thanks! That will push introspection considerably further. I 
toggled auto-pull. -- Andrei


I would recommend cancelling that as it's currently failing on 
Linux and FreeBSD.


Re: Choosing arity of a template function

2016-03-03 Thread Meta via Digitalmars-d
On Thursday, 3 March 2016 at 21:06:12 UTC, Andrei Alexandrescu 
wrote:
Thanks! That will push introspection considerably further. I 
toggled auto-pull. -- Andrei


I made the simplest change possible to get it to compile, PR 
here[1]. It adds an extra allocation so any suggestions on 
eliminating that are welcome.


1. https://github.com/D-Programming-Language/dmd/pull/5496