7

I have been trying to write as less code as possible. So, I use:

MyBoolean := Memo1.Text <> '';

instead of

if Memo1.Text = '' then
  MyBoolean := true
else
  MyBoolean := false;

Declare and initialize

var
  myGlobal: integer = 99;

to declare and initialize global variable. I would like to do the same for local variables, but seems it is not possible, so, I wonder if there is a way to initialize multiple variables of some type in one line, like in C

int x, y, z;
x=y=z=0;

Thank you.

Edijs Kolesnikovičs
  • 1,627
  • 3
  • 18
  • 34
  • Well, yes and no. Yes for writing e.g. `X: Integer = 99; Y: Integer = 99;` on a single line and no to multiple assigment statements. – TLama Apr 27 '14 at 10:04
  • 1
    Thats not so much of one line if you use Ctrl+D (aka Code Formatting). – Edijs Kolesnikovičs Apr 27 '14 at 10:27
  • Yup, but there's no way to initialize multiple variables in a single statement. And I'm glad that is so, since a statement like `x=y=z=0` is pretty hard for me to read. Personally, I would write even that on multiple lines. – TLama Apr 27 '14 at 10:38
  • @TLama How is x=y=z=0 hard to read or unclear? It's also standard mathematical notation and some programming languages do indeed allow that very syntax. What if instead of 0 the value being assigned was received from a call to an expensive (time-consuming) function? This syntax would only require one call. To avoid multiple calls in Delphi you'd need to create a temporary variable, assign the function result to that, then have multiple lines assigning the temp value to the variables. That would be, if not really less clear, certainly less elegant. There's legitimate value to this syntax. – alcalde Apr 27 '14 at 19:54
  • 1
    Edjis, I admire your commitment to DRY (don't repeat yourself). Unfortunately Delphi tends to take the form of WET (We Enjoy Typing or Write Everything Twice). There is a lot of syntactic sugar that the language doesn't implement that can cut down on duplicate code, e.g. ternary operator: x if a else c, multiple assignment, better operator priority (to avoid the need for parentheses in statements with boolean operators), power operator, step in for loop, strings in case statements, slice notation, type inference, etc. I hope once they move to the new compiler we will get some of these things. – alcalde Apr 27 '14 at 20:08
  • 1
    @alcalde, why ? I don't know. Maybe because when I read something, my brain usually focuses less on what's in the middle of expression. So, maybe I'm afraid that I will lose those `y` and `z` variables while reading, I don't know. And about temp variables, what's wrong with them ? I will rather clearly see what's written rather than being afraid of an extra assignment. Besides, in generated assembly code it will be the same. Or do you think there is a single instruction that will assign a returned value of a function to three variables at once ? – TLama Apr 27 '14 at 20:11
  • @alcalde: I hope they don't do this. First, if you want to program in C then program in C. Second, it is not good to overload a language with every syntactical structure someone somewhere might find useful for some occasions. And in Delphi, nothing is written twice. A declaration is not an initialization. – Rudy Velthuis Apr 27 '14 at 22:23
  • @TLama It is said, "Every line of code not written is a line of code guaranteed to be bug-free". :-) In python to swap variables you can just do a, b = b, a. It's *more* clear than temp := a;a :=b;b := temp and there's no chance of messing up the order of the assignments (as we've all done from time to time). I don't care about the assembly; I care about writing clean, clear, elegant code. temp := ExpensiveFunc;a := temp, b := temp; c:= temp isn't as concise as a = b =c = ExpensiveFunc(); Watch this for about four minutes and you'll see a perfect example: http://youtu.be/OSGv2VnC0go?t=34m2s – alcalde Apr 27 '14 at 22:31
  • @RudyVelthuis The idea of "if any other language has a good idea then one should just go use that language and leave Delphi preserved in amber forever" is part of the problem it's looked on today as outdated. We wouldn't have generics, iteration or lots of other useful features if EMBT thought that way. Second, the syntax in question is not for some obscure problem: initializing variables is routine in almost every type of program. Rudy, LOTS of stuff in Delphi is written twice. Heck, the interface and implementation sections alone disprove that claim. Same for forward declarations. – alcalde Apr 27 '14 at 22:36
  • @RudyVelthuis There's also overloaded functions, the pre-fireDAC setting of SQL parameters - lots of "ADOQuery1.Parameters.ParamByName(", the current REST library has a similar problem, you can't initialize an array like x := [1,2,3] but have to do x[1] := 1; x[2] := 2; x[3] := 3, lack of a ternary operator means you have to do if x = 7 then z := y * 3 else z := y * 2 instead of z := y * (2 if x = 7 else 3); If I wanted to split a string and put the result into 3 variables I'd have to first split it into a temporary array then copy the results one by one into the three variables, etc. – alcalde Apr 27 '14 at 22:44
  • @alcalde: Nothing is written twice. A declaraton is not a definition, and in the implementation section, you do not have to repeat the parameters (although I would advise anyone to do it). Sure, it makes sense to pick up ideas from other languages. But not everything someone somewhere might find useful. And as someone mentions: an assignment is not an expression, it is a statement, so `x := y := z := 0` does not make any sense. You can assign array constants to variables, but no array literals. Delphi does not (and should not) have every conceivable feature, but neither do other languages. – Rudy Velthuis Apr 27 '14 at 23:30
  • @alcalde: In other words: additions to the language and to the synatx should be chosen with care. Not everything conceivable should be done, in order to keep the language as consistent as possible. No one needs the equivalent of C++, which can do a lot but is extremely hard to really do properly. – Rudy Velthuis Apr 27 '14 at 23:33
  • @alcalde said: _"Every line of code not written is a line of code guaranteed to be bug-free"._ Damn, I guess I should go back and delete the line of code I added last week. I was debugging something, and it turned out a very important step had been forgotten. ;) ... Jesting aside, I actually agree wholeheartedly superfluous code is a dangerous waste. The goal should be to write clear unambiguous code. But don't let familiarity with a specific language feature mislead you into believing something is clear. E.g. `Swap(a, b)` is much clearer than `a, b = b, a`. – Disillusioned Apr 29 '14 at 10:37
  • @alcalde said: _"you can't initialize an array like x := [1,2,3];"_ Actually you can write `TIntegerArray.Create(1, 2, 3);`. See (http://stackoverflow.com/a/23361469/224704) for an example. I don't know when the feature was introduced. I only learnt about it fairly recently. ... The point is languages have different ways of achieving certain efficiencies. Rather than trying to shoe-horn other features into a language (creating more ways to solve the same problem), sometimes it's better to learn about the differences between languages. _(But this should never be an excuse to let it stagnate.)_ – Disillusioned Apr 29 '14 at 10:49
  • The "constructor" syntax for dynamic arrays was introduced in Delphi 2005 or 2007, IIRC. Note that it generates rather suboptimal code, but it works. – Rudy Velthuis May 02 '14 at 11:47

4 Answers4

6

In C assignment is an expression (returns a value).

In Pascal assignment is a statement (does not return a value).

The difference has some interesting consequences. For example in C both

while (x=0)

and

while (x==0)

are syntactically valid constructions (it is the source of innumerable errors) while in Pascal

while (x:=0)

is syntactically invalid because x:=0 is a statement.

mghie
  • 32,028
  • 6
  • 87
  • 129
kludg
  • 27,213
  • 5
  • 67
  • 118
  • I don't understand how this relates at all to the question. The question is about initializing multiple variables at once. In Python assignment is a statement and you can't assign a variable in a while loop just like Pascal. However, x=y=z=0 is also a valid statement.There's absolutely no relation between these two concepts. – alcalde Apr 27 '14 at 19:58
  • 1
    @alcalde I'm not familiar enough with Python to know the intent of the language, but relevance may depend on how you view its assignment feature: **(1)** Is assignment treated as an expression with syntactic salt to prevent common errors (as in the while loop)? **(2)** Or is it treated as a statement with syntactic sugar to simplify assignment of multiple values? ... Personally I consider the answer quite relevant and interesting in terms of better understanding the differences between languages. – Disillusioned Apr 29 '14 at 10:11
5

You can only initialize a single local variable per statement.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
0

Of course it would be possible to write a function

function AssignInteger(var _AssignTo: integer; _Value: integer): integer;
begin
  Result := _Value;
  _AssignTo := _Value;
end;

and use it like this:

var
  i, j, k: integer;
begin
  i := AssignInteger(j, AssignInteger(k, 5));

But that's not quite what you want, saying you want to write as short as possible code.

I'm pointing this out nonetheless just in case.

dummzeuch
  • 10,975
  • 4
  • 51
  • 158
0

As dummzeuch says, you could write your own routine. However, I would prefer one with a signature something like: procedure AssignIntegers(AValue, ATargetArray);. And ideally call the routine with: AssignInteger(99, [X, Y, Z]);.

Unfortunately the ideal option does not work, but the following procedure is close enough and should suffice. It works by taking pointers to the integers that need to be assigned.

procedure AssignIntegers(AValue: Integer; const ATargets: array of PInteger);
var
  I: Integer;
begin
  for I := Low(ATargets) to High(ATargets) do
    ATargets[I]^ := AValue;
end;

The following DUnit test case demonstrates that it works. You can even keep an array of these integer pointers handy to reassign at any time.

type
  TArrayPInteger = array of PInteger;
procedure TDelphiTests.TestAssignIntegers;
var
  X,Y,Z: Integer;
  LGroup: TArrayPInteger;
begin
  AssignIntegers(1, [@X, @Y, @Z]); { Pass open arrray using addresses of integers to initialise }
  CheckEquals(1, X);
  CheckEquals(1, Y);
  CheckEquals(1, Z);

  LGroup := TArrayPInteger.Create(@X, @Y); { Handy technique to initialise dynamic arrays }
  AssignIntegers(2, LGroup);
  CheckEquals(2, X);
  CheckEquals(2, Y);
  CheckEquals(1, Z); { Not part of group }
end;

WARNING

The only real drawback is that you lose type-checking. The compiler won't prevent you from passing the address of non-integer types. This can lead to corrupting other structures' data or access violations.

Community
  • 1
  • 1
Disillusioned
  • 14,635
  • 3
  • 43
  • 77