Re: [Boost-users] [boost] upcoming Switch library review Jan 5th - Jan 9th
On Jan 6, 2008 7:34 AM, Tobias Schwinger
Steven Watanabe wrote:
Tobias Schwinger
writes: Of course there are no pointers to templates, so using a function pointer for anything but the default is pretty pointless. So is trying to handle varying result types -- maybe the result type should be passed in with another template parameter?
I'd rather leave it as result_of
::type. Actually 'result_of
::type' determines the result of the nullary call to F. I don't think I like this sort of "result_of abuse"... The correct usage would be 'result_of ::type' but it's pointless since 'MPLConstant' varies and so may the whole type expression. So, if you insist on deducing the result type from the function object (instead of having it specified explicitly) my vote is 'F::result_type', however, I still find another template parameter more appropriate for the following good reasons:
o The function object can work fine with result_of in a non-'switch_' context. The cases can return different things as long as they are convertible to the result of 'switch_', and
o there is no way to determine this type with 'result_of.
The current implementation seems to use result_type - is it planned to
change to use result_of?
I agree that result_of
Stjepan Rajko wrote:
On Jan 6, 2008 7:34 AM, Tobias Schwinger
wrote: Tobias Schwinger
writes: Of course there are no pointers to templates, so using a function pointer for anything but the default is pretty pointless. So is trying to handle varying result types -- maybe the result type should be passed in with another template parameter? I'd rather leave it as result_of
::type. Actually 'result_of ::type' determines the result of the nullary call to F. I don't think I like this sort of "result_of abuse"... The correct usage would be 'result_of ::type' but it's Steven Watanabe wrote: pointless since 'MPLConstant' varies and so may the whole type expression.
So, if you insist on deducing the result type from the function object (instead of having it specified explicitly) my vote is 'F::result_type', however, I still find another template parameter more appropriate for the following good reasons:
o The function object can work fine with result_of in a non-'switch_' context. The cases can return different things as long as they are convertible to the result of 'switch_', and
o there is no way to determine this type with 'result_of.
Actually, the latter is more severe...
The current implementation seems to use result_type - is it planned to change to use result_of?
I agree that result_of
::type is slightly abusive, since that's not what actually gets called.
Would using result_of
be an option for a non-empty case sequence?
I think it's too complicated: We can't use 'result_of' to determine the result of 'switch_', so it should be as simple to determine as possible (ideally without deduction at all).
As long as the order of the cases doesn't matter (btw, does it?), the user could put the desired type in the front of the Cases sequence if the return type differs for different MPLConstant types.
Further, we still need a special-engineered function object; one of the cases will have a special role. It might work, but it feels inelegant to me: The function object's result type should be convertible to whatever 'switch_' wants to return. So what will deducing that type from the function object buy us? The only answer I can currently see is "nothing but trouble" :-). Please tell me if I'm missing something. Regards, Tobias
On Jan 6, 2008 12:20 PM, Tobias Schwinger
Stjepan Rajko wrote:
Would using result_of
be an option for a non-empty case sequence? I think it's too complicated: We can't use 'result_of' to determine the result of 'switch_', so it should be as simple to determine as possible (ideally without deduction at all).
Sure - although the library could offer something along the lines of result_of::switch.
As long as the order of the cases doesn't matter (btw, does it?), the user could put the desired type in the front of the Cases sequence if the return type differs for different MPLConstant types.
Further, we still need a special-engineered function object; one of the cases will have a special role. It might work, but it feels inelegant to me: The function object's result type should be convertible to whatever 'switch_' wants to return.
I agree that being able to specify the return type explicitly would be very useful, precisely because you could use function objects that are not result_of/result_type compatible, or override the return type even if one is specified by the function object. I can see overriding it to boost::any or some other "common denominator" as a frequent use case.
So what will deducing that type from the function object buy us?
The only answer I can currently see is "nothing but trouble" :-). Please tell me if I'm missing something.
From what I can see, it buys simplicity when the use case is not complicated (the return type is available through result_type or result_of and does not change), or when you really want to leave it to
the function object to specify what the return type should be. Granted, all of the proposed solutions for return type deduction seem slightly imperfect / inelegant, but as long as the behavior is clearly explained in the documentation they could be useful. Regards, Stjepan
Tobias Schwinger wrote:
Stjepan Rajko wrote:
o there is no way to determine this type with 'result_of.
Actually, the latter is more severe...
The current implementation seems to use result_type - is it planned to change to use result_of?
I agree that result_of
::type is slightly abusive, since that's not what actually gets called. Would using result_of
be an option for a non-empty case sequence? I think it's too complicated: We can't use 'result_of' to determine the result of 'switch_', so it should be as simple to determine as possible (ideally without deduction at all).
As long as the order of the cases doesn't matter (btw, does it?), the user could put the desired type in the front of the Cases sequence if the return type differs for different MPLConstant types.
Further, we still need a special-engineered function object; one of the cases will have a special role. It might work, but it feels inelegant to me: The function object's result type should be convertible to whatever 'switch_' wants to return.
So what will deducing that type from the function object buy us?
The only answer I can currently see is "nothing but trouble" :-). Please tell me if I'm missing something.
I haven't been following the review (yet, though I'll be in the next few days) and I haven't read the docs yet. But from intuition, having implemented at least 2 switch implementations (spirit and phoenix), I'm guessing that there are N functions with N return types, right? If so, it follows (to my mind) that the result should be a boost::variant of all the possible return types given the arguments (through application of result_of to all the functions). Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net
Joel de Guzman wrote:
Tobias Schwinger wrote:
Stjepan Rajko wrote:
o there is no way to determine this type with 'result_of.
Actually, the latter is more severe...
The current implementation seems to use result_type - is it planned to change to use result_of?
I agree that result_of
::type is slightly abusive, since that's not what actually gets called. Would using result_of be an option for a non-empty case sequence? I think it's too complicated: We can't use 'result_of' to determine the result of 'switch_', so it should be as simple to determine as possible (ideally without deduction at all). As long as the order of the cases doesn't matter (btw, does it?), the user could put the desired type in the front of the Cases sequence if the return type differs for different MPLConstant types. Further, we still need a special-engineered function object; one of the cases will have a special role. It might work, but it feels inelegant to me: The function object's result type should be convertible to whatever 'switch_' wants to return.
So what will deducing that type from the function object buy us?
The only answer I can currently see is "nothing but trouble" :-). Please tell me if I'm missing something.
I haven't been following the review (yet, though I'll be in the next few days) and I haven't read the docs yet. But from intuition, having implemented at least 2 switch implementations (spirit and phoenix), I'm guessing that there are N functions with N return types, right? If so, it follows (to my mind) that the result should be a boost::variant of all the possible return types given the arguments (through application of result_of to all the functions).
What are we going to do with that Variant? Switch again and go back
where we're coming from? It might but isn't necessarily what we want.
Now in order to get our Variant we have to
o check result_of
Tobias Schwinger wrote:
Joel de Guzman wrote:
Tobias Schwinger wrote:
Stjepan Rajko wrote:
o there is no way to determine this type with 'result_of.
Actually, the latter is more severe...
The current implementation seems to use result_type - is it planned to change to use result_of?
I agree that result_of
::type is slightly abusive, since that's not what actually gets called. Would using result_of be an option for a non-empty case sequence? I think it's too complicated: We can't use 'result_of' to determine the result of 'switch_', so it should be as simple to determine as possible (ideally without deduction at all). As long as the order of the cases doesn't matter (btw, does it?), the user could put the desired type in the front of the Cases sequence if the return type differs for different MPLConstant types. Further, we still need a special-engineered function object; one of the cases will have a special role. It might work, but it feels inelegant to me: The function object's result type should be convertible to whatever 'switch_' wants to return.
So what will deducing that type from the function object buy us?
The only answer I can currently see is "nothing but trouble" :-). Please tell me if I'm missing something. I haven't been following the review (yet, though I'll be in the next few days) and I haven't read the docs yet. But from intuition, having implemented at least 2 switch implementations (spirit and phoenix), I'm guessing that there are N functions with N return types, right? If so, it follows (to my mind) that the result should be a boost::variant of all the possible return types given the arguments (through application of result_of to all the functions).
What are we going to do with that Variant? Switch again and go back where we're coming from?
Use the variant visitor. That may amount to the same thing, but in this case, we have a value, not a function that returns a value.
It might but isn't necessarily what we want.
Why not?
Now in order to get our Variant we have to o check result_of
::type for every function, o figure out unique types, and o make a variant from them, possibly handling special cases like using Boost.Optional or the bare type where more appropriate. It's surely useful for certain use cases but takes a lot of template instantiations, so I think it should be an extra metafunction.
Sorry, perhaps I missed the "extra metafunction" solution. What is it again? Anyway, you have good points. Yes, an explicitly specified return type would be ok too. In the standpoint of optimization, yes, a variant return is suboptimal at both compile time and at runtime. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net
Joel de Guzman wrote:
Tobias Schwinger wrote:
Joel de Guzman wrote:
Tobias Schwinger wrote:
Stjepan Rajko wrote:
o there is no way to determine this type with 'result_of.
Actually, the latter is more severe...
The current implementation seems to use result_type - is it planned to change to use result_of?
I agree that result_of
::type is slightly abusive, since that's not what actually gets called. Would using result_of be an option for a non-empty case sequence? I think it's too complicated: We can't use 'result_of' to determine the result of 'switch_', so it should be as simple to determine as possible (ideally without deduction at all). As long as the order of the cases doesn't matter (btw, does it?), the user could put the desired type in the front of the Cases sequence if the return type differs for different MPLConstant types. Further, we still need a special-engineered function object; one of the cases will have a special role. It might work, but it feels inelegant to me: The function object's result type should be convertible to whatever 'switch_' wants to return.
So what will deducing that type from the function object buy us?
The only answer I can currently see is "nothing but trouble" :-). Please tell me if I'm missing something. I haven't been following the review (yet, though I'll be in the next few days) and I haven't read the docs yet. But from intuition, having implemented at least 2 switch implementations (spirit and phoenix), I'm guessing that there are N functions with N return types, right? If so, it follows (to my mind) that the result should be a boost::variant of all the possible return types given the arguments (through application of result_of to all the functions). What are we going to do with that Variant? Switch again and go back where we're coming from?
Use the variant visitor. That may amount to the same thing, but in this case, we have a value, not a function that returns a value.
It might but isn't necessarily what we want.
Why not?
Because we're just coming from inside the switch and if we wanted to do something conditionally we could have done it there. Variant, Any, Optional or some non-union type can all make sense, depending on what we're up to.
Now in order to get our Variant we have to o check result_of
::type for every function, o figure out unique types, and o make a variant from them, possibly handling special cases like using Boost.Optional or the bare type where more appropriate. It's surely useful for certain use cases but takes a lot of template instantiations, so I think it should be an extra metafunction.
Sorry, perhaps I missed the "extra metafunction" solution. What is it again?
Ooops -- the English word "extra" might not work quite the way I expected (see below for clarification).
Anyway, you have good points. Yes, an explicitly specified return type would be ok too. In the standpoint of optimization, yes, a variant return is suboptimal at both compile time and at runtime.
Exactly. The mechanism you propose could still be useful and provided by the library as a utilty metafunction (which is what I was trying to say with "should be an extra metafunction" :-)). Regards, Tobias
Tobias Schwinger wrote:
Joel de Guzman wrote:
Anyway, you have good points. Yes, an explicitly specified return type would be ok too. In the standpoint of optimization, yes, a variant return is suboptimal at both compile time and at runtime.
Exactly. The mechanism you propose could still be useful and provided by the library as a utilty metafunction (which is what I was trying to say with "should be an extra metafunction" :-)).
Agreed 100% Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net
Tobias Schwinger wrote:
Joel de Guzman wrote:
What are we going to do with that Variant? Switch again and go back where we're coming from? Use the variant visitor. That may amount to the same thing, but in this case, we have a value, not a function that returns a value.
It might but isn't necessarily what we want. Why not?
Because we're just coming from inside the switch and if we wanted to do something conditionally we could have done it there. Variant, Any, Optional or some non-union type can all make sense, depending on what we're up to.
This is not always the case. Many times, you don't supply the functions or have control over them. That's specially true if you are a library writer, you know that ;-) Anyway, I agree with you, not in the standpoint of what is a better API, but in the standpoint of practicality. Many languages do switch the /variant/ way. But in our case, the variant will indeed be a burden that might not be needed. So, I am for "you pay only for what you need". Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net
Joel de Guzman wrote:
Anyway, I agree with you, not in the standpoint of what is a better API, but in the standpoint of practicality.
Yep. I can follow your perspective: The only logical outcome of a switch operation is in fact a union type. Besides the efficiency aspect, the devil is in the details: The default constructor's semantics of Variant, the trade-off between 'variant' and 'any', and syntactic inconsistency vs. clutter in case there's just one type...
Many languages do switch the /variant/ way.
In a lot of programming languages (especially dynamically typed ones) variants are a much more of a natural thing than they are in C++. What you call "the variant way" (or should I say the "optional variant way") is often just "the way variables work". Perl did not even have a switch statement until Version 5.10 -- you'd simply "bend the syntax to switch": http://ipserve.com/school/public/perl/perlsyn.htm#perlsyn_basic_0 Ruby has similar, though somewhat more expressive and goal-oriented constructs. We probably shouldn't tell programmers with native languages like these about 'get', 'variant', 'any' and 'optional' ;-)... Regards, Tobias
participants (3)
-
Joel de Guzman
-
Stjepan Rajko
-
Tobias Schwinger