muschL muschL - 14 days ago 4
Pascal Question

Is it possible to turn a statement into a expression? And if so, how?

Is it possible to turn a statement into a expression with Pascal, Delphi, Freepascal or Lazarus? And if so, how?

Right now, I'm using the following exemplary workaround:

function AssignAndReturn(var LHS: Integer; RHS: Integer): Integer;
begin
LHS := RHS;
Result := RHS;
end;

(...)

var
a, b: Integer;
begin
a := Round(Sqrt(10));
AssignAndReturn(a, Round(Sqrt(10)));

b := (a := Round(Sqrt(10))); //not possible, because statement <> expression
AssignAndReturn(b, AssignAndReturn(a, Round(Sqrt(10))));


Is there something built-in already?

For example, there is
function IfThen
for the ternary operator
?:
. (For more information see https://en.wikipedia.org/wiki/%3F:#Delphi or Delphi - Equivalent to C#'s ternary operator?)




EDIT

I added an example to the code above. In C, you can assign two variables in one line with

b = a = sqrt(10);


In Delphi

b := a := Sqrt(10);


is not allowed, because assignments are statements, not expressions. Therefore
a := Sqrt(10)
cannot be assigned to
b
.

My exemplary function
AssignAndReturn
assigns the right hand side
RHS
to the left hand side
LHS
and returns an expression with the value
RHS
. The command

AssignAndReturn(b, AssignAndReturn(a, Round(Sqrt(10))));


would be an equivalent to the C-code
b = a = sqrt(10);
. But since there is a built-in function
IfThen
, which is Delphi's way for the ternary operator, I was wondering if there is a built-in method to turn a statement into a expression.




EDIT 2

I'm not trying to "make everything look like C". I just noticed, that sometimes it would be nice to "reuse" the right hand side of an assignment in the same line again. (See Lazarus/Free Pascal: How to improve coding style (to avoid using endless loop) of a while loop whose boolean expression is reassigned every pass) Which has nothing to do with C. So I tried to look it up and found Delphi's distinction between statements and expressions.

Now, I thought, that I might not be the only one, who wants to "reuse" the right hand side of an assignment in the same line again and was wondering, if Delphi has something already built in for this purpose - even though I have never seen something like it before. Why would I think that? Because the implementation is not very complex (see my
AssignAndReturn
) and there are other such functions like
IfThen
which "simplifies"

if a > 0 then b := 7 else b := 2;


(a line of code which is totally fine) to

b := IfThen(a > 0, 7, 2);


So
IfThen
is not absolutely necessary. Why is it bad to ask if there is also a built-in function for other not absolutely necessary simplifications like

b := a := Sqrt(10);


The C code only is there to clarify my question.

Answer

The short answer is:
No. What you want is not possible. And arguably would be of little if any benefit in Delphi.


First, let's discuss a more practical example. To be frank, a = b = f(x); is a rather poor example.

  • It's rare that you arbitrarily want the same value assigned to 2 variables.
  • Order of operation above has to break the left to right convention otherwise it would first resolve a = b then ? = f(x).
  • So there's little justification to favour that over b = f(x); a = b;.
  • Basically it's good for byte count (code golf) not readability.

So instead, let's consider the following, more practical scenario:

//Option 1
if ((b = f(x)) > 42)
  //use b

There's no Delphi equivalent to the above, but it's at least as readable/maintainable to write:

//Option 2
b := f(x);
if (b > 42) then
  //use b

There is another option to consider; especially if Option 1 is sitting in the middle of a larger function. Remember small functions are more maintainable and easier for a compiler to optimise. So consider:

//Option 3
...
ProcessRule42(f(x));
...
//Where Rule42 is is implemented as:
procedure ProcessRule42(b: Integer);
begin
  if (b > 42) then
    //use b
end;

Delphi doesn't really seem to be suffering due to not being able to write: if (b := f(x)) > 42 then //use b.

Is there any real benefit to Option 1?

If the Option 2 is at least as good, why would one ever bother with Option 1. The benefit is seen when you consider scoping rules.

//b does not exist
if ((var b = f(x)) > 42) {
  //use b
}
//b does not exist 

// Using the Delphi approach, this becomes:
//b does not exist
var b = f(x);
if (b > 42) {
  //use b
}
//b still exists

Delphi simply does not have the same scoping concerns. Delphi variables are all declared at the beginning of the method, and available for the whole method.


Conclusion

This brings us back to what others have been trying to explain. Delphi is a different language with slightly different approaches to some problems. While I applaud you for examining other options and considering what concepts can be borrowed from other languages: be careful of trying to force-fit some concepts where they don't belong.

If you break too many Delphi paradigms, your code may become unnecessarily difficult for Delphi programmers to maintain.

Comments