[Estimated Reading Time: 8 minutes]

A welcome new language feature in Delphi 2010 is the introduction of attributes, as previously found in .NET languages.  However I am slightly disappointed that the language implementation is also very close to that found in C# and other .NET languages and not more in keeping with what I would consider The Spirit Of Delphi.

[Introduction(‘Clarifies perspective’)]

First, do not make the mistake of thinking that I am “anti-attributes” per se.  Not at all.

It is true however that I am skeptical of their real benefit given that the functionality they provide can easily be fabricated without language changes.  This then falls into the category of language features that are nice to have but which don’t provide us with anything we couldn’t already do and in some ways those alternatives have some distinct advantages.

And if we aren’t already doing it some other way then, well, how much benefit is there?  Really? Beyond being able to hold our heads just that little bit higher in the company of our C# and Prism colleagues.

Be that as it may, allow me to explain what I mean when I say that the language implementation, as offered in Delphi 2010, is not in The Spirit Of Delphi.

That Spirit is in my view, simply put, to promote by way of guiding principles in the language, legible, easily read, easily understood and easily maintained code.

A couple of clarifications:

Ease of understanding does not necessarily come from embedding every last detail in one place, but in ensuring that relevant detail is easily locatable and digestible – and with an emphasis on human readability.

Developers are not compilers.  Compilers can be made to understand human meaningful forms far more readily than humans can be made to understand machine readable forms.

And so to my concerns and issues with the attributes implementation as it stands.

Inconsistency

First of all, the Delphi language already had a form of attribute since version 3.0 in the form of the interface GUID.  The syntax is even curiously similar to that for attributes.  Compare and contrast the declaration of a SQLTable attribute in a fictional SQL persistence framework with the declaration of an interface IID:

ICustomer = interface
['{6A831FA8-9203-4334-8094-D7A916417719}']
end;

[SQLTable('CUSTOMER')]
TCustomer = class
end;

The difference should be immediately obvious.  The IID applies to the symbol just defined – the ICustomer interface.  The SQLTable attribute on the other hand applies to the next symbol yet to be defined.  A small difference maybe, but one that niggles, as it sets a pattern that leads to bigger niggles.

I simply cannot see why this decision was made.  When we come to attributes on class members in particular, it would have made far more sense, quite apart from being consistent with the existing IID declaration, which is now going to look very odd as attributes are added to interfaces and interface members:

[SomeAttribute('With some parameter')]
ICustomer = interface
['{6A831FA8-9203-4334-8094-D7A916417719}']
  [AnotherAttribute('But I relate to the NEXT identifier, unlike the IID "attribute" above')]
  procedure SomeInterfaceMethod;
end;

Seeing The Members For The Attributes

In this this example of using Attributes for Validation rules, we start to see the beginnings of the problems that will quickly develop as attributes proliferate in code:
  TPerson = class
  private
    fName: String;
    fAge: Integer;
  public
    [NonEmptyString('Must provide a Name')]
    property Name : String read fName write fName;
    [MinimumInteger(18, 'Must be at least 18 years old')]
    [MaximumInteger(65, 'Must be no older than 65 years')]
    property Age : Integer read fAge write fAge;
  end;

Already the property declarations are harder to read than simple declarations would have been.   There is conflation of business rules – by definition a runtime behaviour – with the simple type declaration introduces “noise” that is likely of little relevance to someone reading the class declaration.

Some people take issue with that, but I really do not see why.

Since such things as Minimum and Maximum age values are by definition a runtime behaviour, varying in the actual constraint from one instance of those attributes to the next, what possible reason would I have to find that of interest in the source code?

So that I might copy the declared min/max values and embed them in my own code?  Of course not.

I interact with those details of the class by interacting with the attributes at runtime.  The design time concern might be the knowledge that the class contains properties decorated with such attributes, but again, my code should be discovering this via the new RTTI mechanisms that support attributes or, more likely, by reference to the architecture documents for the project I am working on.

I, and my code, must know that such attributes might exist and knowing that they do exist by inspecting the source doesn’t alter the fact that I have to write the code to discover whether they exist or not, because between reading the TPerson code and my own code executing against (e.g) a given instance of a TPerson, attributes may be added, changed or removed entirely.

There really is no earthly reason that I can see for these things to be present in the class declaration, other than as a convenience for the compiler (or possibly the compiler writers).

