Click here to Skip to main content
14,600,507 members

Delphi Language Progression Suggestions

Rate this:
4.83 (19 votes)
Please Sign up or sign in to vote.
4.83 (19 votes)
13 Jul 2018CPOL
There are dozens of more things I'd like to see in Delphi, but here I will cover the ones that are easy to implement, yet provide large gains.
This is an old version of the currently published article.

Since ~Delphi 2010, we have had generics, attributes, iterators, and some other compiler niceties. While many of the features we would like are difficult to implement, I believe that a few simple language features are long overdue.

There are dozens of more things I'd like to see in Delphi, but here I will cover the ones that are easy to implement, yet provide large gains.

The Easy How

Most compilers just declare block level variables internally as normal locals, i.e., it's just syntactic (but very useful!) sugar. It could even be done with a pre-processor but that would be hacky and affect the debugger.

The easiest way is scan for block vars. They internally treat them as locals. But add a prefix of suffix of otherwise unusable characters and give each block an ID.

So for example, give each block a number, 1, 2, 3, 4... then for each block var, internally just make it name$1 or something. Very easy to implement with very little impact to the compiler.

Block Level Variables

Actually, block level variables, initializers, and basic type inference:

procedure Test();
var
  a: integer = 1;
  // Type inference would be nice too, but not critical.
  // Could be limited to static inits only, even that would be helpful
  // as dynamic ones are a lot more complex.
  b = 1;
begin
  for var c:string in List do begin
    ...
  end;

  var d:TStrings = TStringList.Create;
  // type inference only on non objects for simplicity if needed
  var e = 'Hello'

  // type inference would be nice, but not critical.
  // Can always be added in future.
  for f:integer := 1 to 10 do begin
    // Usable in block only.
    // Internally is just local$2
    var x = 5;
    ...
  end;

  // Simple type inference at least with constructors would be pretty
  // simple, but even if g:TStringList/TStrings = TStringList.Create
  // that would be fine.
  with var g = TStringList.Create do try
    g.Add('Hello;);
    // Usable in block only.
    // Internally is just local$3
    // Note that we used x before, but the are block level
    // so they are independent from each other.
    var x = 5; 

    // Block level, value set later.
    var y: integer;
    ...
    y := 22;
  finally g.Free; end;
end;

Type Inference

function Foo(): integer;
var
  x = 1;
  y = TStringList.Create;
begin
end;

Using Statement

A try with an implicit finally free block.

Let me show you how this would alter existing code:

class function TMyWriter.ToString(aSrc: TRoot): string;
var
  xStream: TStringStream;
  xWriter: TWriter;
begin
  xWriter := TWriter.Create(aSrc); try
    xStream := TStringStream.Create; try
      xWriter.SaveToStream(xStream);
      Result := xStream.DataString;
    finally xStream.Free; end;
  finally xWriter.Free; end;
end;    

With using:

class function TMyWriter.ToString(aSrc: TRoot): string;
var
  xStream: TStringStream;
  xWriter: TWriter;
begin
  using var xWriter := TWriter.Create(aSrc) do begin
    using var xStream := TStringStream.Create do begin
      xWriter.SaveToStream(xStream);
      Result := xStream.DataString;
    end;
  end;
end;    

Auto Free

This, of course, applies to the Windows compiler, not the ARC based ones. Someday, the ARC compiler will reach Windows as well, but until it does, this solution is simple and helpful.

There are possible alternate syntaxes as well, but the main desire is for the functionality. The exact name of the keyword isn't that important either. Auto is simply shorter to type thatn autofree, dynamic, finalized, etc.

procedure Test2();
var
  x: integer;
  y: TStrings = TStringList.Create; autofree;
begin
  ...
  autofree z: TStrings = TStringList.Create; 
  ...
  // At proc end, all .Free is called for all auto declared variables.
  // ie in this case, compiler emits a hidden y.Free and z.Free
end;

Let me show you how this would alter existing code:

class function TMyWriter.ToString(aSrc: TRoot): string;
var
  xStream: TStringStream;
  xWriter: TWriter;
begin
  xWriter := TWriter.Create(aSrc); try
    xStream := TStringStream.Create; try
      xWriter.SaveToStream(xStream);
      Result := xStream.DataString;
    finally xStream.Free; end;
  finally xWriter.Free; end;
end;    

With auto:

class function TMyWriter.ToString(aSrc: TRoot): string;
var
  xStream: TStringStream; auto;
  xWriter: TWriter; auto;
begin
  xWriter := TWriter.Create(aSrc);
  xStream := TStringStream.Create;
  xWriter.SaveToStream(xStream);
  Result := xStream.DataString;
end;    

Or when combined wtih block declared variables:

class function TMyWriter.ToString(aSrc: TRoot): string;
begin
  auto xWriter := TWriter.Create(aSrc);
  auto xStream := TStringStream.Create;
  xWriter.SaveToStream(xStream);
  Result := xStream.DataString;
end;    

Conclusion

With these simple additions, Delphi would be far easier to write code in without losing any functionality.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Chad Z. Hower, a.k.a. Kudzu
"Programming is an art form that fights back"

I am a former Microsoft Regional DPE (MEA) covering 85 countries, former Microsoft Regional Director, and 10 Year Microsoft MVP.

I have lived in Bulgaria, Canada, Cyprus, Switzerland, France, Jordan, Russia, Turkey, The Caribbean, and USA.

Creator of Indy, IntraWeb, COSMOS, X#, CrossTalk, and more.

Comments and Discussions

Discussions on this specific version of this article. Add your comments on how to improve this article here. These comments will not be visible on the final published version of this article.

Article
Posted 12 Jul 2018

Tagged as

Stats

12.6K views
5 bookmarked