|
Boost : |
Subject: [boost] Explicit conversions to a contextual target type (was [optional] operator<(optional<T>, T) -- is it wrong?)
From: Vicente J. Botet Escriba (vicente.botet_at_[hidden])
Date: 2014-11-27 13:29:44
Le 26/11/14 12:00, Vladimir Batov a écrit :
I have started a new thread to try to clarify what I have in my mind.
>> ... I'm looking on how all these conversions can be made safer.
>> ...
> OK, Vicente, my most humble apologies for snipping all the stuff you typed
> that flew right over my head and made me feel stupid. I have to be brutally
> honest I did not understand your "idea to state explicitly that you want a
> explicit conversion but don't state to what" and your "implicit explicit
> conversion thing". You obviously put a lot of thought into it but I
> personally did not get *what problem* exactly you are trying to solve. I
> personally do not feel there is a conversion-related problem that needs
> fixing... On the other hand I do not know Haskell, so it may well be that I
> do not know what I am missing. :-) I just hope that other people you'll
> present your idea to will be smarter than me to appreciate it. Do you have
> any links to slow-pace tutorial/explanation/justification of what you are
> trying to propose that I could peruse without hurry?
>
>
I will try again, but I'm not sure I will be clearer this time :(
NOTE: this has nothing to be with a library solution, not with the
current C++ language, and so it could be out of the scope of this ML.
Please, skip this post if you are not concerned by how other language
can influence C++.
Just 3 references to Haskell
*
http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html
* http://en.wikibooks.org/wiki/Haskell/Understanding_monads
* https://www.haskell.org/haskellwiki/Polymorphism
C++ doesn't takes in account the result type of a function during
overload resolution. This has its advantages and liabilities.
Consider the following situation. Given
void f(W<T>);
template <template<class> class B, class A>
B<A> make(A v) { return B<A>(v); }
It seems reasonable to define a function
void g(X x) {
f(make<W>(x));
}
Here we are conveying the context via the template class W, that is, we
are explicit about the context.
Consider now a system on which the overload resolution takes in account
the target type. Let me use [] instead of () to wrap the function
parameters and arguments for this kind of functions so that we can
identify them in an easy way.
First of all we need to identify the context on which the function has a
sens. Let me call this construction just *context*.
template <template <class> class B>
* context* Builder
{
template <class T>
B<T> make [ T v ];
};
The function 'make' has only one argument, but its result type depends
on the context.
void g(X x) {
f( make[x] );
}
The result of make[x] has no sens if we don't know what the target type
is. In the expression
f( make [x] )
the target of the expression make [x] is W<X> and the context would be
W. So the overload that will be taken would be Builder<W>::make[X].
We need to say what Builder<W>::make[X] means, if it would even has a
meaning. In order to give a meaning to this expression we need to map W
as a builder
* template <>
context* Builder<W>
{
template <class T>
W<T> make [ T v ] { return whatever_you_want_that_returns_w_t(c); }
};
Note that in Haskell the keywords are class for context, and instance
for context_map. In some way, we could say that Builder is a type-class
having types as instances, and a type belong to this type-class if there
is an explicit mapping. This has a lot to be with the abandoned
Concept-0x proposal, which was based on signature mapping. The current
C++ Concept Lite trend is to have a default mapping for those types that
satisfy a set of some syntactical constraint. I think that we could
build something similar to Concept-0x on top of Concept Lite, but of
course without the help of the language it would be more verbose as we
will need to add an indirection.
There are also some similarities with the object oriented approach, but
instead of having an explicit object you have an deduced context that
determines the function to call using static polymorphism. This kind of
polymorphism is called ad-hoc polymorphism in the literature an in
particular it is used in Haskell and Rust.
Another example, this time with a variable
* context* ProbablyValued PV
{
// constructors
PV make [ ValueType<PV> v ];
constexpr PV none;
// accessors
...
};
Ad-hoc polymorphism has its own liabilities also of course.
Best,
Vicente
P.S. I'm not serious. Having another way to do polymorphic calls in c++
is not reasonable, or is it?
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk