An Almost Useful Language Extension

While fiddling around a bit with clang, I came across an interesting C++ language extension from Microsoft. If you’ve done library development on Windows, you’ve likely come across the __declspec keyword for things like importing and exporting symbols from a framework. You use __declspec( dllexport ) or __declspec( dllimport ), respectively. The __declspec keyword is basically Microsoft’s version of attributes, though it predates the concept (in C++) by many years. The __declspec that caught my eye was __declspec( property ). It’s way to have automatically generated getter and setter behavior for C++ class member variables. At first, I thought this was a great feature! Then I looked into it a bit more.

You attach this particular __declspec to a class member variable, and specify a getter and/or setter function. This allows you to use the member variable as an l- or r-value, and it will call the getter or setter as appropriate. For instance:

struct s {
  int getter() const { return i; }
  void setter( int i_ ) { i = i_; }

  __declspec( property( get = getter, put = setter ) )
  int MyAwesomeProperty

private:
  int i;
};

int main( void ) {
  struct s my_s;
  my_s.MyAwesomeProperty = 12;
  ::printf( "%d\n", my_s.MyAwesomeProperty );
  return 0;
}

The code to assign into MyAwesomeProperty would actually call s::setter, and the code to query MyAwesomeProperty would actually call s::getter.

Pretty awesome, right? Well… not really. The first thing I tried to do with it didn’t work:

class Foo {
public:
  Foo() : mAwesome( NULL ) {}

  __declspec( property( get = getValue, put = putValue ) )
    const char *Awesome;

private:
  char *mAwesome;
  void putValue( const char *val ) {
    mAwesome = val ? ::_strdup( val ) : nullptr;
  }

  const char *getValue() const { return mAwesome; }
};

int main()
{
  Foo *f = new Foo;
  f->Awesome = "This is awesome";
  ::printf( "%s\n", f->Awesome );
  delete f;
  return 0;
}

Great idea, right? Except it doesn’t work! Instead, you get two errors:

error C2248: ‘Foo::getValue’ : cannot access private member declared in class ‘Foo’
error C2248: ‘Foo::putValue’ : cannot access private member declared in class ‘Foo’

The first thing that came to my mind was: why?? Then I sat down and considered the feature in more detail. What the compiler has to do in order to support this is two-fold. First, it does not allocate any space for the Awesome member variable. So the size of the class is 4 bytes (on a 32-bit build) instead of 8 bytes. The second thing that would happen is any call to Awesome would be immediately replaced by either putValue or getValue. If it was an l-value access, it would be replaced with putValue, and if it was an r-value access, it would be replaced with getValue. That means these functions must be accessible to the caller. To test this theory out, I took a look at the resulting binary, and here are the relevant bits that I found:

; Allocate 4 bytes before calling the constructor
push        4  
call        operator new (139119Ah)  

; Assign to Awesome
push        offset string "This is awesome" (1396834h)  
mov         ecx,dword ptr [ebp-14h]  
call        Foo::putValue (1391046h)  

; Retrieve Awesome and use it in a call to printf
mov         ecx,dword ptr [ebp-14h]  
call        Foo::getValue (13910AFh)  
mov         esi,esp  
push        eax  
push        offset string "%s\n" (1396830h)  
call        dword ptr [__imp__printf (13992ECh)]  

So my guess was correct. But I am still bothered by the behavior. This feature is practically a macro at this point (a very smart macro, but a macro nonetheless). I think the feature could have been implemented slightly more intelligently. The __declspec attaches to the declaration of Awesome (that’s why it’s a declaration specification), so any time you access Awesome, you know exactly what the getter and setter are. It would be trivial for the compiler to ignore the access level of the getter and setter, and simply use the access level of the member variable instead. So I tried to figure out why the behavior is the way it is. The first thing that came to mind was the ability to have a read-only property.

class Foo {
public:
  Foo() : mAwesome( NULL ) {}

  __declspec( property( get = getValue ) )
    const char *Awesome;

  char *mAwesome;
  const char *getValue() const { return mAwesome; }
};

int main()
{
  Foo *f = new Foo();
  f->Awesome = "This is awesome";
  ::printf( "%s\n", f->Awesome );
  return 0;
}

If you run this code, you will get the following error:

error C2774: ‘Foo::Awesome’ : no ‘put’ method is associated with this property

Now, this does make the feature pretty awesome in my mind. Having read-only properties is a great thing for reducing unfettered external modifications. So in this regard, I do think the feature is quite handy. However, this doesn’t actually demonstrate a reason for the access level behavior!

The closest approximation I could come up with would be to have a property that can be externally readable, but internally writeable. For instance:

class Foo {
public:
  Foo() : mAwesome( NULL ) {}

  __declspec( property( get = getValue, put = putValue ) )
    const char *Awesome;

  const char *getValue() const { return mAwesome; }

protected:
  void putValue( const char *val ) {
    mAwesome = val ? ::_strdup( val ) : nullptr;
  }

private:
  char *mAwesome;
};

class Bar : public Foo {
public:
  Bar( const char * s ) : Foo() { Awesome = s; }
};

int main()
{
  Foo *f = new Bar( "This is awesome" );
  ::printf( "%s\n", f->Awesome );
  return 0;
}

In this example, Bar has the ability to assign into Awesome, but you cannot access Awesome from outside the class hierarchy. However, I find this to be awfully contrived since Bar could just as easily be calling putValue directly!

So my final thoughts on this feature are that it has limited appeal. It doesn’t help with encapsulation at all, only provides minor code readability, but at the expense of code quality since there are (by definition) two ways to get to the same code path. The only situations I would find this marginally useful for are: read-only properties and making “prettier” COM code (since COM uses the get and put pattern frequently). But truthfully, that’s a stretch. If Microsoft had made access follow the property instead of the method, this would be a far more interesting language extension.

This entry was posted in C/C++, Win32 and tagged , , . Bookmark the permalink.

2 Responses to An Almost Useful Language Extension

  1. Justin says:

    To be fair, if it followed the property’s access specifier instead of the accessor’s & mutator’s specifiers, it could be dangerous if the user was only intended to have protected access, but the property was public instead. If the “get” function is protected or private, but the property lets you treat it like it’s public, what’s the point of even being able to specify that something is protected or private?

    I’d be more wary of something that gives you access you’re not supposed to have than something that promises more access than you’re allowed but doesn’t follow through, but that may just be me.

  2. Weasel says:

    Yeah, it’s just you. Member functions/accessors can already do what you are so afraid of, so what’s the difference? If you don’t want public access, then don’t make the property public?! Is that so hard?

    It’s absolutely not any different than normal accessors, except it doesn’t require stupid parantheses. This post was in 2011 and 6 years later it’s still not included in C++ standard even though there’s been several specs already for “implicitly callable functions” (which in the end, serves the same purpose as declspec(property) btw). WTF are they doing? Their priorities are shit.

Leave a Reply

Your email address will not be published. Required fields are marked *