So, back to the problem of clarity being reduced by the introduction of this “noise”.

We could improve things a little by employing some judicious whitespace, but things would have been made even easier if multiple attributes could be declared in a single attribute “block”:

  TPerson = class
  private
    fName: String;
    fAge: Integer;
  public
    [
     NonEmptyString('Must provide a Name');
    ]
    property Name : String read fName write fName;
    [
     MinimumInteger(18, 'Must be at least 18 years old');
     MaximumInteger(65, 'Must be no older than 65 years');
    ]
    property Age : Integer read fAge write fAge;
  end;

Setting aside the fact that we are now forced to introduce whitespace to create “divisions” within an area of “like” code already separated by the whitespace around the visibility specifiers in order to try to make something that was previously quite readable as readable as it was before we introduced additional concerns, unfortunately this is not a valid syntax.

Those Minimum and Maximum attributes have to be declared seperately.  Along with all other attributes relating to the Age property.

For example, with SQL persistence in play, there is likely to be an SQLColumn attribute involved, or similar, and possibly some default value for Age and let us also, for the purposes of my next point, envisage that we wish to simply “tag” both Name and Age as being exposed to some scripting framework within our application:

  [SQLTable('PERSON')]
  TPerson = class
  private
    fName: String;
    fAge: Integer;
  public
    [SQLColumn('NAME')]
    [Scripted()]
    [NonEmptyString('Must provide a Name')]
    property Name : String read fName write fName;

    [Scripted()]
    [DefaultInteger(18)]
    [MinimumInteger(18, 'Must be at least 18 years old')]
    [SQLColumn('AGE')]
    [MaximumInteger(65, 'Must be no older than 65 years')]
    property Age : Integer read fAge write fAge;
  end;

Already I think the problem of attribute proliferation is becoming quite clear or, if not yet at this point, how the problem will quickly accelerate as new attributes are devised for this that and the other purpose. The uses to which attributes can and will be put know almost no bounds.

Unnecessary Utilisation Of Excess Verbiage

The decision to relate attributes to the identifier following the declaration has a huge consequence.  That is, within a class declaration it denies a simple mechanism for declaring an attribute that applies to multiple identifiers.

In the case of our somewhat contrived example previously, it means that each and every property that we wish to expose to our scripting framework has to be tagged with an identical attribute.

If attribute declarations related not to the following identifier, but to the previous, then a simple mechanic for achieving precisely that could have been devised naturally out of the existing syntax for class declarations.  That is, to consider attributes applied to visibility specifiers (private, protected, public, published etc) to apply to all identifiers within the scope of that visibility specifier.  I do not mean “having that level of visibility” but literally the identifiers covered by a specific occurrence of a visibility specifier.

In the case of our contrived example, if we applied all these suggested changes we would have ended up with something like this:

  TPerson = class
  [SQLTable('PERSON')]
  private
    fName: String;
    fAge: Integer;
  public
  [Scripted()]
    property Name : String read fName write fName;
      [SQLColumn('NAME');
       NonEmptyString('Must provide a Name')]

    property Age : Integer read fAge write fAge;
      [DefaultInteger(18)]
       MinimumInteger(18, 'Must be at least 18 years old');
       SQLColumn('AGE');
       MaximumInteger(65, 'Must be no older than 65 years')]
  end;

Quite apart from the fact that this mimics the already present and therefore natural convention of applying “decorators” as a “postfix” to the identifiers to which they relate (e.g. virtual and abstract for methods, default, stored for properties etc – visibility specifiers are the exception that prove the rule), I simply cannot see how anyone could consider that anything but an improvement, given that my efforts to improve legibility in this example is only one of many more possibilities made available by these changes.

Sadly I am sure it is too late to make such a fundamental change to the implementation of attributes, so we are now lumbered with it.

However, there is a further alternative that could be introduced without breaking the current implementation, allowing us to keep attributes separate from the more fundamental aspects of our classes, and improving the clarity of both as a result.

Separation of Concerns

It’s almost as if Embarcadero believe that Separation of Concerns doesn’t apply to Delphi developers.

It has been suggested to me that far from conflation, this is actually an expression of that philosophy. I do not believe that perspective bears close scrutiny and is quickly discredited.

As the uses to which attributes are applied, so the morass of attribute declarations will multiply into a confusion of unrelated declarations, forced by necessity into the same space – co-located with and immediately preceding the thing to which they relate.  The very antithesis of SoC.

