Delphi version 7 WTF



  • <font size="3"><font face="Verdana">My work is almost completely a Delphi7 + SQL Server shop, and I've been having fun learning Delphi since I started here. I often encounter little wtfs in the language.

    I think this one is a fine example of what's wrong with Delphi.</font>

    <font face="Courier New">// procedures can accept arrays as parameters
    procedure doSomething( list : array of string);
    </font>
    <font face="Courier New">
    begin
        // whatever

    end;

    procedure Main;
    var
        bob : array of string;   // here's a normal array
        bobsquared : array of array of string;  // here's a multidimensional array
    begin
        doSomething(bob);  // you can pass arrays to procedures

    end;

    // but procedures CANNOT accept multidimensional arrays as parameters!! WHY NOT??
    </font><font face="Courier New">
    procedure doSomethingElse( listsquared : array of array of string); // this does not compile!!
    begin
        // whatever
    end;</font>

    <font face="Georgia"><font face="Verdana">Why is passing an array of array ANY different to passing an array of anything else? An array should just be a pointer to a structure containing data about the array, including a pointer to some memory where the elements are held. If those elements happen to be pointers to more arrays - so what?

    Delphi just feels hacked together, as if someone just started coding without doing any design work.</font>
    </font>

    </font>





  • Actually, Delphi is a very mature and robust language, designed by Anders Hejlsberg, the same architect of Turbo Pascal, C#, and other frameworks.  The problem that you are seeing is not a deficiency of Delphi, but a misunderstanding of how it works.  An array is an intrinsic data structure, but a multi-dimensional array is not, and is treated as an anonymous user defined data structure, therefore they are different.  It is not strictly an array of pointers, even if it is implemented as such at the lowest levels.  You could, of course, create an array of pointers and it will work just fine, but then you'll have to typecast or dereference the items yourself manually.

    You can easily make it work by just creating a named type and using that in the function declaration.

        dZ.



  • Well yes, there are workarounds. What I ended up doing was using an array of TStringLists.
    My point is, it should have been so much simpler.



  • @phithe said:

    Well yes, there are workarounds. What I ended up doing was using an array of TStringLists.
    My point is, it should have been so much simpler.




    Yeah meddling with pointers is soooo much more simpler, and so less bug prone...



  • I think that people have discovered that Pascal is what's wrong with Delphi.



  • @HitScan said:

    I think that people have discovered that Pascal is what's wrong with Delphi.


    And why would you think that? Delphi's Object Pascal is very well designed. I can do almost anything
    with it that you can do with any other language (including C++, with the exception of multiple inheritance; with Delphi 7 it would also include operator overloading, but you can do that with Delphi 2006).

    If the reason is simply because "it's Pascal", you need to think again.



  • No, the thing that's wrong with Delphi is Borland.  Now I'm developing Swing apps in Java, I really miss the productivity of Delphi.  But I don't miss the career dead-end it always threatens to be.



  • @JohnAdams said:

    No, the thing that's wrong with Delphi is Borland.  Now I'm developing Swing apps in Java, I really miss the productivity of Delphi.  But I don't miss the career dead-end it always threatens to be.


    But not for long... Borland is selling off their IDE business. It's in the due-diligence process now, and
    most of the big names from Delphi's past are going with it.



  • @JohnAdams said:

    No, the thing that's wrong with Delphi is Borland.  Now I'm developing Swing apps in Java, I really miss the productivity of Delphi.  But I don't miss the career dead-end it always threatens to be.

    Career dead end?  Its exactly because of Delphi's productivity that my company has been able to compete with larger competitors.  Hardy a dead-end.



  • @zamies said:

    @phithe said:
    Well yes, there are workarounds. What I ended up doing was using an array of TStringLists.
    My point is, it should have been so much simpler.




    Yeah meddling with pointers is soooo much more simpler, and so less bug prone...


    I didn't say anything about meddling with pointers. If I can pass an "array of string", why can't I pass an "array of array of string"? The syntax implies there is no difference.
    I don't want to, and shouldn't have to know how Delphi implements these things under the hood.



  • @phithe said:

    <FONT size=3><FONT face=Verdana>My work is almost completely a Delphi7 + SQL Server shop, and I've been having fun learning Delphi since I started here. I often encounter little wtfs in the language.

    I think this one is a fine example of what's wrong with Delphi.</FONT>
    (...)
    </FONT>

    Delphi (read: Pascal) has type definitions and type specifications. When you declare a variable or a parameter you use a type specification; when you declare a type, it's a definition. Type specifications of types not previously defined generate independent types on the spot and are therefore incompatible (that's why two variables declared as "array of <type>" are not assignment-compatible; even though they are the same in memory, they are *not* of the same type). Pascal is a very strongly-typed language.

    Incidentally a type specification of "array of <type>" in a routine declaration is an open array, and there are no multidimensional open arrays. Delphi has static arrays (fixed bounds), dynamic arrays (limited only by available memory in length and dimensions), open arrays (created/destroyed at the call site to the routine; only one dimension), and variant arrays (variables of type Variant), and they are rarely compatible.

    In your example you could solve everything by declaring a multidimensional array type, and then using that in your variable and procedure declarations:

    type
       StringArray = array of string;
       StringArray2D = array of StringArray;

    procedure doSomething(list: StringArray);
    (...)

    procedure Main;
    var bob: StringArray;
    var bobsquared: StringArray2D;
    begin
       doSomething(bob);
       (...)

    procedure doSomethingElse(listsquared: StringArray2D);
    (...)

    Yours is clearly a case of not RTFM.

    P.S.: This forum's editor is simply atrocious.



  • Fair point, and I don't dispute it.  But I said 'threatens!'  If you think though how Borland/Inprise/Borland/Whoever staggered through the nineties and noughties alternatively hyping Delphi, then burying it, Enterprising it and .NETifying,  you can't disagree that it's been a bit hairy for developers who nailed their colours to its mast. 



  • Well, I did RTFM, and I found a solution - I used an array of TStrings. And I realise I could define a type to do it.

    My point is, if "procedure foo(array of bar)" works, and "var array of array of bar" works, then logically,  "procedure foo(array of array of bar)" SHOULD work.

    Alternatively, the syntax should be changed to reflect the different types of arrays under the hood.

    Also:

    that's why two variables declared as "array of <type>" are not
    assignment-compatible; even though they are the same in memory, they
    are not of the same type). Pascal is a very strongly-typed language.
    Wow. This is even more WTF. I wrote some code to test that out. Check it out:<font face="Courier New">
    var
        a : array of string;      // these two are
        b : array of string;      // not assignment-compatible, but
        c, d : array of string;      // these two ARE assignment compatible</font>

    Awesome.



  • @bah said:


    Delphi (read: Pascal) has type definitions and type specifications. When you declare a variable or a parameter you use a type specification; when you declare a type, it's a definition. Type specifications of types not previously defined generate independent types on the spot and are therefore incompatible (that's why two variables declared as "array of <type>" are not assignment-compatible;

    In C++ you might run into the exact opposite problem, e.g. if you've created two typedefs based on the same type and then want to create two overloaded versions of a function, with those two "different" typedef'ed types making all the difference between the two overloaded versions of the function, the compiler will complain because those two types are essentially the same type:

    <FONT face="Courier New" size=2>bash-3.00$ cat dailywtf.c++
    #include <vector></FONT>

    <FONT face="Courier New" size=2>class bar {};</FONT>

    <FONT face="Courier New" size=2>typedef std::vector<std::vector<bar> > foo0;
    typedef std::vector<std::vector<bar> > foo1;</FONT>

    <FONT face="Courier New" size=2>void OverloadedFunc(const foo0& arg)    {}
    void OverloadedFunc(const foo1& arg)    {}
    bash-3.00$ c++ -o dailywtf dailywtf.c++
    dailywtf.c++: In function `void OverloadedFunc(const foo1&)':
    dailywtf.c++:9: error: redefinition of `void OverloadedFunc(const foo1&)'
    dailywtf.c++:8: error: `void OverloadedFunc(const foo0&)' previously defined here
    bash-3.00$</FONT>

    So, whatever the language designers chose to offer or not to offer, you'll probably run into a situation at some point where it's exactly what you didn't need.



  • @KenW said:

    @JohnAdams said:
    No, the thing that's wrong with Delphi is Borland.
    But not for long... Borland is selling off their IDE business. It's in the due-diligence process now, and
    most of the big names from Delphi's past are going with it.

    Another (management) WTF here is that their reasoning is that they want to do Application Lifecycle Management.  So an application's development is not part of its lifecycle?

    These days, applications do not need to be developed anymore, because they are somehow self-developing?



  • @phithe said:


    My point is, it should have been so much simpler.


    hmm, I don't think you understood the response you got.  You can't ever pass an anonymous type to a procedure.  This has nothing to do with arrays, it's about data types.

    This isn't a wtf at all.  This is just a simple rule.  It doesn't limit you in any way.  You just have to declare the type.  I'm not a delphi guy, but this was the rule with pascal as well. No anonymous types as params.  Calling that a wtf is like saying, "omg i have to declare a variable before I use it! I'm used to applesoft basic where I don't have to do that!"



  • Yes, I understand that (now anyway). Here's what made me go WTF.
    An array is an intrinsic data structure, but a multi-dimensional array is not, yet the syntax implies they are both instrinsic. If a multidimensional array is so different to a single dimensional array, call it a TMultiDimensionalArray or something.



  • @phithe said:

    Well, I did RTFM, and I found a solution - I used an array of TStrings. And I realise I could define a type to do it.

    I hope you also realise an "array of TStrings" is an array of class instances, and so you'll have to create/free all the objects manually (unless you're doing .NET, but you'll still have to create them all).
    I don't see what's wrong with using "type TDoubleStringArray = array of array of string"; especially since it's compiler-managed.

    @phithe said:

    My point is, if "procedure foo(array of bar)" works, and "var array of array of bar" works, then logically,  "procedure foo(array of array of bar)" SHOULD work.

    No, it should not. "Array of" in a routine declaration defines an OPEN ARRAY, which is not a dynamic array. Go read up on it [1].

    @phithe said:

    Wow. This is even more WTF. I wrote some code to test that out. Check it out:<FONT face="Courier New">
    var
        a : array of string;      // these two are
        b : array of string;      // not assignment-compatible, but
        c, d : array of string;      // these two ARE assignment compatible</FONT>

    Awesome.

    Well it's rather obvious to anyone with some experience in Pascal. a and b have two separate specs, while c and d share theirs. It should be as clear as:

    var
       a: Type1;
       b: Type2;
       c, d: Type3;

    @phithe said:

    Yes, I understand that (now anyway). Here's what made me go WTF.
    An array is an intrinsic data structure, but a multi-dimensional array is not, yet the syntax implies they are both instrinsic.

    Well they are. Like I wrote above, "array of <type>" in a routine declaration defines an open array. Open arrays are created just before, and destroyed just after the call to the routine. You can pass dynamic arrays to an open array parameter, but it's handled quite differently by the compiler.

    [1] http://rvelthuis.de/articles/articles-openarr.html



  • @bah said:

    @phithe said:

    Well, I did RTFM, and I found a solution - I used an array of TStrings. And I realise I could define a type to do it.

    I hope you also realise an "array of TStrings" is an array of class instances, and so you'll have to create/free all the objects manually (unless you're doing .NET, but you'll still have to create them all).
    I don't see what's wrong with using "type TDoubleStringArray = array of array of string"; especially since it's compiler-managed.

    Well, you're probably right there - your way would have been the better option.

    @bah said:


    @phithe said:

    My point is, if "procedure foo(array of bar)" works, and "var array of array of bar" works, then logically,  "procedure foo(array of array of bar)" SHOULD work.

    No, it should not. "Array of" in a routine declaration defines an OPEN ARRAY, which is not a dynamic array. Go read up on it [1].

    Ok, that link was very helpful, thanks. However, according to that link, a dynamic array may be passed into an open array parameter. And it works, when said dynamic array is one dimensional.

    @bah said:


    @phithe said:

    Wow. This is even more WTF. I wrote some code to test that out. Check it out:<font face="Courier New">
    var
        a : array of string;      // these two are
        b : array of string;      // not assignment-compatible, but
        c, d : array of string;      // these two ARE assignment compatible</font>

    Awesome.

    Well it's rather obvious to anyone with some experience in Pascal. a and b have two separate specs, while c and d share theirs. It should be as clear as:

    var
       a: Type1;
       b: Type2;
       c, d: Type3;

    Okay, I guess I'll put that down to my lack of pascal experience then. It's not obvious to me at all.

    @bah said:


    @phithe said:

    Yes, I understand that (now anyway). Here's what made me go WTF.
    An array is an intrinsic data structure, but a multi-dimensional array is not, yet the syntax implies they are both instrinsic.

    Well they are. Like I wrote above, "array of <type>" in a routine declaration defines an open array. Open arrays are created just before, and destroyed just after the call to the routine. You can pass dynamic arrays to an open array parameter, but it's handled quite differently by the compiler.

    [1] http://rvelthuis.de/articles/articles-openarr.html



    But you can't pass multidimensional dynamic arrays into an open array parameter. Delphi has all these different, incompatible types of array. And the syntax to declare them is almost exactly the same!



  • @KenW said:

    @HitScan said:
    I think that people have discovered that Pascal is what's wrong with Delphi.


    And why would you think that? Delphi's Object Pascal is very well designed. I can do almost anything
    with it that you can do with any other language (including C++, with the exception of multiple inheritance; with Delphi 7 it would also include operator overloading, but you can do that with Delphi 2006).

    If the reason is simply because "it's Pascal", you need to think again.

    Exactly.  Why are there so many stereotypes against Pascal, anyway?  That was the first language I learned...(fun little fact ;)

    Although I haven't tried Delphi, I would jump at the change.  I've always loved Borland's products.



  • @HitScan said:

    I think that people have discovered that Pascal is what's wrong with Delphi.

    Why? My first language was Pascal, and it was a good start. Easy, clear, consistent. I did some quite nice things with it back in the 80's. Only problem with Pascal is that so many people never took the step from Pascal.

    @phithe said:
    My point is, if "procedure foo(array of bar)" works, and "var array of array of bar" works, then logically,  "procedure foo(array of array of bar)" SHOULD work.

    Alternatively, the syntax should be changed to reflect the different types of arrays under the hood.

    Also:
    that's why two variables declared as "array of <type>" are not
    assignment-compatible; even though they are the same in memory, they
    are not of the same type). Pascal is a very strongly-typed language.
    Wow. This is even more WTF. I wrote some code to test that out. Check it out:<font face="Courier New">
    var
        a : array of string;      // these two are
        b : array of string;      // not assignment-compatible, but
        c, d : array of string;      // these two ARE assignment compatible</font>

    Awesome.

    Actually, phithe has a valid point. Remember that Pascal was invented as a teaching tool with the explicit intention that everything should be clear and unambiguious. In these two instances syntactic similarity or identity of expression leads the programmer --especially the novice programmer with a less than complete understanding about compiler theory and underlying representation-- to belive that different constructs or symbols are interchangable. From a harsh interpretation of the goals of Pascal it can be taken as a failure of the language. However, as has been said, it is virtually impossible, or at least exceedingly difficult, to make a fully consistent and non-ambiguious language.



  • Yeah, I don't agree on the Borland bashing either ... I used Pascal a long time ago and it was definately a better choice than a lot of the other more 'popular' languages of the era ... I 've been developing with Borland C++Builder (Various versions) professionally basically since it was released to the public world.  I've used all the versions of VC++ all the way up to the current version, as well as MingW and CygWin, and I can honestly say Borland makes by far the BEST IDE around, especially its Form builder.  The only thing I wish was that the VCL and the CLX were more standards friendly (Would it kill them to add implicit construction/assigned operator for std::string ?).


Log in to reply