Getting and setting a Windows Runtime property looks like this:
| Language | Getter | Setter |
|---|---|---|
| C# | v = o.Property; | o.Property = 42; |
| C++/CX | v = o->Property; | o->Property = 42; |
| C++/WinRT | v = o.Property(); | o.Property(42); |
| JavaScript | v = o.property; | o.property = 42; |
| Python | v = o.property | o.property = 42 |
Somebody is the odd man out.
All the projections use a simple member access to read a property and a simple assignment statement to set a property, with the exception of C++/WinRT, which uses a function call in both places.
That’s because the standard C++ language doesn’t have “properties”, and C++/WinRT is a projection of the Windows Runtime into standard C++. (C++/CX gets away with it because it’s not standard C++.)
If you’re translating existing code from one of the other languages to C++/WinRT, you may realize that properties need to change to function calls, but in your haste (or tiredness), you mistakenly convert o.Property = 42 to
o.Property() = 42;
Fortunately, this gives you a compiler error because you cannot assign to an integer value.
Unfortunately, if the property has a non-primitive type, you don’t get an error.
o.Name() = L"Fred";
// oops: Should be o.Name(L"Fred");
lv.Background() = greenBrush;
// oops: Should be lv.Background(greenBrush);
That’s because you are assigning to the temporary object returned by the property getter method, and that temporary object has an assignment operator.
The above code breaks down like this:
auto name = o.Name();
name = L"Fred";
// destruct temporary "name"
auto background = lv.Background();
background = greenBrush;
// destruct temporary "background"
Congratulations, you updated a temporary that was immediately destructed. Total waste of time.
The simplest way to make the compiler complain about code like that is to make the return value of o.Name() const.
https://gcc.godbolt.org/z/x1WsPr
But that also removes the ability to perform non-const operations on the result, like
SomeOtherFunction(detach_abi(o.Name())).I guess the other approach would be for
o.Property()to return an intermediate object, such that if you tried to use it then you would get the property for real, but if you tried to assign to it then it would set the property, in much the same way that array-like objects allow you to writeo[1] = o[0];.But then
auto result = o.Property(); o.destroy(); if (result == L"Hello") { ... }would now useoafter it has been destroyed.Any reason for not using the more common (?) o.GetProperty() / o.SetProperty(…) naming?
This comment has been deleted.
Windows Metadata (WinMD) files notes that property accessor methods have “get_” and “put_” prefixes in their names. I imagine C++/WinRT could have surfaced those names unchanged and there wouldn’t then have been any clashes.
Again, really weird that put was choosen above set, but maybe its just me:-)
Thank classic VB which had two assignment statements, Set and Let. That pattern leaked into COM and from there into every subsequent Windows object metamodel. “Put” thus makes it clear that this is not VB Let or VB Set (actually any given usage of put probably overlaps one of the other two, but no promises made as to which one).
》 Congratulations, you updated a temporary that was immediately destructed. Total waste of time.
Stop whinging. :-p