July 29th, 2020
like1 reaction

C++/WinRT gotcha: Setting properties incorrectly

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.

Topics

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

21 comments

Discussion is closed. Login to edit/delete existing comments.

Sort by :
  • Adam

    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

    • Raymond ChenMicrosoft employee Author

      But that also removes the ability to perform non-const operations on the result, like SomeOtherFunction(detach_abi(o.Name())).

  • Neil Rashbrook

    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 write o[1] = o[0];.

    • Raymond ChenMicrosoft employee Author

      But then auto result = o.Property(); o.destroy(); if (result == L"Hello") { ... } would now use o after it has been destroyed.

  • Gunnar Dalsnes

    Any reason for not using the more common (?) o.GetProperty() / o.SetProperty(…) naming?

    • Akash Bagh

      This comment has been deleted.

      • Kalle Niemitalo

        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.

      • Gunnar Dalsnes

        Again, really weird that put was choosen above set, but maybe its just me:-)

      • Ben Voigt

        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).

  • Ivan K

    》 Congratulations, you updated a temporary that was immediately destructed. Total waste of time.

    Stop whinging. :-p