digitalmars.D - Choosing arity of a template function
- Andrei Alexandrescu (20/20) Feb 26 2016 A generic function receives an argument called "partition" by alias.
- Andrei Alexandrescu (5/23) Feb 26 2016 Urgh, forgot the "static" in front of the second "if". It does work now....
- Era Scarecrow (5/7) Feb 26 2016 Perhaps that should be an error instead; Going from a static if
- cym13 (4/11) Feb 26 2016 What about automatically inferring it? It sounds reasonnable,
- Chris Wright (8/19) Feb 26 2016 static if (oggSupportEnabled)
- Era Scarecrow (4/26) Feb 26 2016 Only for switching between static and non-static code. Besides
- Chris Wright (3/31) Feb 26 2016 This would be a great thing for a lint tool to check, but for a language...
- Jonathan M Davis (21/25) Feb 26 2016 There's nothing cheating about using __traits(compiles). It's
- Meta (11/11) Feb 26 2016 It isn't cheating but IMO it's bad form. If you can do it without
- Timon Gehr (12/15) Feb 27 2016 The two are subtly different and only __traits(compiles,...) reliably
- Marc =?UTF-8?B?U2Now7x0eg==?= (7/19) Feb 27 2016 I don't see it as cheating; in fact it is more elegant, because
- Andrei Alexandrescu (4/8) Feb 27 2016 Good point. Unrelated: I also noticed that if the template has an error
- Walter Bright (3/4) Feb 27 2016 Get the type of the function, the tuple of its parameter types, and the ...
- Dicebot (15/29) Feb 29 2016 Untested:
- Meta (5/7) Mar 03 2016 There's this[1] PR which implements exactly what you want, but
- Andrei Alexandrescu (3/9) Mar 03 2016 Thanks! That will push introspection considerably further. I toggled
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
Feb 26 2016
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
Feb 26 2016
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).
Feb 26 2016
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:What about automatically inferring it? It sounds reasonnable, much like saying that "static" actually is for the whole if/elseif block.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).
Feb 26 2016
On Fri, 26 Feb 2016 23:46:11 +0000, cym13 wrote:On Friday, 26 February 2016 at 23:18:30 UTC, Era Scarecrow wrote: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.On Friday, 26 February 2016 at 23:11:32 UTC, Andrei Alexandrescu wrote:What about automatically inferring it? It sounds reasonnable, much like saying that "static" actually is for the whole if/elseif block.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).
Feb 26 2016
On Friday, 26 February 2016 at 23:53:06 UTC, Chris Wright wrote:On Fri, 26 Feb 2016 23:46:11 +0000, cym13 wrote: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).On Friday, 26 February 2016 at 23:18:30 UTC, Era Scarecrow wrote: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.On Friday, 26 February 2016 at 23:11:32 UTC, Andrei Alexandrescu wrote:What about automatically inferring it? It sounds reasonnable, much like saying that "static" actually is for the whole if/elseif block.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).
Feb 26 2016
On Sat, 27 Feb 2016 01:25:31 +0000, Era Scarecrow wrote:On Friday, 26 February 2016 at 23:53:06 UTC, Chris Wright wrote: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.On Fri, 26 Feb 2016 23:46:11 +0000, cym13 wrote: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).On Friday, 26 February 2016 at 23:18:30 UTC, Era Scarecrow wrote: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.On Friday, 26 February 2016 at 23:11:32 UTC, Andrei Alexandrescu wrote:What about automatically inferring it? It sounds reasonnable, much like saying that "static" actually is for the whole if/elseif block.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).
Feb 26 2016
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
Feb 26 2016
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.
Feb 26 2016
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 } }
Feb 27 2016
On Friday, 26 February 2016 at 23:11:32 UTC, Andrei Alexandrescu wrote:On 02/26/2016 06:09 PM, Andrei Alexandrescu 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.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.
Feb 27 2016
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
Feb 27 2016
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.
Feb 27 2016
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)`.
Feb 29 2016
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
Mar 03 2016
On 03/03/2016 02:54 PM, Meta wrote:On Friday, 26 February 2016 at 23:09:52 UTC, Andrei Alexandrescu wrote:Thanks! That will push introspection considerably further. I toggled auto-pull. -- AndreiSo, 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
Mar 03 2016
On Thursday, 3 March 2016 at 21:06:12 UTC, Andrei Alexandrescu wrote:Thanks! That will push introspection considerably further. I toggled auto-pull. -- AndreiI would recommend cancelling that as it's currently failing on Linux and FreeBSD.
Mar 03 2016
On Thursday, 3 March 2016 at 21:06:12 UTC, Andrei Alexandrescu wrote:Thanks! That will push introspection considerably further. I toggled auto-pull. -- AndreiI 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
Mar 03 2016