Introducing Inline Variables in the Delphi Language The coming 10.3 version of Delphi introduces a very handy feature to the language, local inline variables with local scope and type inference. The Delphi language in 10.3 has a fairly core change in the way it allows far more flexibility in the declaration of local variables, their scope and lifetime. This is a change that breaks a key tenet of the original Pascal language, but offers a significant number of advantages, reducing unneeded code in several cases. Old Style Var Blocks Since Turbo Pascal 1 and until now, following classic Pascal language rules, all local variable declarations had to be done in a var block written before the beginning of a function, procedure or method: procedure Test; var I: Integer; begin I := 22; ShowMessage (I.ToString); end; Inline Variable Declarations The new inline variable declaration syntax allows you to declare the variable directly in a code block (allowing also multiple symbols as usual): procedure Test; begin var I, J: Integer; I := 22; j := I + 20; ShowMessage (J.ToString); end; While this might seem a limited difference, there are several side effects of this change. It is these additional effects that make the feature valuable. Initializing Inline Variables A significant change compared to the old model, is that the inline declaration and initialization of a variable can be done in a single statement. This makes things more readable and smoother compared to initializing several variables at the beginning of a function. procedure Test; // declaration and initialization in a single statement begin var I: Integer := 22; ShowMessage (I.ToString); end; More over, if the value of a variable is available only later in the code block, rather than setting an initial value (like 0 or nil) and later assign the actual value, you can delay the variable declaration to the point you can calculate a good initial value: procedure Test1; // multiple inline declarations (symbols declared when used) begin var I: Integer := 22; var J: Integer := 22 + I; var K: Integer := I + J; ShowMessage (K.ToString); end; In other words, while in the past all local variables where visible in the entire code block, now an inline variable is visible only from the position of its declaration and up to the end of the code block. Scope and Lifetime of Inline Variables Declared in Nested Blocks The scope limitation is also more relevant as is doesn't apply to the entire procedure or method, but only to the begin-end code block the inline variable appears. In other words, the scope of an inline variable is limited to the declaration block and the variable cannot be used outside of the block. Not only, but the variable lifetime is also limited to the block. A managed data type (like an interface, string or managed record) will now get disposed at the end of the sub-block, rather than invariably at the end of the procedure or method. procedure Test2; // scope limited to local block begin var I: Integer := 22; if I > 10 then begin var J: Integer := 3; ShowMessage (J.ToString); end else begin var K: Integer := 3; ShowMessage (J.ToString); // COMPILER ERROR: "Undeclared identifier: J" end; // J and K not accessible here end; As you can see in the last code snippet above, a variable declared inside a begin-end block is visible only in the specific block, and not after the block has terminated. At the end of the if statements, J and K won’t be visible any more.

As I mentioned, the effect is not limited only to visibility. A managed variable, like an interface reference or a record, will be properly cleaned up at the end of the block, rather than at the end of the procedure or method: procedure Test99; begin // some code if (something) then begin var Intf: IInterface = GetInterface; // Intf.AddRef var MRec: TManagedRecord = GetMRecValue; // MRec.Create + MRec.Assign UseIntf(Intf); UseMRec(MRec); end; // Intf.Release and MRec.Destroy are implicitly called at end of scope // more code end; // no additional cleanup Type Inference for Inline Variables Another huge benefit of inline variables is that the compiler now can, in several circumstances, infer the type of an inline variable by looking to the type of the expression or value assigned to it: procedure Test; begin var I := 22; ShowMessage (I.ToString); end; The type of the r-value expression (that is, what comes after the :=) is analyzed to determine the type of the variable. Some of the data types are “expanded” to a larger type, as in the case above where the numeric value 22 (a ShortInt) is expanded to Integer. As a general rule, if the right hand expression type is an integral type and smaller than 32 bits, the variable will be declared as a 32-bit Integer. You can use an explicit type if you want a specific, smaller, numeric type. Now while this feature can save you a few keystrokes for an Integer or a string, variable type inference becomes fairly nice in case of complex type, like instances of generic types. In the code snippet below, the types inferred are TDictionary for the variable MyDictionary and TPair for the variable APair. procedure NewTest; begin var MyDictionary := TDictionary (string, Integer).Create MyDictionary.Add ('one', 1); var APair := MyDictionary.ExtractPair('one'); ShowMessage (APair.Value.ToString) end; (Code above uses parenthesis rather than angle brackets for the generic instance, because of rendering issues on this blog, sorry) Inline Constants Beside variables, you can now also inline a constant value declaration. This can be applied to types constants or untyped constants, in which case the type is inferred (a feature that has been available for constants for a long time). A simple example is below: const M: Integer = (L + H) div 2; // single identifier, with type specifier const M = (L + H) div 2; // single identifier, without type specifier For Loops With Inline Loop Variable Declaration Another specific circumstance in which you can take advantage of inline variable declarations is with for loop statements, including the classic for-to loops and modern for-in loops: for var I: Integer := 1 to 10 do ... for var Item: TItemType in Collection do... You can further simplify the code taking advantage of type inference: for var I := 1 to 10 do ... for var Item in Collection do ... This is a case in which having the inline variable with limited scope is particularly beneficial, as in the sample code below: Using the I variable outside of the loop will cause a compiler error (while it was only a warning in most cases in the past): procedure ForTest; begin var total := 0; for var I: Integer := 1 to 10 do Inc (Total, I); ShowMessage (total.ToString); ShowMessage (I.ToString); // compiler error: Undeclared Identifier ‘I’ end; Inline Summary Inline variable declarations, with type inference and local scope, bring fresh air to the Delphi language. While Pascal source code readability remains a key tenet to preserve, it is important to modernize the language at the core level, removing some of the rust (real or perceived). In case of inline variables, there are so many advantages to depart from the traditional coding style, that the value is clear. Still, you can keep your code as is and ask your fellow developers to stick with the traditional declaration: nothing in the existing code or style is wrong, but inline declarations offer you a new opportunity. I already have trouble going back to older versions of Delphi... just saying.

