{"id":484,"date":"2009-08-25T13:34:06","date_gmt":"2009-08-25T01:34:06","guid":{"rendered":"https:\/\/www.deltics.co.nz\/blog\/?p=484"},"modified":"2012-04-30T15:05:37","modified_gmt":"2012-04-30T03:05:37","slug":"a-vision-of-attributes-in-the-spirit-of-delphi","status":"publish","type":"post","link":"https:\/\/www.deltics.co.nz\/blog\/posts\/484\/","title":{"rendered":"A Vision of Attributes in &#8220;The Spirit of Delphi&#8221;"},"content":{"rendered":"<span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\">8<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span><p>A welcome new language feature in <a title=\"Delphi 2010\" href=\"http:\/\/etnaweb04.embarcadero.com\/rad-studio-2010\" target=\"_blank\">Delphi 2010<\/a> is the introduction of <a title=\"attributes\" href=\"http:\/\/www.malcolmgroves.com\/blog\/?p=476\" target=\"_blank\">attributes<\/a>, as previously found in .NET languages. &nbsp;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 <strong><em>The Spirit Of Delphi<\/em><\/strong>.<\/p>\n<p><!--more--><\/p>\n<h2>[Introduction(&#8216;Clarifies perspective&#8217;)]<\/h2>\n<p>First, do not make the mistake of thinking that I am &#8220;anti-attributes&#8221; per se. &nbsp;Not at all.<\/p>\n<p>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. &nbsp;This then falls into the category of language features that are nice to have but which don&#8217;t provide us with anything we couldn&#8217;t already do and in some ways those alternatives have some distinct advantages.<\/p>\n<p>And if we aren&#8217;t already doing it some other way then, well, how much benefit is there? &nbsp;Really?  Beyond being able to hold our heads just that little bit higher in the company of our C# and Prism colleagues.<\/p>\n<p>Be that as it may, allow me to explain what I mean when I say that the language implementation, as offered in <strong>Delphi 2010<\/strong>, is not in <strong><em>The Spirit Of Delphi<\/em><\/strong>.<\/p>\n<p>That <strong>Spirit<\/strong> is&nbsp;in my view, simply put, to promote by way of guiding principles in the language, legible, easily read, easily understood and easily maintained code.<\/p>\n<p>A couple of clarifications:<\/p>\n<p>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 &#8211; and with an emphasis on human readability.<\/p>\n<p>Developers are not compilers. &nbsp;Compilers can be made to understand human meaningful forms far more readily than humans can be made to understand machine readable forms.<\/p>\n<p>And so to my concerns and issues with the attributes implementation as it stands.<\/p>\n<h2>Inconsistency<\/h2>\n<p>First of all, the Delphi language already had a form of attribute since version 3.0 in the form of the interface GUID. &nbsp;The syntax is even curiously similar to that for attributes. &nbsp;Compare and contrast the declaration of a <strong>SQLTable<\/strong> attribute in a fictional SQL persistence framework with the declaration of an interface IID:<\/p>\n<pre class=\"delphi\">ICustomer = interface\r\n['{6A831FA8-9203-4334-8094-D7A916417719}']\r\nend;\r\n\r\n[SQLTable('CUSTOMER')]\r\nTCustomer = class\r\nend;<\/pre>\n<p>The difference should be immediately obvious. &nbsp;The IID applies to the symbol just defined &#8211; the <strong>ICustomer<\/strong> interface. &nbsp;The <strong>SQLTable<\/strong> attribute on the other hand applies to the next symbol <em>yet to be defined<\/em>. &nbsp;A small difference maybe, but one that niggles, as it sets a pattern that leads to bigger niggles.<\/p>\n<p>I simply cannot see why this decision was made. &nbsp;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:<\/p>\n<pre class=\"delphi\">[SomeAttribute('With some parameter')]\r\nICustomer = interface\r\n['{6A831FA8-9203-4334-8094-D7A916417719}']\r\n  [AnotherAttribute('But I relate to the NEXT identifier, unlike the IID \"attribute\" above')]\r\n  procedure SomeInterfaceMethod;\r\nend;<\/pre>\n<h2><strong>Seeing The Members For The Attributes<\/strong><\/h2>\n<div>In this&nbsp;<a title=\"Validation\" href=\"http:\/\/www.malcolmgroves.com\/blog\/?p=530\" target=\"_blank\">this example of using Attributes for Validation<\/a> rules, we start to see the beginnings of the problems that will quickly develop as attributes proliferate in code:<\/div>\n<pre class=\"delphi\">  TPerson = class\r\n  private\r\n    fName: String;\r\n    fAge: Integer;\r\n  public\r\n    [NonEmptyString('Must provide a Name')]\r\n    property Name : String read fName write fName;\r\n    [MinimumInteger(18, 'Must be at least 18 years old')]\r\n    [MaximumInteger(65, 'Must be no older than 65 years')]\r\n    property Age : Integer read fAge write fAge;\r\n  end;<\/pre>\n<p>Already the property declarations are harder to read than simple declarations would have been. &nbsp; There is conflation of business rules &#8211; by definition a <span style=\"text-decoration: underline;\">runtime<\/span> behaviour &#8211; with the simple type declaration introduces &#8220;noise&#8221; that is likely of little relevance to someone reading the class declaration.<\/p>\n<p>Some people take issue with that, but I really do not see why.<\/p>\n<p>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?<\/p>\n<p>So that I might copy the declared min\/max values and embed them in my own code? &nbsp;Of course not.<\/p>\n<p>I interact with those details of the class by interacting with the attributes at runtime. &nbsp;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.<\/p>\n<p>I, and my code, must know that such attributes <span style=\"text-decoration: underline;\">might<\/span> exist and knowing that they <span style=\"text-decoration: underline;\">do<\/span> exist by inspecting the source doesn&#8217;t alter the fact that I have to write the code to discover whether they exist or not, because between reading the <strong>TPerson<\/strong> code and my own code executing against (e.g) a given instance of a <strong>TPerson<\/strong>, attributes may be added, changed or removed entirely.<\/p>\n<p>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 <span style=\"text-decoration: underline;\">for the compiler<\/span> (or possibly the compiler <em>writers<\/em>).<\/p>\n<p>So, back to the problem of clarity being reduced by the introduction of this &#8220;noise&#8221;.<\/p>\n<p>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 &#8220;block&#8221;:<\/p>\n<pre class=\"delphi\">  TPerson = class\r\n  private\r\n    fName: String;\r\n    fAge: Integer;\r\n  public\r\n    [\r\n     NonEmptyString('Must provide a Name');\r\n    ]\r\n    property Name : String read fName write fName;\r\n    [\r\n     MinimumInteger(18, 'Must be at least 18 years old');\r\n     MaximumInteger(65, 'Must be no older than 65 years');\r\n    ]\r\n    property Age : Integer read fAge write fAge;\r\n  end;<\/pre>\n<p>Setting aside the fact that we are now forced to introduce whitespace to create &#8220;divisions&#8221; within an area of &#8220;like&#8221; 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.<\/p>\n<p>Those <strong>Minimum <\/strong>and <strong>Maximum <\/strong>attributes have to be declared seperately. &nbsp;Along with <strong><span style=\"text-decoration: underline;\"><em>all<\/em><\/span><\/strong> other attributes relating to the <strong>Age<\/strong> property.<\/p>\n<p>For example, with SQL persistence in play, there is likely to be an <strong>SQLColumn<\/strong> attribute involved, or similar, and possibly some default value for <strong>Age<\/strong> and let us also, for the purposes of my next point, envisage that we wish to simply &#8220;tag&#8221; both <strong>Name<\/strong> and <strong>Age<\/strong> as being exposed to some scripting framework within our application:<\/p>\n<pre class=\"delphi\">  [SQLTable('PERSON')]\r\n  TPerson = class\r\n  private\r\n    fName: String;\r\n    fAge: Integer;\r\n  public\r\n    [SQLColumn('NAME')]\r\n    [Scripted()]\r\n    [NonEmptyString('Must provide a Name')]\r\n    property Name : String read fName write fName;\r\n\r\n    [Scripted()]\r\n    [DefaultInteger(18)]\r\n    [MinimumInteger(18, 'Must be at least 18 years old')]\r\n    [SQLColumn('AGE')]\r\n    [MaximumInteger(65, 'Must be no older than 65 years')]\r\n    property Age : Integer read fAge write fAge;\r\n  end;<\/pre>\n<p>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.<\/p>\n<h2>Unnecessary Utilisation Of Excess Verbiage<\/h2>\n<p>The decision to relate attributes to the identifier following the declaration has a huge consequence. &nbsp;That is, within a class declaration it denies a simple mechanism for declaring an attribute that applies to multiple identifiers.<\/p>\n<p>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.<\/p>\n<p>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. &nbsp;That is, to consider attributes applied to <span style=\"text-decoration: underline;\">visibility specifiers<\/span> (private, protected, public, published etc) to apply to all identifiers within the scope of that <span style=\"text-decoration: underline;\">visibility specifier<\/span>. &nbsp;I do not mean &#8220;having that level of visibility&#8221; but literally the identifiers covered by a specific occurrence of a visibility specifier.<\/p>\n<p>In the case of our contrived example, if we applied all these suggested changes we would have ended up with something like this:<\/p>\n<pre class=\"delphi\">  TPerson = class\r\n  [SQLTable('PERSON')]\r\n  private\r\n    fName: String;\r\n    fAge: Integer;\r\n  public\r\n  [Scripted()]\r\n    property Name : String read fName write fName;\r\n      [SQLColumn('NAME');\r\n       NonEmptyString('Must provide a Name')]\r\n\r\n    property Age : Integer read fAge write fAge;\r\n      [DefaultInteger(18)]\r\n       MinimumInteger(18, 'Must be at least 18 years old');\r\n       SQLColumn('AGE');\r\n       MaximumInteger(65, 'Must be no older than 65 years')]\r\n  end;<\/pre>\n<p>Quite apart from the fact that this mimics the already present and therefore natural convention of applying &#8220;decorators&#8221; as a &#8220;postfix&#8221; to the identifiers to which they relate (e.g. virtual and abstract for methods, default, stored for properties etc &#8211; 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.<\/p>\n<p>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.<\/p>\n<p>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.<\/p>\n<h2>Separation of Concerns<\/h2>\n<p>It&#8217;s almost as if Embarcadero believe that <a href=\"http:\/\/en.wikipedia.org\/wiki\/Separation_of_concerns\" target=\"_blank\">Separation of Concerns<\/a> doesn&#8217;t apply to Delphi developers.<\/p>\n<p>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.<\/p>\n<p>As the uses to which attributes are applied, so the morass of attribute declarations will multiply into a confusion of <strong><em>un<\/em><\/strong><em>related<\/em> declarations, forced by necessity into the same space &#8211; co-located with and immediately preceding the thing to which they relate. &nbsp;The very antithesis of <strong>SoC<\/strong>.<\/p>\n<p>What used to be a simple declaration of a type &#8211; a class with member data and methods &#8211; explodes into a &#8220;mash-up&#8221; 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.<\/p>\n<p>But I do not advocate throwing out the baby along with the bathwater. &nbsp;Attributes certainly have their place.<\/p>\n<p>What we need is a way to use them sensibly, without cluttering up our class declarations.<\/p>\n<h2>A New Unit Section For A New Language Feature<\/h2>\n<p>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.<\/p>\n<p>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:<\/p>\n<pre class=\"delphi\">attributes\r\n  TPerson:              [SQLTable('PERSON')];\r\n\r\n  TPerson.Age:          [SQLColumn('AGE');\r\n                         Scripted();\r\n                         DefaultInteger(18);\r\n                         MinimumInteger(18, 'etc');\r\n                         MaximumInteger(65, 'etc')];\r\n\r\n  TPerson.Name:         [SQLColumn('NAME');\r\n                         Scripted();\r\n                         NotAnEmptyString('etc')];<\/pre>\n<p>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.<\/p>\n<p>(<em>Interestingly <\/em><em>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<\/em>)<\/p>\n<p>This mechanism could allow for &#8220;tagging&#8221; of multiple items by supporting a comma delimited identifier list:<\/p>\n<pre class=\"delphi\">attributes\r\n  TPerson:              [SQLTable('PERSON')];\r\n\r\n  TPerson.Age:          [SQLColumn('AGE');\r\n                         DefaultInteger(18);\r\n                         MinimumInteger(18, 'etc');\r\n                         MaximumInteger(65, 'etc')];\r\n\r\n  TPerson.Name:         [SQLColumn('NAME');\r\n                         NotAnEmptyString('etc')];\r\n\r\n  TPerson.Age,\r\n  TPerson.Name          [Scripted()];<\/pre>\n<p>This looks cumbersome to me however, and I&#8217;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.<\/p>\n<pre class=\"delphi\">  [Scripted()]:    TPerson.Age, TPerson.Name;<\/pre>\n<p>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.<\/p>\n<p>Perhaps.<\/p>\n<p>I am just spit-balling in this exercise after all.<\/p>\n<p>More generally, an <strong>attributes<\/strong> section could follow either the <strong>interface<\/strong> or the <strong>implementation<\/strong> section (preceding any&nbsp;<strong>initialization<\/strong>) and <em><span style=\"text-decoration: underline;\">declare attributes for any identifier in scope at that point<\/span><\/em>. &nbsp;(I shall come back to this)<\/p>\n<p>So a given unit may contain two <strong>attributes<\/strong> sections declaring attributes for each of the <strong>interface<\/strong> or <strong>implementation<\/strong> sections as required, or it may contain only one, declaring attributes for all relevant identifiers in the unit in the <strong>implementation attributes<\/strong> section alone.<\/p>\n<p>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.<\/p>\n<p>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 <strong>$<\/strong><strong>include file<\/strong>.<\/p>\n<h2>You Might Want To Sit Down&#8230;<\/h2>\n<p>Did you see the bit where I suggested attributes sections could <em>declare attributes for any identifier in scope at that point<\/em> ?<\/p>\n<p>I tossed that in without thinking, as a statement of the obvious, but quickly realised that the implications of that are potentially staggering.<\/p>\n<p>If possible, then this would allow us to define additional attributes for classes that <em>we did not originate<\/em>!<\/p>\n<p>We could decorate classes with attributes that are meaningful to our applications and code that <em>the original class author\/creator could not have anticipated<\/em>.<\/p>\n<h2>Thoughts, Comments, Observations?<\/h2>\n<p>You know where to put them (see below).<\/p>\n<p>As usual, all are welcome. \ud83d\ude42<\/p>\n","protected":false},"excerpt":{"rendered":"<p><span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\">8<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span> A welcome new language feature in Delphi 2010 is the introduction of attributes, as previously found in .NET languages. &nbsp;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.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":[]},"categories":[4],"tags":[79,292,13,127,145,78],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p1TKYv-7O","jetpack_sharing_enabled":true,"jetpack-related-posts":[{"id":847,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/847\/","url_meta":{"origin":484,"position":0},"title":"Nested Types in the &#8220;Spirit of Delphi&#8221;","date":"30 Apr 2012","format":false,"excerpt":"I have posted before about new language features introduced in a way that does not adhere to the (admittedly quite notional) \"Spirit of Delphi\". It's time for another one, this time inspired by a post by Paul Klink of the ADUG. In his post, Paul makes the following observation: The\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":498,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/498\/","url_meta":{"origin":484,"position":1},"title":"[tap][tap] Is this thing working?","date":"29 Aug 2009","format":false,"excerpt":"For some reason my two most recent posts don't seem to have been picked up by the DelphiFeeds aggregator. \u00a0Apologise to anyone who found my posts by other means. \u00a0I wouldn't normally be bothered except that I thought that those two posts were worth some attention. The first is a\u2026","rel":"","context":"In &quot;Blogging&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":2624,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2624\/","url_meta":{"origin":484,"position":2},"title":"Expressive If and Case &#8230;","date":"25 Apr 2017","format":false,"excerpt":"A quick post on a small but hugely useful little language feature in Oxygene... if expressions. Many people will be familiar with the so-called ternary operator. Delphi developers will also be aware that there is no direct equivalent in Delphi. In 'C' and other languages we can write a statement\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1207,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/1207\/","url_meta":{"origin":484,"position":3},"title":"Adventures in Syntax: Something Old, Something New etc&#8230;","date":"20 Sep 2012","format":false,"excerpt":"As the post title says, this will be a brief detour through some features of the Pascal language and a presentation of some (theoretical) alternatives that could have been introduced instead. That is, some are real but little known syntax, others are what I think might be preferable to the\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1224,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/1224\/","url_meta":{"origin":484,"position":4},"title":"Sugary Goodness in &#8220;Nougat&#8221;","date":"13 Sep 2012","format":false,"excerpt":"Continuing the theme of recent - and upcoming - posts about new (and not so new) syntax in modern (and not so modern) variations on the Pascal language, I just have to comment on what I regard as yet another stunningly good job that the guys at RemObjects have done\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":220,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/220\/","url_meta":{"origin":484,"position":5},"title":"Poll Time Again","date":"23 Aug 2008","format":false,"excerpt":"With Delphi 2009 literally just around the corner, I thought it would be interesting to see how it's impending release is being viewed. As a result, the poll answers are a little wordy this week for which I apologise, but I thought it would be interesting to try and gauge\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"_links":{"self":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/484"}],"collection":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/comments?post=484"}],"version-history":[{"count":13,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/484\/revisions"}],"predecessor-version":[{"id":858,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/484\/revisions\/858"}],"wp:attachment":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/media?parent=484"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/categories?post=484"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/tags?post=484"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}