What used to be a simple declaration of a type – a class with member data and methods – explodes into a “mash-up” of member data, methods and expressions of business rules relating to SQL persistence, validation and beyond these obvious and common examples we are likely to see attributes relating to XML persistent, logging, scripting interface exposures, help system anchors, documentation, automated testing infrastructure etc etc.

But I do not advocate throwing out the baby along with the bathwater.  Attributes certainly have their place.

What we need is a way to use them sensibly, without cluttering up our class declarations.

A New Unit Section For A New Language Feature

What I propose is no more nor less than an entirely new section for our units, a section that supports a syntax for declaring the attributes that relate to the other contents of our code. I have not designed a complete syntax, but the basic principle will be to identify the entity to which a given set of attribute declarations relates.

The syntax for this section does not need to follow any current rigidly defined Pascal rules as it is an entirely new section type, so could be as simple as a qualified identifier followed by an attribute declaration block:

attributes
  TPerson:              [SQLTable('PERSON')];

  TPerson.Age:          [SQLColumn('AGE');
                         Scripted();
                         DefaultInteger(18);
                         MinimumInteger(18, 'etc');
                         MaximumInteger(65, 'etc')];

  TPerson.Name:         [SQLColumn('NAME');
                         Scripted();
                         NotAnEmptyString('etc')];

Crucially, there need be no restriction on the number of occurences of a given identifier (which must be fully defined at this point in any event), so validation related attributes could be declared entirely separately from SQL persistence related attributes, if desired.

(Interestingly I did not set out specifically to create it in this fashion, but the similarity to style sheets in HTML is striking, and the similarity in intent is also hard to ignore. Form, as they say, follows function)

This mechanism could allow for “tagging” of multiple items by supporting a comma delimited identifier list:

attributes
  TPerson:              [SQLTable('PERSON')];

  TPerson.Age:          [SQLColumn('AGE');
                         DefaultInteger(18);
                         MinimumInteger(18, 'etc');
                         MaximumInteger(65, 'etc')];

  TPerson.Name:         [SQLColumn('NAME');
                         NotAnEmptyString('etc')];

  TPerson.Age,
  TPerson.Name          [Scripted()];

This looks cumbersome to me however, and I’d be inclined to try to find a naturally occuring variation of the syntax to allow the declaration in such instances to be inverted, i.e.

  [Scripted()]:    TPerson.Age, TPerson.Name;

It may even be as simple as that. If an attribute declaration immediately follows the attributes keyword or another attribute declaration then it is considered a multi-identifier.

Perhaps.

I am just spit-balling in this exercise after all.

More generally, an attributes section could follow either the interface or the implementation section (preceding any initialization) and declare attributes for any identifier in scope at that point.  (I shall come back to this)

So a given unit may contain two attributes sections declaring attributes for each of the interface or implementation sections as required, or it may contain only one, declaring attributes for all relevant identifiers in the unit in the implementation attributes section alone.

As a side effect, separating attributes into a dedicated section such as this would surely make life a great deal easier for modelling tools and other code generators.

And if this degree of separation was not sufficient, as a self contained section of a unit these declarations could of course easily be maintained in a $include file.

You Might Want To Sit Down…

Did you see the bit where I suggested attributes sections could declare attributes for any identifier in scope at that point ?

I tossed that in without thinking, as a statement of the obvious, but quickly realised that the implications of that are potentially staggering.

If possible, then this would allow us to define additional attributes for classes that we did not originate!

We could decorate classes with attributes that are meaningful to our applications and code that the original class author/creator could not have anticipated.

Thoughts, Comments, Observations?

You know where to put them (see below).

As usual, all are welcome. 🙂