61 Comments

Introducing Inline Variables in the Delphi Language This is a really superb enhancement to the language. Well done. I especially like being able to control managed type finalization with greater granularity that the procedure. Just too bad for me that I have to buy new licences for every developer in my team if I want to take advantage of this.

Introducing Inline Variables in the Delphi Language Good news! (The indentation of the examples would need to be fixed ... )

for loops I'm wondering about for loops, such as in your example: for var I: Integer := 1 to 10 do Shouldn't that always be: for const I: Integer := 1 to 10 do Because one is not supposed to ever modify the for loop variable? Or is there some technical reason why var is required, and const maybe not allowed? Or is it even fancier: perhaps a var inline loop variable _can_ be modified inside the loop, but the loop will still work and continue with the next sequential value, regardless of the local modification inside the loop? (Not that this would be good programming style, but a possibility.) Just curious!

Introducing Inline Variables in the Delphi Language Really looking forward to this release!

Introducing Inline Variables in the Delphi Language Can we please also have a bit of syntactic sugar for interfaces, such as: class function IIntf.Create: IIntf; static; //or even better constructor IIntf.Create; Obviously the constructor just translates into a static class function for the interface. We can already do this using the known trick of wrapping the interface inside a record and overloading the implicit operator, but that's a lot of typing. Much better if the compiler helped us with this.

Introducing Inline Variables in the Delphi Language Hello Marco, I am suggesting that the next release be broken down to purchasable add-on parts so that it is more affordable for everyone. For example, the core compiler with the RTL and basic libraries can have their licenses sold apart from the VCL, Firemonkey, FireDAC, DBExpress, Web development, etc. core libraries. This way we, your customers, can choose what to purchase and save money. This is since the collective product is expensive to say the least. Thanks.

Introducing Inline Variables in the Delphi Language Very interesting, especially the fact that for scope "..an inline variable is limited to the declaration block and the variable cannot be used outside of the block.."

Introducing Inline Variables in the Delphi Language Seems that Santa Claus comes early this year!

Introducing Inline Variables in the Delphi Language I looked at the Rust language awhile ago and wished Delphi had these features too! Dream come true!! Thank you!

Introducing Inline Variables in the Delphi Language @Matthias Bolliger no i don't think it needs to be a constant, the 'I' variable changes before of the for loop, a constant has a constant value and not a variable value which is needed for the loop. Anyway this change looks very good and promising! Thank you for bringing the news Marco

Introducing Inline Variables in the Delphi Language This is the thing I miss most when switching between Delphi and C#. Imho the best addition to Delphi since Generics. Thanks for adding this to Delphi! Next: Linq :-)

