digitalmars.D - Template constraints
- Andrei Alexandrescu (20/20) Feb 14 2015 There's been recurring discussion about failing constraints not
- Tobias Pankrath (17/38) Feb 14 2015 I agree, but also for function should conditions that do not
- Andrei Alexandrescu (2/15) Feb 14 2015 That would impact cross-module overloading. -- Andrei
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (6/10) Feb 14 2015 There was talk about enabling IFTI for constructors. If that is
- Xinok (23/44) Feb 14 2015 I've done this myself for the same reason. I may split up the
- Atila Neves (7/28) Feb 15 2015 Even then this "hides" some errors and debugging isn't easy
- Steven Schveighoffer (33/53) Feb 16 2015 Wait, isn't this OK?
- Nick Treleaven (9/24) Feb 19 2015 OK, so the idea might not be appropriate for types. What about for
- Chris Williams (10/31) Feb 17 2015 This seems like a lot of manual labor to cover a compiler
There's been recurring discussion about failing constraints not generating nice error messages. void fun(T)(T x) if (complicated_condition) { ... } struct Type(T)(T x) if (complicated_condition) { ... } If complicated_condition is not met, the symbol simply disappears and the compiler error message just lists is as a possible, but not viable, candidate. I think one simple step toward improving things is pushing the condition in a static_assert inside type definitions: void fun(T)(T x) if (complicated_condition) { ... } // no change struct Type(T)(T x) { static assert(complicated_condition, "Informative message."); ... } This should improve error messages for types (only). The rationale is that it's okay for types to refuse compilation because types, unlike functions, don't overload. The major reason for template constraints in functions is allowing for good overloading. Andrei
Feb 14 2015
On Saturday, 14 February 2015 at 17:00:33 UTC, Andrei Alexandrescu wrote:There's been recurring discussion about failing constraints not generating nice error messages. void fun(T)(T x) if (complicated_condition) { ... } struct Type(T)(T x) if (complicated_condition) { ... } If complicated_condition is not met, the symbol simply disappears and the compiler error message just lists is as a possible, but not viable, candidate. I think one simple step toward improving things is pushing the condition in a static_assert inside type definitions: void fun(T)(T x) if (complicated_condition) { ... } // no change struct Type(T)(T x) { static assert(complicated_condition, "Informative message."); ... } This should improve error messages for types (only). The rationale is that it's okay for types to refuse compilation because types, unlike functions, don't overload. The major reason for template constraints in functions is allowing for good overloading. AndreiI agree, but also for function should conditions that do not effect overloading go into static asserts. For example if I were to write an algorithm that works with forward ranges and can be optimized for random access ranges but needs assignable elements in any case: void foo(R)(R r) if(isForwardRange!R && !isRandomAccessRange!R) { static assert(hasAssignableElements!R, "informative error msg"); } void foo(R)(R r) if(isRandomAccessRange!R) { static assert(hasAssignableElements!R, "informative error msg"); }
Feb 14 2015
On 2/14/15 9:06 AM, Tobias Pankrath wrote:I agree, but also for function should conditions that do not effect overloading go into static asserts. For example if I were to write an algorithm that works with forward ranges and can be optimized for random access ranges but needs assignable elements in any case: void foo(R)(R r) if(isForwardRange!R && !isRandomAccessRange!R) { static assert(hasAssignableElements!R, "informative error msg"); } void foo(R)(R r) if(isRandomAccessRange!R) { static assert(hasAssignableElements!R, "informative error msg"); }That would impact cross-module overloading. -- Andrei
Feb 14 2015
On Saturday, 14 February 2015 at 17:00:33 UTC, Andrei Alexandrescu wrote:... This should improve error messages for types (only). The rationale is that it's okay for types to refuse compilation because types, unlike functions, don't overload.There was talk about enabling IFTI for constructors. If that is done, some types _will_ overload. But for the remaining ones (i.e. those that we don't want to overloadable), I think it's a good strategy.
Feb 14 2015
On Saturday, 14 February 2015 at 17:00:33 UTC, Andrei Alexandrescu wrote:There's been recurring discussion about failing constraints not generating nice error messages. void fun(T)(T x) if (complicated_condition) { ... } struct Type(T)(T x) if (complicated_condition) { ... } If complicated_condition is not met, the symbol simply disappears and the compiler error message just lists is as a possible, but not viable, candidate. I think one simple step toward improving things is pushing the condition in a static_assert inside type definitions: void fun(T)(T x) if (complicated_condition) { ... } // no change struct Type(T)(T x) { static assert(complicated_condition, "Informative message."); ... } This should improve error messages for types (only). The rationale is that it's okay for types to refuse compilation because types, unlike functions, don't overload. The major reason for template constraints in functions is allowing for good overloading. AndreiI've done this myself for the same reason. I may split up the condition into multiple 'static assert' statements which gives a more specific error message. However, I wonder if there's a better solution that we can incorporate in to D. The trouble with template constraints is that, if you have complex conditions, there's no easy way to fall back to a default state. You would have to duplicate all the conditions and write "not this and not this and not this and ...". Template specializations can fall back to a default state, but not template constraints. So what if we were to add a feature that would allow us to do just that? void test(Range)(Range r) if(isRandomAccessRange!Range) { ... } void test(Range)(Range r) default { static assert(false, "descriptive error message"); } I'm not claiming this is a better solution; I'm simply putting the idea out there.
Feb 14 2015
Even then this "hides" some errors and debugging isn't easy (figuring out why the template constraint failed). I've been planning on creating a DIP addressing this for ages, I should probably get around to that. Atila On Saturday, 14 February 2015 at 17:00:33 UTC, Andrei Alexandrescu wrote:There's been recurring discussion about failing constraints not generating nice error messages. void fun(T)(T x) if (complicated_condition) { ... } struct Type(T)(T x) if (complicated_condition) { ... } If complicated_condition is not met, the symbol simply disappears and the compiler error message just lists is as a possible, but not viable, candidate. I think one simple step toward improving things is pushing the condition in a static_assert inside type definitions: void fun(T)(T x) if (complicated_condition) { ... } // no change struct Type(T)(T x) { static assert(complicated_condition, "Informative message."); ... } This should improve error messages for types (only). The rationale is that it's okay for types to refuse compilation because types, unlike functions, don't overload. The major reason for template constraints in functions is allowing for good overloading. Andrei
Feb 15 2015
On 2/14/15 12:00 PM, Andrei Alexandrescu wrote:There's been recurring discussion about failing constraints not generating nice error messages. void fun(T)(T x) if (complicated_condition) { ... } struct Type(T)(T x) if (complicated_condition) { ... } If complicated_condition is not met, the symbol simply disappears and the compiler error message just lists is as a possible, but not viable, candidate. I think one simple step toward improving things is pushing the condition in a static_assert inside type definitions: void fun(T)(T x) if (complicated_condition) { ... } // no change struct Type(T)(T x) { static assert(complicated_condition, "Informative message."); ... } This should improve error messages for types (only). The rationale is that it's okay for types to refuse compilation because types, unlike functions, don't overload. The major reason for template constraints in functions is allowing for good overloading. AndreiWait, isn't this OK? struct S(T) if(is(T == int)) { ... } struct S(T) if(is(T == double)) { ... } I mean we could do it like this: struct S(T) { static if(is(T == int)) { ... // int mode } else static if(is(T == double)) { ... // double mode } else static assert(0); } but that defeats the purpose of being able to split the "int mode" stuff from the "double mode" stuff. They may even be in multiple modules. Is this not "overloading" of types? I don't think this should be frowned upon. I think instead of this, we should try and just make the messages better. Note that something like you are suggesting requires much rewriting of code. Have you considered something like this? forum.dlang.org/post/m4nnrk$1ml5$1 digitalmars.com -Steve
Feb 16 2015
On 16/02/2015 19:31, Steven Schveighoffer wrote:Wait, isn't this OK? struct S(T) if(is(T == int)) { ... } struct S(T) if(is(T == double)) { ... }...They may even be in multiple modules. Is this not "overloading" of types? I don't think this should be frowned upon.OK, so the idea might not be appropriate for types. What about for methods though - if a method doesn't have overloads, static assert might be better than a constraint. Even where there are overloads, (part of) the constraint may be OK to push into static assert instead for better error messages.I think instead of this, we should try and just make the messages better. Note that something like you are suggesting requires much rewriting of code.True, but until the compiler improves perhaps we could use this technique for methods e.g. in new code.
Feb 19 2015
On Saturday, 14 February 2015 at 17:00:33 UTC, Andrei Alexandrescu wrote:There's been recurring discussion about failing constraints not generating nice error messages. void fun(T)(T x) if (complicated_condition) { ... } struct Type(T)(T x) if (complicated_condition) { ... } If complicated_condition is not met, the symbol simply disappears and the compiler error message just lists is as a possible, but not viable, candidate. I think one simple step toward improving things is pushing the condition in a static_assert inside type definitions: void fun(T)(T x) if (complicated_condition) { ... } // no change struct Type(T)(T x) { static assert(complicated_condition, "Informative message."); ... } This should improve error messages for types (only). The rationale is that it's okay for types to refuse compilation because types, unlike functions, don't overload. The major reason for template constraints in functions is allowing for good overloading. AndreiThis seems like a lot of manual labor to cover a compiler limitation that is going to affect not just Phobos, but every D project which uses constraints (or template type specialization?) instead of interfaces. Ideally, the compiler would be able to say, "Well the function name and the parameter list exactly match these possibilities, so let's run through each constraint applied in the set of possibilities and explicitly dump the boolean result for each constraint."
Feb 17 2015