Why don’t we have this?

There’s been a lot of talk in the last few years about major language features that Delphi doesn’t have.  Stuff like Unicode and Generics which finally got added in D2009, stuff like 64-bit compilation that’s perenially slated for another year or two out, and so on.  There’s currently a major debate going on (and on and on) in the Delphi forums about the team’s statement that the next release won’t include inline assembly, and the effects that that will or won’t have on library compatibility and future development.

But there are also more minor, simple things that we don’t have, and some of them are a little bit silly.
For example, what’s wrong with this code?

[code lang="Delphi"]
const NAMES: array[0..3] of string = ('Alice', 'Bob', 'Catherine');
[/code]

Well, that’s pretty simple, actually.  In case you don’t immediately notice the issue, the compiler will point it out to you the instant you try to build:

[DCC Error] E2072 Number of elements (3) differs from declaration (4)

So we see that the Delphi compiler is perfectly capable of correctly counting the number of elements declared in a const array, and of giving you an error if that number is not the same as the number of elements you declared that you were going to put in the array.

Which brings me to my question.  Since the compiler is capable of correctly counting the number of elements you put there, and since the concept of dynamic arrays exists in Delphi, wherein you’re not required to declare a size upfront, why won’t this compile?

[code lang="Delphi"]
const NAMES: array of string = ('Alice', 'Bob', 'Catherine');
[/code]

Can someone give me a good reason why?  Because I really can’t think of one.  We’re not introducing any new syntax into the language; “array of” has been around for years.  And in situations where you’ve got long arrays of const records that need to be updated frequently, (something I’ve dealt with both at work and in personal projects,) having the compiler use its built-in array-element-counting skills for you instead of against you would be very nice.

As long as you don’t need the first element’s index to be something other than 0, there’s really no point in having to repeat the same information (the upper bound) twice, once as a number and once as an inherent part of the list of elements.  That’s a bit of a DRY principle violation there, and it’s painful for exactly the reason they came up with the DRY principle in the first place: because when you change one of the two, you have to change the other one too or else it breaks.

So does anyone know why this doesn’t work yet?

10 Comments

  1. Anonymous says:

    […] nachvollziehen, weil hier nicht auf eine Google-Adresse verlinkt wurde, aber hier der Artikel: http://tech.turbu-rpg.com/236/why-dont-we-have-this Philip […]

  2. Jolyon Smith says:

    The answer is quite simple imho.

    “array of string” declares a *dynamic* array of string elements. A “constant dynamic” array is an oxymoron.

    You are either declaring a constant array, which by definition is not dynamic, or you are declaring a dynamic array, which by definition is not constant.

    The confusion arises here because you are treating the lack of dimensions in one case (constant) as an omission that you expect the compiler to complete on your behalf, whilst in the other case (variable) it fundamentally changes the type of the thing you are declaring.

    It could be argued that since a dynamic array cannot be constant, that where this syntax is encountered in a constant declaration that the compiler should regard it as a different form of type. But that could equally be argued against as introducing an ambiguity and inconsistency in the language.

    Ambiguity: Did you mean to declare a constant array with no bounds, or did you simply forget to put bounds on the constant array ?

    Inconsistency:

    const a: array of String = … ; // SetLength(a) cannot be allowed
    var a: array of String; // SetLength(a) IS allowed

    NOTE: the apparent equivalent inconsistency that already exists between variables of a given type and constants of the same type is not actually an inconsistency at all…

    var a: Integer; // a := xxx is allowed
    const a: Integer = 1; // a := xxx IS also allowed (*)

    (*)unless you have specifically made typed-constants non-rewritable, but even then a typed constant is still not considered a TRUE constant (cannot be used in CASE statements, for example).

    An alternative solution to this problem might be to allow variables to be initialised as part of their declaration.

    In any event, I think the problem you have picked on is just the tip of a much bigger set of issues surrounding constants in Delphi, in particular with TYPED constants (not being allowed to use them in CASE statements is my biggest bug bear).

  3. Clóvis Valadares says:

    With Delphi, we live to make a dumb compiler happy.

    • Jolyon Smith says:

      With Delphi the straightforward (not dumb) compiler makes US happy, because we cannot make stupid mistakes, and humans are incredibly fond of being stupid:

      if a = b or b = c then

      Many “smart” compilers will happily take this code. Delphi requires US to know what we are doing, which is good, because it means that when we come back to our code later, we too can see what we were doing.

  4. Kryvich says:

    A constant array is located in a data segment, while a dynamic one is in the heap. Dynamic array demands different access methods and a different memory management.

  5. Thorsten says:

    Having a “constant dynamic array” in the data segment would be no problem. In the same way as you can have string constants. Reference count would simply be -1 in that case.

  6. LDS says:

    I would suggest:

    var
    Numbers: array[] of integer = (1, 2, 3); // static array, size computed as [0..x] at compile time, initialized
    Names: array of string = (‘1’, ‘2’, ‘3’); // dynamic array, length set at initialization, initialized

    that should resolve the ambiguity “array of”, static or dynamic?

    and maybe

    const
    Numbers: array[] of integer = (1, 2, 3); // allowed
    Names: array of string = (‘1’, ‘2’, ‘3’); // not allowed

    • LDS says:

      I submitted this idea as QC #89675 (just the “array[] of” syntax)

      • Jolyon Smith says:

        Nice, but I would go further and make it:

        numbers: array[*} of integer = (1, 2, 3);

        Or substitute ? for *… but require *something* that makes it explicit that the dimension is specifically dynamic/calculated, rather then simply omitted (potentially) by accident.

  7. […] Generics support.  Could it be that Embarcadero is finally adding proper Generics collapsing and improved constant array initialization, like I’ve been wanting for years?  That second one may not seem like much, but it can make […]