Introducing Inline Variables in the Delphi Language @Franky Brandt: Yes, the variable (I) changes before each iteration of the for loop, but inside the loop, on each iteration, it is a constant. (Already today, the documentation states: "It is illegal to assign a value to the for loop control variable inside the for loop." And about for-in loops: "The iteration variable cannot be modified within the loop.") So I thought that 'const' might make this fact extra clear. Or, perhaps the label var/const could simply have been omitted in for loops, since 'const' is obvious, leaving just: for I: Integer := 1 to 10 do or simply, without any declaration of I anywhere at all: for I := 1 to 10 do But I guess this would be a bit confusing. I'm quite OK with 'var' + the good old rule that the control/iteration variable must never be modified.

Introducing Inline Variables in the Delphi Language This is a terrific improvement to the language, and I would argue that it can increase code readability when used correctly. Any feature, when used incorrectly, can make code harder to read, so that isn't really the sole standard I would use to decide if it is an improvement.

Introducing Inline Variables in the Delphi Language Hello dear Marco; Actually great and intresting features, Thanks a lot... ++ A suggestion: Now on we have such flexibility in variable declaration and initialization, this would be very handy if Delphi defines an instruction like "decltype()" as in C++. Best wishes.

Introducing Inline Variables in the Delphi Language cool thanks marco ,very useful as functionality .

Introducing Inline Variables in the Delphi Language This is so wonderful! :) <3 <3 <3

Introducing Inline Variables in the Delphi Language No, the index variable for a for loop can't be a const. Yes, we are not allowed to change it, but it would be a const, so after initialization, it can not change at all. But a loop index will be changed, otherwise it is useless. Not changed by the user, but by the loop. So it can't be a const, it must still be a variable.

Introducing Inline Variables in the Delphi Language FWIW, Marco, write: var Intf: IInterface = GetInterface; // Intf.AddRef Small mistake there. It should be: var Intf: IInterface := GetInterface; // Intf.AddRef Unlike global variables, which are initialized with var X: Integer = 17; local inline variable initialization is with :=, because this is different, see the following paragraph. The initialization expression for an inline var doesn't have to be a constant expression. It can contain other variables and function calls. This is even so for inline const definitions: the initialization expression can be a variable expression.

Introducing Inline Variables in the Delphi Language Brilliant addition. Love the fact I won't have local variables hanging around before and after I need them. I don't think I will be using type inference though - call me old school!

Introducing Inline Variables in the Delphi Language Delphi = C++ now. And this is a bad news. :( Considering SOLID principles, it is a bad idea to put new variables here and there. If a functional block is too big for you in order to put the variables only in a single place, then it means, that you should divide this block into smaller functional parts. For schools, there is also no more need to teach Delphi, since no more strict rules are used and, thus, Delphi became C++.

Introducing Inline Variables in the Delphi Language Long awaited, well received, hopefully cleanly used feature. Very well Mr.!

Introducing Inline Variables in the Delphi Language Completely agree with you, Jacek Krawczyk! But the option for the loop inline variable can be actually very good and does not make it less SOLID.

Introducing Inline Variables in the Delphi Language Very nice! Can’t wait to play around with this. Bonus points if the code editor and refactoring also understand the type inference and inline variable declarations. :)

Introducing Inline Variables in the Delphi Language Jacek, you have a point. But on the plus side it’s much easier to extract the method in the refactoring phase, when code and variables are in one code block. ;) :)

Introducing Inline Variables in the Delphi Language Ha ha, "removing some of the rust", in fact we need more and more rust features. https://rust-lang.org

Introducing Inline Variables in the Delphi Language I think this is not a well thought through addition to the language. This "feature" is hell for teams. The strict separation from declaration and use is one of the key features of the Pascal language. I would prefer to add at least a switch to prevent it from being used. Inline variable declaration is a known source of bugs in C style languages.

Introducing Inline Variables in the Delphi Language This is killing the whole pascal language to built a java structure language. This has nothing to do with structural programming. Let the VCL doion what it must do and build it in FMX

Introducing Inline Variables in the Delphi Language Marco - without making a pun towards my beloved Italy - this feature is likely to lead to something similar to spaghetti code. Better promote the use of goto. Do you actually want to debug something like this? Honestly?

Introducing Inline Variables in the Delphi Language @Jacek: +1 "If a functional block is too big for you in order to put the variables only in a single place, then it means, that you should divide this block into smaller functional parts." Totally agree with this.. Besides, thank's to Marco for this clear article... (as always)

Introducing Inline Variables in the Delphi Language BRRRRR...!!!! I do some coding in PHP too and on the point where you need a variable, try to remember if you allready have a variable with the same name. And if you think you have, try to find it back. And if it needs initialization, rembember if you initialized it. By searching through your code over and over. In the old school way you can look at the beginning of your procedure or function. And if your variable needs a value, give it at the first line(s) of the function. Clear as that. I did not see any inline procedures/functions in the examples. So in those cases you declare your variables old school? So we can mix inline variables and old style var blocks? Even better.. I wonder what is more readable and smoother in the end with this. And I don't get what advantage this has and for who. If you want inline variables and accolades consider switching to .NET.

