For people transitioning to C++/WinRT from other languages, a common beginner mistake is setting properties incorrectly. Here are the ways of accessing a Windows Runtime property in various languages.
Language | Read a property | Write a property |
---|---|---|
C# | oldValue = o.ActiveWidget; |
o.ActiveWidget = newValue; |
VB | oldValue = o.ActiveWidget |
o.ActiveWidget = newValue |
JavaScript | oldValue = o.activeWidget; |
o.activeWidget = newValue; |
Python | old_value = o.active_widget |
o.active_widget = new_value |
C++/CX | oldValue = o->ActiveWidget; |
o->ActiveWidget = newValue; |
C++/WinRT | oldValue = o.ActiveWidget(); |
o.ActiveWidget(newValue); |
Notice the odd one out in the above list.¹ Everybody uses the assignment operator to set a property, except C++/WinRT, which uses a function call.
If you’re used to the other languages, you may incorrectly interpret the rule that “property access is a function call” People transitioning to C++/WinRT from other languages are tempted to write
o.ActiveWidget() = newValue;
in a misguided attempt to set the property to a new value. What this actually does is fetch the current value of the property, and then assign the new value to the temporary. It’s a lot of work with nothing to show for it, and then you scratch your head wondering why the attempt to update the property appears to have been ignored.
I tried to update C++/WinRT to deny assignment to most types of rvalues, rendering the above a compile-time error, but the change had to be reverted for compatibility reasons.
There’s no real value to creating a temporary only to assign a new value to it. You may as well just create the temporary with the desired value, and then use it.
// Pointless DoSomething(o.ActiveWidget() = newValue); // Just do this DoSomething(Widget(newValue)); // Or possibly even just DoSomething(newValue);
¹ Rust/WinRT also uses function calls to access properties:
Language | Read a property | Write a property |
---|---|---|
Rust/WinRT | old_value = o.active_widget(); |
o.set_active_widget(new_value); |
However, it doesn’t suffer from the same problem as C++/WinRT, because Rust disallows assignment to rvalues (known as value expressions in Rust-speak).
// error E0070: Invalid left-hand side of assignment o.active_widget() = new_value;
The problem of assigning to a temporary is peculiar to C++.
Which compiler allows assignment to a temporary? VS2019 would say: “error C2106: ‘=’: left operand must be l-value”, Clang: “error: expression is not assignable”.
Godbolt disagrees with you: https://gcc.godbolt.org/z/G85M9PsnW
Huh. I never realized class types get rvalue ref-qualified assignment operators by default. So, the compiler will allow assignment if the function returns a class type, but not a fundamental one. Thanks for taking the time to make a godbolt demo.
If I were to clone the repo and try to use your helpful update, can you enlighten me about what those compatibility reasons were? Kenny did not provide any details.
For example, if it breaks in an older OS build than I’m requiring I may be able to take the change.