Welcome to Atalasoft Community Sign in | Help

C# Wish --or-- How I Love to Hate Thee: Property

I really want this syntax in C# (informal BNF):

getset-declaration := <access-specifier><other-decorations><type><getset-token><publishedname> <initializer>; |
<access-specifier><other-decorations><type><getsettoken><publishedname>(privatename) <initializer>;
access-specifier := public | protected | private
getset-token := getter | setter | getset
published-name := identifier
private-name := identifier

What this means is that the declaration:

public int getset Age(_age) = 0;

is syntactically equivalent to:

private int _age = 0;
public int Value { get { return _age; } set { _age = value; } }

and the declaration:

public string getter Name = "Atalasoft";

is syntactically equivalent to:

private string _Name = "Atalasoft";
public string Name { get { return _Name; } }


Admittedly, this is syntactic sugar, but it does a really nice thing for me as a programmer: it takes a common syntactic pattern and turns it into something that is easy to work with and will reduce errors.  Specifically, if I need to change the type of this property, it happens in exactly one place instead of two.  If I have to change the name, I also get a benefit of only really having to change it in one place.

The bad news is that the IL for a typical setter doesn't get inlined in the release build.  The good news is that the JIT compiler does that for you (but only in release).  Still, shouldn't this type of trivial property be auto-inlined within an assembly?  At the very least, it makes writing the JIT easier.

Here's a chunk of code that makes an object and sets a property within it:

            MyProperties props = new MyProperties();
            props.Foo = 45;

Here's the IL:
// construct the object
  IL_0000:  newobj     instance void PropertyAnalysis.MyProperties::.ctor()
// pop the stack store it in local variable 0 (ie, props)
  IL_0005:  stloc.0
// push local variable 0 on the stack
  IL_0006:  ldloc.0
// push a 45
  IL_0007:  ldc.i4.s   45
// call the setter
  IL_0009:  callvirt   instance void PropertyAnalysis.MyProperties::set_Foo(int32)

Here's the JIT compiled version of that code in release mode:

// push the class pointer
00000000  mov         ecx,0A053D0h
// call the object allocator
00000005  call        FDBD1F98
// this looks like it's part of System.Object
0000000a  mov         dword ptr [eax+4],0
// inlined field initializer for the class variable
00000011  mov         dword ptr [eax+8],0
// set the field to 45 (2d in hex)
00000018  mov         dword ptr [eax+8],2Dh

Other than setting the field twice in a row (a peep-hole optimizer should do this for you), it's not bad code, but I can't imagine how hard it had to work to get here.  If the IL had been inlined, this should've been an easier task.  Easier JIT compiling means a less-complicated compiler, which typically means fewer bugs.  It also means that in a pure interpretive environment (ie, you're not running a JIT compiler because, say, you don't have the resources), it will run faster anyway.

Another benefit of the inlining is that it becomes easier to do static analysis of this code.  At a minimum, this object should be allocated on the stack and not from the heap since there are no references to it when the function exits.  An extreme optimizer should pretty much no-op this whole thing, since it doesn't actually do anything, and that's determinable at compile time.  You laugh, but I've seen the output of really heavyweight optimizers for C that do that level of work.  Why shouldn't I expect that standard in other production tools?

Now, I really like the notion of properties.  It's a fairly nice way to express the set/get pattern and to be able to insulate calling code from the internal details, and to make the code look good.

The problem I have with properties is the same problem I have with operator overload and some other OOP features: they give the illusion of being cheap, when in reality they can be very expensive.  In the debug build of the typical property, the cost of property access is pretty dang high - even when you're using a release build of an assembly from within a debug project, since the JIT is affected by your project's debug/release settings, and not by those of external assemblies being JIT compiled.

You hope that the property you're accessing will be cheap, but there's no way to tell from your code.  I was adding a feature to some code that queried a capability of a COM object and reported it back to the user.  It was about as straightforward as you'd like it to be:
public bool SupportsSpecialOutput {
   get {
        int settingsFlags = myComObject.QuerySettings();
        return (settingsFlags & OutputCapabilities.SpecialMask) != 0;
   }
}
It turned out that QuerySettings() was very expensive - on the order of a second.  Had I left this code as is, clients would be horrified by the cost.

Another thing to keep in mind is that access to a property or class may have unintended side-effects.  My favorite war story had to do with a C++ class that allocated memory in its constructor.  It was being used like this:
void InteruptServiceRoutine()
{
    SomeVeryBadClass myVariable;
    myVariable.PerformSomeImportantTask();
}
the problem was that the allocation in the default constructor was being performed transparently and once in a while it would destroy the heap since allocation/freeing from the general heap is verbotten at interrupt time.  Since this would only happen if there was an incomplete heap operation in progress, it was a "once in a blue moon" bug, which quickly turned into a nightmare to track down.
Published Thursday, August 31, 2006 1:57 PM by Steve Hawley

Comments

No Comments
Anonymous comments are disabled