Introducing Inline Variables in the Delphi Language Marco, maybe switch to .NET if you are so fond of that coding style.. I see comments from people enjoying the C++ features in Delphi. This kind of variable declaration and generics are copied from other programming languages and cheered at by users of those languages. I don't get why to make Delphi/Object Pascal a copy of those languages. Next are the accolades, which would make it even worse. But what for?

Introducing Inline Variables in the Delphi Language Ok, in the Try Finally block, if you declare and create an object after the try, you cannot free the object in the finally part, right? Because in the finally part of the block, the variable isn't known?

Introducing Inline Variables in the Delphi Language Blimey, what a lot of odd claims from the downers... If it's too hard to find an inline variable, then you obviously don't really care about procedure length (i.e. those two arguments are mutually exclusive). Further, far from encouraging spaghetti code, block scope makes certain forms of it impossible, since (by definition) you can't access variables outside of their originating block. Put another way, making use of it will prevent accidentally reusing a variable that is really (still) 'owned' by another part of the routine - assuming the C# behaviour is implemented (I don't know if it is) whereby a compiler error is raised on declaring a variable with the same name as a variable in an outer scope, far from increasing the need 'to remember if you already have a variable with the same name', it reduces it and forces correctness! And as for the C# hate.. you guys come across a bit like that funny Catholic sect which thinks the Pope isn't a real Catholic ;-)

Introducing Inline Variables in the Delphi Language Finally! Great job! This is one of the long awaited and missing features in the Delphi language. All other OOP languages had it for ages. Now, I am eagerly waiting for full featured class (and other) helpers, where there can be multiple ones in scope.

Introducing Inline Variables in the Delphi Language Sounds good, like C/C++, but broken Pascal's traditional rules. Assign another language name for it maybe better.

Introducing Inline Variables in the Delphi Language For me, the feature above does not have any great approach in programming. for researching or education area maybe so good to make more agile in looking for something. Give us more and more something more helpful. For give us something new it's okay but talking about business, this is so bad. Marco, you have to give another thing more better

Introducing Inline Variables in the Delphi Language "Now, I am eagerly waiting for full featured class (and other) helpers, where there can be multiple ones in scope. " Now that will be a nice addition!

Introducing Inline Variables in the Delphi Language Excellent! Cannot wait! Hope my subscription hasn't lapsed. (How can one tell when it's due?) Next: Case-Sensitivity compiler option.

Introducing Inline Variables in the Delphi Language Cool! Honetly I don't like grouping all vars in the begining of the function/procedure when some are used lately and only within some blocks. So imho, this new feature of D10.3 is very welcomed. The point is not to be like C#/, Java or others, we don't care. The thing is rather offering some comfort to programmer. Anyway congrat to Emb team with Marco.

Introducing Inline Variables in the Delphi Language Cool! Can't wait to start coderevirewing something like that: var arr: array... function Fuckup: boolean; var I: Integer; begin for var I := Low(arr) to High(arr) do if arr[I]..... then break; Result := (I <= High(arr)); end; Without compiler directive that restrict to implement "var section" anywhere except where they should be, expect many additional debug hours.

Introducing Inline Variables in the Delphi Language Andrey Kudriashov your code was buggy before code reviewing. What if "break" is not called? "After the for statement terminates (provided this was not forced by a Break or an Exit procedure), the value of counter is undefined." http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Declarations_and_Statements_(Delphi)#For_Statements

Introducing Inline Variables in the Delphi Language More easy it does not mean good news. One of the good things of Pascal and Object Pascal is that the code is very clear. Maybe some people does not appreciate this. It is more easy to write a compiler for C or any language with few restrictions. Less restrictions does not mean a language less poweful.

Introducing Inline Variables in the Delphi Language I personally find it to increase readability of my code in some cases, and declaring a variable and not being able to assign it a value in the same line of code was pissing me off for so long. Finally I will save hundreds of lines of unnecessary code per project, this is great! You guys make a lot of fuss from nothing. Nobody forces you to use this feature if you don't like it. Literally, noone here gave a valid reason why introducing this is a bad idea. If you think this is so bad, then make a rule in your company to not use it. I am sure, you already have introduced coding standard, right? Right? So there is no problem for you whatsoever.

