Bug 8640 – Template struct/class member functions should compile conditionally
Status
RESOLVED
Resolution
INVALID
Severity
enhancement
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2012-09-11T06:15:00Z
Last change time
2015-06-09T05:14:47Z
Assigned to
nobody
Creator
monarchdodra
Comments
Comment #0 by monarchdodra — 2012-09-11T06:15:40Z
From the conversation here:
http://forum.dlang.org/thread/[email protected]
Not entirely sure if this is a bug, or an enhancement request (The answer I got was "In this case I think D is working as designed")
Basically:
-------
struct S
{
const int i;
}
struct C(T)
{
private T val;
@property T front()
{return val;}
@property void front(T value)
{val = value;} //HERE
}
void main()
{
C!S test;
}
--------
This creates a compilation error at "here". Problem: The non-compiling function was never called.
I think that member functions of template structs/classes should be compiled conditionally only when they are called.
Doing otherwise really burdens the developer with making implementation conditions for *all* his functions.
Suggest that member functions only be compiled and validated when called.
This *should* be possible, because doing this bypasses the problem:
--------
struct C(T)
{
private T val;
@property T front()() //Template specialization
{return val;}
@property void front()(T value) //Template specialization
{val = value;}
}
--------
//Technically, the first specialization is not needed, but there is currently a limitation regarding template/non-template overloads.
Comment #1 by clugdbug — 2012-09-11T08:01:50Z
This is as designed. Doing otherwise would let a lot of bugs through.
In fact one of the oldest open rejects-valid bug reports is a request to make the compiler check template functions even when they are NOT called.
There are strong reasons for the current behaviour.
* This request would interact badly with functions which return auto (the compiler needs to compile them, to find out what the return type is).
* It's impossible for classes (you need to put the function into the vtable, regardless of whether it is called or not), making a new, surprising difference between classes and structs.
Generally in these cases I just turn the function into a template function.
@property void front(Dummy = void)(T value)
{val = value;} //HERE
I never tested that with property functions though.
Comment #2 by monarchdodra — 2012-09-11T08:22:55Z
(In reply to comment #1)
Thanks for the reply.
> This is as designed. Doing otherwise would let a lot of bugs through.
> In fact one of the oldest open rejects-valid bug reports is a request to make
> the compiler check template functions even when they are NOT called.
>
> There are strong reasons for the current behaviour.
> * This request would interact badly with functions which return auto (the
> compiler needs to compile them, to find out what the return type is).
*Does* it need to compile them if no-one calls them? Who cares what the return value is, if there is no return value to be evaluated?
> * It's impossible for classes (you need to put the function into the vtable,
> regardless of whether it is called or not), making a new, surprising difference
> between classes and structs.
That is a good point, although arguably, it only holds for virtual vs final methods. So there is no reason for the same behavior to also apply to the final (non-virtual) methods of templated classes.
> Generally in these cases I just turn the function into a template function.
>
> @property void front(Dummy = void)(T value)
> {val = value;} //HERE
>
> I never tested that with property functions though.
I had considered doing that, with the even simpler:
@property void front()(T value)
{val = value;}
However, as pointed out by bearophile, this approach means this:
--------
struct C(T) {
private T val;
@property void front()(T value) {
val = value;
}
}
void main() {
C!int ci;
auto f = &ci.front; //Should be &ci.front!()
assert(ci.val == 0);
f(1);
assert(ci.val == 1);
}
--------
Ceases to work. So it does have client-side impacts :'(
Comment #3 by simen.kjaras — 2012-09-11T09:45:47Z
(In reply to comment #2)
> However, as pointed out by bearophile, this approach means this:
> --------
> struct C(T) {
> private T val;
> @property void front()(T value) {
> val = value;
> }
> }
> void main() {
> C!int ci;
> auto f = &ci.front; //Should be &ci.front!()
> assert(ci.val == 0);
> f(1);
> assert(ci.val == 1);
> }
> --------
> Ceases to work. So it does have client-side impacts :'(
Indeed. Now, there is another way to do it, which clearly marks the code as 'may or may not work, depending on template parameters', and that involves static if.
If the method does not work with some types, the correct way to state that is so that the compiler gives a sensible error message when someone tries to use your code, not when your code tries to use something else.
In this case:
static if (__traits(compiles, (T value){val = value;})) {
@property void front()(T value) {
val = value;
}
}
Comment #4 by timon.gehr — 2012-09-11T09:49:52Z
I strongly object this change. It worsens expressiveness.
Open an enhancement request about implicitly instantiating function templates if
they get their address taken instead.
Comment #5 by monarchdodra — 2012-09-11T10:32:09Z
Ty for the explanation.
This was mostly me being confused about "D doesn't work like C++".
I agree that it actually improves readability.
Will close.