Date: Fri, 2 Aug 2024 13:54:02 +0000
Other proposals of similar nature have a working compiler way before there's a proposal.
And given the questionable implement ability, having a working compiler is quite necessary.
Time is not a major concern.
I myself have a feature proposal paper in the process, and had a working implementation for 3 years before a first draft was even written. If I'm lucky I might be able to make it to C++26, but given the volume the committee has to deal with proposal it's likely that it will miss that deadline and only make it to C++29. After C++29 is officialized compiler vendors need time to update which might take up another year (for the whole update).
If you were keeping track that's a full decade in between the birth of an idea and it becoming a reality, and that is if it's accepted at all.
It's not realistic to think you are going to wake up with an idea one day, we path you on the back and puff things magically works the way you imagined.
________________________________
From: organicoman <organicoman_at_[hidden]>
Sent: Friday, August 2, 2024 12:08:30 PM
To: Tiago Freire <tmiguelf_at_[hidden]>; marcinjaczewski86_at_[hidden] <marcinjaczewski86_at_[hidden]>; std-proposals_at_[hidden] <std-proposals_at_[hidden]>
Subject: Re: [std-proposals] Function overload set type information loss
Sent from my Galaxy
When you have a working compiler we can continue the conversation.
It's like you are saying:
"Do what Eric Niebler did. Disappear for a couple of years, then come back with an awesome change that make us unhelpful to NOT use it".
That is not efficient,
-I will waste so much time,
-It will promote individualism over collectivism
-And by the time it is done, the world is already moved on.
What can be done by one person in one year, can be done by 3 in 3 months.
Anyway,
It will be on my ToDo list.
________________________________
From: organicoman <organicoman_at_[hidden]>
Sent: Friday, August 2, 2024 1:18:33 AM
To: Tiago Freire <tmiguelf_at_[hidden]>; marcinjaczewski86_at_[hidden] <marcinjaczewski86_at_[hidden]>; std-proposals_at_[hidden] <std-proposals_at_[hidden]>
Subject: Re: [std-proposals] Function overload set type information loss
That's the change I'm proposing
Sent from my Galaxy
-------- Original message --------
From: Tiago Freire <tmiguelf_at_[hidden]>
Date: 8/2/24 3:08 AM (GMT+04:00)
To: organicoman <organicoman_at_[hidden]>, marcinjaczewski86_at_[hidden], std-proposals_at_[hidden]
Subject: Re: [std-proposals] Function overload set type information loss
Do you have a compiler build that does this?
________________________________
From: organicoman <organicoman_at_[hidden]>
Sent: Friday, August 2, 2024 12:55:47 AM
To: Tiago Freire <tmiguelf_at_[hidden]>; marcinjaczewski86_at_[hidden] <marcinjaczewski86_at_[hidden]>; std-proposals_at_[hidden] <std-proposals_at_[hidden]>
Subject: Re: [std-proposals] Function overload set type information loss
Tiago,
I got your analogy perfectly, you are reiterating what you said about how much to allocate...etc.
Allow me to explain:
1- main motivation:
template<int T>
int F(int x) { return T * x + 1; }
int main()
{
vector<int(*)(int)> vec;
vec.push_back(&F<1>);
vec.push_back(&F<2>);
vec.push_back(&F<3>);
for(const auto& f : vec)
{
cout << "function parameterized on t = " << /*some call to get the non-type template value*/ << endl;
cout << "ret val =" << f(10) << endl;
}
}
Despite the information about the template value is known, yet i connot access it from out side the function, why???
Maybe i want to create an abacus of that function against the value of T!!
That's the whole purpose of my proposal.
I hear now, someone among you shouting, just return a pair<int,int>{ T, (T * x + 1) }
Hhhh...that's the easy case.
What if the T was a type template parameter, or worse, templated type template parameter!!
My journey starts from that question.
So a question that raises:
How useful knowing an extra-information about some type?
My original motivation stopped at knowing that type and maybe do some type traits manipulation only.
But i found as side effect something else.
example:
template<typename T>
void foo() { cout <<typeid(T).name()<<endl;}
auto useType(effdecltype(foo) f)
{
using T = __get_ortho_at__<0>(f);
f();
return T(0);
}
template<typename T>
void consumeType(T t)
{ cout << typeid(t).name(); }
int main()
{
vector<effdecltype(foo)> vec;
vec.push_back(&foo<int>);
vec.push_back(&foo<double>);
vec.push_back(&foo<float>);
for(int i=0; i<5; ++i)
vec.push_back(&foo<char>);
for(const auto& F: vec)
consumeType(useType(F));
}
If that operator was implemented, this is how the example should be compiled.
Compiler pre pass
1- parsed foo,
2- has function orthogonal template parameters ?
- yes: tag as dual effective/apparent
- no: pass
3- parsed useType
4- useType has an effdecltype param
4-a- is the expression inside effdecltype one of the 3 categories?
- yes: has it orthogonal template parameter?
- yes: execute 2 only , then goto 4-b
- no: goto 5
4-b- start from return statement and track back to find where effdecltype mechanism is used
- switch:
* in return statement : goto 4-c
* inside function body : goto X
* nowhere: goto 5
4-c- check function retun type: is auto operator?
- yes: tag function for virtual overload dispatch mechanism.(read down) goto 6
- no: error
5- replace effdecltype with void(*)(void)
6- parse consumeType
7- execute 2 only
8- enter main
9- parse vector
10- uses effdecltype in its template parameter.
- yes:
1- read the expression of effdecltype then ask the compiler to record all orthogonal template parameters used to instantiate that expression (foo in our example)
2- replace effdecltype void(*)(void).inside vector template argument.
3- goto 11
- no: pass
11- instantiation :
11-a- is foo tagged
yes: foo<T> : record T if T not recorded
no: pass
12- enter loop 1
12-a- execute 11 only
13- enter loop 2
14- consumeType is a function template
14-a- template parameter replaced by useType function. What is that function return type?
- switch
* concrete type : replace it in , then instantiate consumeType accordingly.
* auto operator: is useType a tagged function?
yes: generate virtual overload dispatch mechanism (read down) replace consumeType with the generated code
no: error, substitution failure, cannot call a function template.
15- execute a second compiler pass that excutes the current C++ standard.
Explanation.
In this compiler pre-pass, we discovered that useType function is using the effdecltype operator and we proved that it's return type and statement depends on it, thanks to the auto operator as a return type place holder.
Thus we tag this function. And we tell the compiler to record all orthogonal template parameters used to instantiate the expression inside the effdecltype operator.
In our case that expression is foo.
So every time foo is instantiated, that orthogonal template parameter is recorded.
At the end, the compiler will replace the auto place holder of useType function with a union made of all the types the compiler recorded.
This union is tagged as compiler generated, that means, it has special meaning.
If useType return value is assigned to a variable we have two cases.
auto var1 = useType (F); // perfect capture
double var2 = useType(F); // casting
The first case, which is the most interesting and powerful, is most useful if you pass that var1 to a function template, consumeType, in our example above.
Here the compiler generate a virtual overload dispatch mechanism (it is a made up name, nowhere in the standard)
It will create an unnamed function
void __Xidfc_consumType_(auto Xunion)
{
switch(Xunion.__X_index)
{
case 0:
consumeType<int>(Xunion.__Xi);
break;
case 1:
consumeType<double>(Xunion.__Xd);
break;
case 2:
consumeType<float>(Xunion.__Xf);
break;
case 3:
consumeType<char>(Xunion.__Xc);
break;
}
}
Where, Xunion could be of type
struct __Xidfc_foo_eff
{
int __X_index;
union
{ int __Xi; double __Xd ; float __Xf; char __Xc };
};
In the second case ( casting) which is the easiest, that line will be replaced by
double var2 = *reinterpret_cast<double*>
((reinterpret_cast<char*>(&(useType()))+sizeof(int)); // int since __X_index is int
No mater what is the union's active member.
The user have to take responsibility of his code.
And it is safe to still the guts of a temporary.
This is one approach.
It relys on static data analysis, and some compiler planner to prove that what it generates as code is correct, before passing to the next compilation phase which is the usual process.
I hope i made the jagged hills somehow even.
Nadir
And given the questionable implement ability, having a working compiler is quite necessary.
Time is not a major concern.
I myself have a feature proposal paper in the process, and had a working implementation for 3 years before a first draft was even written. If I'm lucky I might be able to make it to C++26, but given the volume the committee has to deal with proposal it's likely that it will miss that deadline and only make it to C++29. After C++29 is officialized compiler vendors need time to update which might take up another year (for the whole update).
If you were keeping track that's a full decade in between the birth of an idea and it becoming a reality, and that is if it's accepted at all.
It's not realistic to think you are going to wake up with an idea one day, we path you on the back and puff things magically works the way you imagined.
________________________________
From: organicoman <organicoman_at_[hidden]>
Sent: Friday, August 2, 2024 12:08:30 PM
To: Tiago Freire <tmiguelf_at_[hidden]>; marcinjaczewski86_at_[hidden] <marcinjaczewski86_at_[hidden]>; std-proposals_at_[hidden] <std-proposals_at_[hidden]>
Subject: Re: [std-proposals] Function overload set type information loss
Sent from my Galaxy
When you have a working compiler we can continue the conversation.
It's like you are saying:
"Do what Eric Niebler did. Disappear for a couple of years, then come back with an awesome change that make us unhelpful to NOT use it".
That is not efficient,
-I will waste so much time,
-It will promote individualism over collectivism
-And by the time it is done, the world is already moved on.
What can be done by one person in one year, can be done by 3 in 3 months.
Anyway,
It will be on my ToDo list.
________________________________
From: organicoman <organicoman_at_[hidden]>
Sent: Friday, August 2, 2024 1:18:33 AM
To: Tiago Freire <tmiguelf_at_[hidden]>; marcinjaczewski86_at_[hidden] <marcinjaczewski86_at_[hidden]>; std-proposals_at_[hidden] <std-proposals_at_[hidden]>
Subject: Re: [std-proposals] Function overload set type information loss
That's the change I'm proposing
Sent from my Galaxy
-------- Original message --------
From: Tiago Freire <tmiguelf_at_[hidden]>
Date: 8/2/24 3:08 AM (GMT+04:00)
To: organicoman <organicoman_at_[hidden]>, marcinjaczewski86_at_[hidden], std-proposals_at_[hidden]
Subject: Re: [std-proposals] Function overload set type information loss
Do you have a compiler build that does this?
________________________________
From: organicoman <organicoman_at_[hidden]>
Sent: Friday, August 2, 2024 12:55:47 AM
To: Tiago Freire <tmiguelf_at_[hidden]>; marcinjaczewski86_at_[hidden] <marcinjaczewski86_at_[hidden]>; std-proposals_at_[hidden] <std-proposals_at_[hidden]>
Subject: Re: [std-proposals] Function overload set type information loss
Tiago,
I got your analogy perfectly, you are reiterating what you said about how much to allocate...etc.
Allow me to explain:
1- main motivation:
template<int T>
int F(int x) { return T * x + 1; }
int main()
{
vector<int(*)(int)> vec;
vec.push_back(&F<1>);
vec.push_back(&F<2>);
vec.push_back(&F<3>);
for(const auto& f : vec)
{
cout << "function parameterized on t = " << /*some call to get the non-type template value*/ << endl;
cout << "ret val =" << f(10) << endl;
}
}
Despite the information about the template value is known, yet i connot access it from out side the function, why???
Maybe i want to create an abacus of that function against the value of T!!
That's the whole purpose of my proposal.
I hear now, someone among you shouting, just return a pair<int,int>{ T, (T * x + 1) }
Hhhh...that's the easy case.
What if the T was a type template parameter, or worse, templated type template parameter!!
My journey starts from that question.
So a question that raises:
How useful knowing an extra-information about some type?
My original motivation stopped at knowing that type and maybe do some type traits manipulation only.
But i found as side effect something else.
example:
template<typename T>
void foo() { cout <<typeid(T).name()<<endl;}
auto useType(effdecltype(foo) f)
{
using T = __get_ortho_at__<0>(f);
f();
return T(0);
}
template<typename T>
void consumeType(T t)
{ cout << typeid(t).name(); }
int main()
{
vector<effdecltype(foo)> vec;
vec.push_back(&foo<int>);
vec.push_back(&foo<double>);
vec.push_back(&foo<float>);
for(int i=0; i<5; ++i)
vec.push_back(&foo<char>);
for(const auto& F: vec)
consumeType(useType(F));
}
If that operator was implemented, this is how the example should be compiled.
Compiler pre pass
1- parsed foo,
2- has function orthogonal template parameters ?
- yes: tag as dual effective/apparent
- no: pass
3- parsed useType
4- useType has an effdecltype param
4-a- is the expression inside effdecltype one of the 3 categories?
- yes: has it orthogonal template parameter?
- yes: execute 2 only , then goto 4-b
- no: goto 5
4-b- start from return statement and track back to find where effdecltype mechanism is used
- switch:
* in return statement : goto 4-c
* inside function body : goto X
* nowhere: goto 5
4-c- check function retun type: is auto operator?
- yes: tag function for virtual overload dispatch mechanism.(read down) goto 6
- no: error
5- replace effdecltype with void(*)(void)
6- parse consumeType
7- execute 2 only
8- enter main
9- parse vector
10- uses effdecltype in its template parameter.
- yes:
1- read the expression of effdecltype then ask the compiler to record all orthogonal template parameters used to instantiate that expression (foo in our example)
2- replace effdecltype void(*)(void).inside vector template argument.
3- goto 11
- no: pass
11- instantiation :
11-a- is foo tagged
yes: foo<T> : record T if T not recorded
no: pass
12- enter loop 1
12-a- execute 11 only
13- enter loop 2
14- consumeType is a function template
14-a- template parameter replaced by useType function. What is that function return type?
- switch
* concrete type : replace it in , then instantiate consumeType accordingly.
* auto operator: is useType a tagged function?
yes: generate virtual overload dispatch mechanism (read down) replace consumeType with the generated code
no: error, substitution failure, cannot call a function template.
15- execute a second compiler pass that excutes the current C++ standard.
Explanation.
In this compiler pre-pass, we discovered that useType function is using the effdecltype operator and we proved that it's return type and statement depends on it, thanks to the auto operator as a return type place holder.
Thus we tag this function. And we tell the compiler to record all orthogonal template parameters used to instantiate the expression inside the effdecltype operator.
In our case that expression is foo.
So every time foo is instantiated, that orthogonal template parameter is recorded.
At the end, the compiler will replace the auto place holder of useType function with a union made of all the types the compiler recorded.
This union is tagged as compiler generated, that means, it has special meaning.
If useType return value is assigned to a variable we have two cases.
auto var1 = useType (F); // perfect capture
double var2 = useType(F); // casting
The first case, which is the most interesting and powerful, is most useful if you pass that var1 to a function template, consumeType, in our example above.
Here the compiler generate a virtual overload dispatch mechanism (it is a made up name, nowhere in the standard)
It will create an unnamed function
void __Xidfc_consumType_(auto Xunion)
{
switch(Xunion.__X_index)
{
case 0:
consumeType<int>(Xunion.__Xi);
break;
case 1:
consumeType<double>(Xunion.__Xd);
break;
case 2:
consumeType<float>(Xunion.__Xf);
break;
case 3:
consumeType<char>(Xunion.__Xc);
break;
}
}
Where, Xunion could be of type
struct __Xidfc_foo_eff
{
int __X_index;
union
{ int __Xi; double __Xd ; float __Xf; char __Xc };
};
In the second case ( casting) which is the easiest, that line will be replaced by
double var2 = *reinterpret_cast<double*>
((reinterpret_cast<char*>(&(useType()))+sizeof(int)); // int since __X_index is int
No mater what is the union's active member.
The user have to take responsibility of his code.
And it is safe to still the guts of a temporary.
This is one approach.
It relys on static data analysis, and some compiler planner to prove that what it generates as code is correct, before passing to the next compilation phase which is the usual process.
I hope i made the jagged hills somehow even.
Nadir
Received on 2024-08-02 13:54:07