Introducing Inline Variables in the Delphi Language Will this help to compiler to create better optimized code and hopefully better performance in situations where Delphi just does not do a good job reusing registers?

Introducing Inline Variables in the Delphi Language it is weird to have C/Java like syntax sugars in Delphi programming language. Afterall, Delphi is Pascal-style not C-style !

Introducing Inline Variables in the Delphi Language @Mowafaq, I don't understand people complain. There is so much other options, free to choose. You can go with Lazarus, FPC, Delphi capabilities to price ratio is very good, my only complain is about slow major bugfixing politic. You should release patches regullary every 2-3 months fixing most dangarous issues from Quality Portal.

Introducing Inline Variables in the Delphi Language Nice!

Introducing Inline Variables in the Delphi Language This is a godsend for performance critical code! This, because until now, my company moves code that uses strings and/or arrays into separate functions, to avoid the overhead of finalization that occurs on variables of these types. By handling variables that undergo finalization in separate functions, we avoided that overhead in the "fast path" that didn't access these variables. The price we paid for that, however, was an additional call. Now, with inline variable scope, we can move such code back into the main functions, avoid the call, but still have local variable scope!!!! Huge thanks for all involved (and also thanks for picking up on my request here https://quality.embarcadero.com/browse/RSP-14867). Cheers!

Introducing Inline Variables in the Delphi Language A global variable can be initialized like this: var a : integer = 1; Default values for subroutine arguments likewise use an equals sign. Inline variables, however, use a different syntax (colon plus equals): var b : integer := 1; And while can initialize a variable in a global var section, you still cannot do this in a var section local to a subroutine, while doing it inline works. Can someone please clear up this mess?

Introducing Inline Variables in the Delphi Language Hi, This is very cool. I had installed Rio and test it. I have a note: When I use inline variable, Rad Studio underline it like error hint, but compilation is OK. Is there some option to not underline it, or it is bug with this new feature in Rio?

Introducing Inline Variables in the Delphi Language I like the concept and I have played around with it for some time now. HOWEVER ... it annoys me that the editor shows inline code as being erroneous, with red wavy lines underneath. It makes it very difficult to see where there might be an actual , real, code error before you compile. Can this be fixed?

Introducing Inline Variables in the Delphi Language Is the inline variable error highlighting fixed in the December 2018 IDE patch? I don't see anything about it in the patch readme but I could be missing it.

Introducing Inline Variables in the Delphi Language I hope you don't mind I have mentioned your article at https://www.linkedin.com/pulse/inline-variables-delphi-rio-ivelin- nikolaev/

Introducing Inline Variables in the Delphi Language The variable error highlighting bug is NOT fixed in the December IDE patch. Too bad...

Introducing Inline Variables in the Delphi Language Great to have this inline variable addition to the Delphi language. Unfortunately the Delphi editor shows with a red underlined var text in: for var i : Integer := 1 to 100 do It will finally be perfect when the editor/IDE is aware of the language enhancements!

Introducing Inline Variables in the Delphi Language It's also not fixed in Delphi 10.3.1. Is there a bug report about this?

Introducing Inline Variables in the Delphi Language +1 for Jacek Krawczyk and -1 for this change.

Introducing Inline Variables in the Delphi Language I tried a quick test of the inline variable declaration in a forin loop: for var filename in archive.FileNames do begin ... end; archive is an instance of TZipFile. The IDE puts squiggles under var andFileNames. For var it says "Expected an identifier but received var". For FileNames it says "Expected the end of file but received an identifier". Am I doing something wrong or is this is an issue with the IDE. I am running 10.3 with update 1.

Introducing Inline Variables in the Delphi Language Those rules were there for something. It's like they are killing the language, in favor of a more "promiscous" style. Following this line of changes, we'll end up using "auto"-like sentences to cover the full 4, even 5 lines of ininteligible mess for a variable declaration, like the programmers of some well known language have to do today.

Introducing Inline Variables in the Delphi Language This is a really convenient feature. It does compile correctly in my RS 10.3 but I still keep on getting red underlining on the word 'var' showing that there is an error

Introducing Inline Variables in the Delphi Language The inline vars are great. It would be superb if the for/to syntax was extended to "with" clauses with multiple vars. Something like: with var s := oShape.Size, k := Kitten do begin k.Height := s.Height; .. .. .. end; which would finally fix the long forgotten and super useful for readability "with" clause.





Post Your Comment

Click here for posting your feedback to this blog.

There are currently 0 pending (unapproved) messages.