10 thoughts on “A Vision of Attributes in “The Spirit of Delphi””

  1. Alas, there is a long history of not doing things in the “spirit” of Delphi 🙁

    I almost cried, many years ago, when dynamic arrays where introduced without the ability to specifiy the lower bound of the array…

    I agree that you proposal for attributes as a Postfix item is a lot clearer, but I’m fairly sure the syntax has been “driven” by compatibilty with Prism, and the old Delphi .NET

    While you are working on contrived examples, why not throw in some XMLDoc comments for good measure?

  2. Jolyon,

    Have you considered signing up for the Delphi Field Test so some of these ideas can be aired before implementation decisions are made? Even though I don’t always agree with your positions, you obviously think deeply about them, so that input can only have a positive impact on the product.

    Cheers
    Malcolm

  3. @Alistair: I am sure you are right w.r.t compatability with Prism, which makes it even sadder.

    Prism was born out of a feeling that Borland didn’t quite hit the mark with “The Spirit of Delphi” for .NET but in respect to attributes I think they themselves followed C# too closely and for some reason forgot the Spirit of Delphi themselves.

    And now here we are with a C#-a-like attributes language feature, via Prism.

    But, whilst that may preclude any alteration to the feature as implemented in the language, it should not prevent an extension of the feature along the lines of the “attributes” section that I propose.

    Maybe not for an initial Delphi 2010 release tho, eh? 🙂

    @Malcolm: To be entirely honest I was not convinced that any time spent on a field test would be worthwhile. That may be a self fulfilling prophesy but my experience of making suggestions through the existing channels over the years – community, Quality Central etc – has not been particularly productive in terms of results.

    Plus surely these kinds of things are delivered into a field test more or less fully formed? Involvement during initial design discussions is where these sorts of things are more likely to be changed, and I wouldn’t expect anyone outside of CodeGear to be involved at that stage.

    Perhaps I’m mistaken but I would have thought that by the time it reaches field test I would have thought it’s already too late.

  4. Interesting ideas. I agree that the existing syntax is a bit awkward, and hopefully some of this can get implemented in the “new Delphi syntax” that Nick made such a stir talking about a while back.

    Your last point, though–decorating pre-existing classes with attributes–is quite impossible without rearranging the entire object model. Attributes are stored in packed records within a class’s VMT. Changing it externally would be very problematic, especially trying to change it from a different unit from the one the class was declared in. That would require cracking open an existing DCU and rewriting it.

  5. I did wonder just how possible it would be to add attributes to existing classes.

    But, I would say that designing a syntax that doesn’t allow it because it’s difficult simply creates a situation where even if a mechanism could be found to allow it, the language then has no way to exploit that mechanism. Result: No-one even bothers looking into finding a mechanism.

    And nothing is impossible – it’s just software… we can make it do whatever we want…. within reason. 🙂

    In this case I can already envisage that the system could reserve one of those records to contain a pointer to a more dynamically managed list of additional attributes. Indeed, why does the system not implement attributes with a *single* pointer in the VMT to an attribute table which could then surely grow independently of the VMT itself?

    But I am only a bear of little brain. 🙂

    And “packed” records you say…. does this mean that attribute storage is optimised for space, not access efficiency? Ouch.

    This does make me concerned that performance of code using attributes could indeed suffer, resulting in them becoming practically unusable as they proliferate in a class library.

    Poor performance is the reason that the people I know who started out using them in C# quickly learned to *stop* using them.

  6. That’s a shame, Jolyon, and probably means that we’ll forever get your feedback when it is too late. Some of the best discussions on the field test newsgroups take place before a particular feature has been delivered, while the guys are still designing and implementing.

    Hope you’ll change your mind next time around.

  7. Something definitely worth bearing in mind, but I don’t think it would have made any difference in this case. As Alistair points out, compatibility with Prism would have been a major factor in this particular case.

    I should also have mentioned that as a full time employee (working in environments some number of releases *behind* the current one and not able to use the current, let alone future, releases “in anger” in those environments), and as a family man with other interests outside of software development, I didn’t feel I could give a field test the commitment in time that it likely deserved and needed.

    As I point out in the original post however, this would not prevent an extension of the language feature for the native compiler (I’m guessing that the Prism implementation leverages, and is therefore somewhat hamstrung by, the underlying CLR implementation).

    But a native compiler specific extension, simultaneously supporting the Prism syntax, could be as a achievable now as it would have been had I suggested it during the field test.

    It has also occurred to me that something along the lines I suggested (an attributes section, able to “decorate” arbitrary identifiers) could be a step toward some form of Aspects support in Delphi. Not in the sense that Aspects could be implemente as or using Attributes, but that it might establish a syntax precedent that Aspects could also take advantage of (with further modification/extension).

  8. Thanks to Stefan Glienke’s DSharp we now got a utilizable form of aspects — using attributes. My attempts with it look promising, and even with the restrictions related to what is possible with VMT manipulation I’m willing to give it a shot in production code. Looks like aspects take the set notation of attributes… for now…

Comments are closed.