Implicit cast function receiving tuple
Before Swift 3, one was able to call a function either by explicitly specifying its arguments, or by passing a well-crafted tuple. However this way of calling functions was removed when SE-0029 was implemented.
Basically, the following was possible:
func buildDescription(name: String, age: Int) -> String {
return "Hi, I am \(name), and I am \(age)"
}
buildDescription("John Doe", age: 21)
// or, via a tuple, giving the same result
buildDescription(("John Doe", name: 21))
The Swift forums have this post regarding the above change (emphasis mine):
The proposal has been accepted for Swift 3. We acknowledge that we're removing a useful feature without providing an equally expressive drop-in replacement. However, maintaining this behavior in the type checker is a severe source of implementation complexity, and actively interferes with our plans to solidify the type system.
So it looks like the call-function-by-tuple support was prohibited only at the type checker level, meaning you cannot directly pass tuples to functions, however the internals of the compiler remained the same, which allow indirect passes of tuples, like in the examples from the question.
Cannot implicitly convert deconstructable type to Tuple
There's no implicit conversion to ValueTuple
, and your assignment is not invoking the deconstruction. You're essentially attempting to do the following which is not legal:
xy = (ValueTuple<int, int>)size;
You need two variables, not one. This is made more obvious if you consider that deconstruction is just compiler trickery/syntactic sugar for invoking the Deconstruct
method. If you were going to call it manually, you'd need to pass two variables as out
parameters, not one.
int x, y;
size.Deconstruct(out x, out y);
There's not an overload that takes a single tuple. How would that work? There's only a single variable. I suppose you might be thinking that the compiler could do something akin to:
size.Deconstruct(out xy.Item1, out xy.Item2);
Unfortunately it doesn't. For your case, you'll need to declare the variables seperately (not as a ValueTuple
) and then use deconstruction and tuple-syntax to assign to them. If you wanted, you could move the assignment from the default
case out of the switch
to give the declaration of the two variables a more tuple-y feel:
var (x, y) = (0, 0); // two variables
switch (deconstructableStruct)
{
case Size size:
(x, y) = size;
break;
case Point point:
(x, y) = point;
break;
}
You can still switch on the values later, you just need to use tuple syntax:
return (x, y) switch {
(0, 0) => "Empty",
(0, _) => "Extremely narrow",
(_, 0) => "Extremely wide",
_ => "Normal"
};
See this answer for a good alternative: writing your own implicit
conversion operator if you really need a variable that is of a tuple-type on it own (and you are both able to and don't mind modifying the Size
and Point
types to add this behavior).
generate an implicit tuple while calling a function
If the notation
Command(mode, addr)(neighbour0, neighbour1);
is acceptable, Command()
could return essentially a function object with a bound first std::tuple<...>
which would call the actual function when receiving the other arguments. That is the implementation would be something along the lines of
template <typename... Out, typename... In>
void realCommand(std::tuple<Out...>, std::tuple<In...>);
template <typename... Out>
auto Command(Out&&... out) {
return [&](auto&&... in){
realCommand(std::make_tuple(std::forward<Out>(out)...),
std::make_tuple(std::forward<decltype(in)>(in)...));
}
}
C#7 value tuple/deconstruction asymmetry
The ability to have deconstructs act like implicit converters was something that was asked for (by me, so I'm biased here) before C# 7 was released. The response from the team was (as I read it anyway) that it was asked for too near to the C# 7 release and would have taken too long to implement, so wasn't up for consideration. As it would now be a breaking change, it's not something that will ever happen.
Please see the "Allow Deconstruct and implicit operator to both support deconstruction and conversion to tuple types" roslyn repo issue for the actual discussion on the matter.
Extending type conversion to pairs/tuples of convertable types
You cannot make implicit conversion to an unknown type; and again, conversion operator must be a non-static member function which will still require you to wrap it a class; and write a converting constructor from an unknown type (aka templated constructor).
Why don't you want to make it a free function:
template<typename To, typename From>
std::pair<To, To> convert(const std::pair<From, From>& p){
return std::make_pair( static_cast< To >( p.first ),
static_cast< To >( p.second ) );
}
And then call it like:
std::pair<float, float> mp{3.424, 59.35};
auto p2 = convert<double>(mp);
That's just about as clear as it can be. See it Live on Coliru
EDIT
(As per OP's comment):
You could do a quick Type for that sort of thing:
template<typename T>
class Point{
public:
T x = T{};
T y = T{};
template<typename Y>
Point(Point<Y> p) :
x(static_cast<T>(p.x)),
y(static_cast<T>(p.y))
{ }
Point(T x_val, T y_val) : x(x_val), y(y_val)
{ }
Point(Point&&) = default;
Point(const Point&) = default;
Point& operator = (Point&&) = default;
Point& operator = (const Point&) = default;
};
Consider this function that uses a double
as the type parameter to Point
:
void print(Point<double> p){
std::cout << "(" << p.x << ", " << p.y << ")\n";
}
The statements below will all work because of the Converting constructor.
int main() {
Point<float> mp{4.535, 395.3};
Point<int> ip = mp;
print(mp);
print(ip);
return 0;
}
See it Live on Coliru
define a function with tuples
There is no trait specifically for tuples, but you could use a typeclass approach, as demonstrated in this answer.
If your goal is really to have a List but allow callers to pass in tuples (for convenience), you can modify that solution so that the type class produces a List rather than a Product.
In brief, the idea is that you provide implicit conversions from the types that callers can pass to the type you're actually going to use:
def foo(x: IndexList) = x.indices
sealed case class IndexList(indices: List[Int])
object IndexList {
implicit def val2indices(i: Int) = IndexList(List(i))
implicit def tuple2toIndices(t: (Int, Int)): IndexList =
product2indices(t)
// etc
implicit def list2indices(l: List[Int]) = IndexList(l)
private def product2indices(p: Product) =
IndexList(p.productIterator.toList.asInstanceOf[List[Int]])
}
You can then call your method with any type for which you've provided a conversion:
foo(1)
foo((2,3))
foo(List(1,2,3))
Related Topics
Ckcontainer.Discoverallidentities Always Fails
Swift Memory Management: Storing Func in Var
How to Record My MAC's Internal Sound, Not the Microphone!, Using Avcapturesession
Swift Alternative to Respondstoselector:
Swift Protocol for String Interpolation
What Might Be Causing This Animation Bug with Swiftui and Navigationview
How to Draw Two Polylines in Different Colors in Mapkit
Compactmap on Sequence() Not Lazy
Margin Between Images in Uiscrollview
How to Get Data from a Swift Nsurlsession
What Is the Markup Format for Documentation on the Parameters of a Block in Swift
Alamofire 3 Custom Encoding to Alamofire 4 Custom Encoding
Converting Audiobuffer to Cmsamplebuffer with Accurate Cmtime
Use Different Googleservice-Info.Plist for Single Project in Xcode Using Swift4
Spritekit Particle Emitter Multi Image
Swiftui Tabbar: Action for Tapping Tabitem of Currently Selected Tab to Reset View