Mike Torrettinni 198 Posted August 20, 2020 I have functions A, B and C, and I need to return True if any of the function calls returns True, while all functions have to executed. In this example - as I would usually setup function calls: IsAnyTrue returns True if A, B or C functions are True A,B,C functions have to executed function IsAnyTrue1: boolean; begin Result := false; if A then Result := True; if B then Result := True; if C then Result := True; end; I can shorten this with: function IsAnyTrue2: boolean; begin Result := false; Result := A or Result; Result := B or Result; Result := C or Result; end; OR! I just realized, I can do it like this: function IsAnyTrue3: boolean; begin Result := false; Result := A or B or C or Result; end; But! This will trigger 'boolean short-circuit' rule. In this case I would need to use {$B+} to force full boolean expression evaluation - all A, B and C functions to be executed always. Are there any other ways how I can setup Result and always execute all functions? Share this post Link to post
Anders Melander 1783 Posted August 20, 2020 10 minutes ago, Mike Torrettinni said: Are there any other ways how I can setup Result and always execute all functions? Your first two solutions are fine. Why try to be "clever"? 1 1 Share this post Link to post
Mike Torrettinni 198 Posted August 20, 2020 1 minute ago, Anders Melander said: Your first two solutions are fine. Why try to be "clever"? I have nested search across a lot of fields (grouped in functions), and just trying to shorten all the code. Just trying to see if there are other options I can explore with my examples. Share this post Link to post
Anders Melander 1783 Posted August 20, 2020 1 minute ago, Mike Torrettinni said: Just trying to see if there are other options I can explore with my examples. Okay then. There's none that I can think of that doesn't fall into the "too clever" category so I would choose the solution that is the most human readable. Share this post Link to post
FredS 138 Posted August 20, 2020 21 minutes ago, Mike Torrettinni said: always execute all functions function CompleteEval(const Values: array of Boolean): Boolean; 1 1 Share this post Link to post
Mike Torrettinni 198 Posted August 20, 2020 1 minute ago, Anders Melander said: "too clever" Yes, too clever code usually means I will not know what it does in a week. So, I try to avoid it. Share this post Link to post
Mike Torrettinni 198 Posted August 20, 2020 3 minutes ago, FredS said: function CompleteEval(const Values: array of Boolean): Boolean; How would that work to retain Result value, if True? Share this post Link to post
Vandrovnik 214 Posted August 20, 2020 45 minutes ago, Mike Torrettinni said: How would that work to retain Result value, if True? result:=CompleteEval([result, A, B, C]); Share this post Link to post
Mike Torrettinni 198 Posted August 20, 2020 4 minutes ago, Vandrovnik said: result:=CompleteEval([result, A, B, C]); With: function CompleteEval(const aBooleanValues: array of Boolean): Boolean; var i: Integer; begin Result := false; for i := Low(aBooleanValues) to High(aBooleanValues) do if aBooleanValues[i] then Result := True; end; Right? Share this post Link to post
Vandrovnik 214 Posted August 20, 2020 5 minutes ago, Mike Torrettinni said: With: function CompleteEval(const aBooleanValues: array of Boolean): Boolean; var i: Integer; begin Result := false; for i := Low(aBooleanValues) to High(aBooleanValues) do if aBooleanValues[i] then Result := True; end; Right? Yes, I just would change it a little, so that it can work a bit faster: function CompleteEval(const aBooleanValues: array of Boolean): Boolean; var i: Integer; begin for i := Low(aBooleanValues) to High(aBooleanValues) do if aBooleanValues[i] then begin Result := True; exit; end; Result := false; end; 1 Share this post Link to post
Mike Torrettinni 198 Posted August 20, 2020 1 minute ago, Vandrovnik said: Yes, I just would change it a little, so that it can work a bit faster: function CompleteEval(const aBooleanValues: array of Boolean): Boolean; var i: Integer; begin for i := Low(aBooleanValues) to High(aBooleanValues) do if aBooleanValues[i] then begin Result := True; exit; end; Result := false; end; Great, thanks! Share this post Link to post
Stefan Glienke 2002 Posted August 20, 2020 And what exactly is wrong or not understandable in a week with using {B+} and a simple one liner? 2 Share this post Link to post
Mike Torrettinni 198 Posted August 20, 2020 Just now, Stefan Glienke said: And what exactly is wrong or not understandable in a week with using {B+} and a simple one liner? Oh, no, I was not referring to this solution. As soon as 'clever' came up, I thought of some complicated code that uses some sort of tricks that if not docummented thoroughly, I would not recognize next week. This is good solution, but I never use these switches, so I'm afraid I would forget to use it in next example. CompleteEval seems better solution, at this moment. Share this post Link to post
FredS 138 Posted August 20, 2020 33 minutes ago, Stefan Glienke said: And what exactly is wrong or not understandable in a week with using {B+} Nothing, but in the past too many directives where bad for the health of Error/Code insight.. sure that's much improved now 🙂 1 Share this post Link to post
Stefan Glienke 2002 Posted August 20, 2020 2 minutes ago, FredS said: Nothing, but in the past too many directives where bad for the health of Error/Code insight.. sure that's much improved now 🙂 Conditionals probably but certainly not switches. Share this post Link to post
Mike Torrettinni 198 Posted August 20, 2020 (edited) Actually I like both examples: function IsAnyTrue3: boolean; begin Result := false; {$B+} // Force full boolean expression evaluation Result := A or B or C or Result; {$B-} end; and function IsAnyTrue4: boolean; begin Result := false; Result := CompleteEval([Result, A, B, C]); end; Edited August 20, 2020 by Mike Torrettinni Share this post Link to post
aehimself 396 Posted August 20, 2020 Introduce a Variant in the check. I was hitting my head for days when I finally found out that Delphi always evaluates a boolean fully, if a variant comparison is present. Share this post Link to post
Anders Melander 1783 Posted August 20, 2020 If you use {$BOOLEVAL ON} and {$BOOLEVAL OFF} instead it will be a bit clearer what's going on. 19 minutes ago, Mike Torrettinni said: Result := false; Result := CompleteEval([Result, A, B, C]); There's no point in passing Result along as a parameter. You're just doing an logical OR on the values in the list anyway. - and I do think you're being too clever. It's not a solution I would allow. 1 Share this post Link to post
Mike Torrettinni 198 Posted August 20, 2020 4 minutes ago, Anders Melander said: If you use {$BOOLEVAL ON} and {$BOOLEVAL OFF} instead it will be a bit clearer what's going on. Even better, yet. 5 minutes ago, Anders Melander said: There's no point in passing Result along as a parameter. You're just doing an logical OR on the values in the list anyway. You are right, always room for some tweaking. Thanks. Share this post Link to post
Remy Lebeau 1394 Posted August 20, 2020 (edited) 3 hours ago, Mike Torrettinni said: I have nested search across a lot of fields (grouped in functions), and just trying to shorten all the code. Just trying to see if there are other options I can explore with my examples. How about something like this? uses System.SysUtils; function IsAnyTrue5: boolean; const Funcs: array[0..2] of TFunc<Boolean> = (A, B, C); var i: Integer; begin Result := False; for i := Low(Funcs) to High(Funcs) do Result := Funcs[i]() or Result; end; Edited August 20, 2020 by Remy Lebeau 1 Share this post Link to post
Mike Torrettinni 198 Posted August 20, 2020 9 minutes ago, Remy Lebeau said: const Funcs: array[0..2] of TFunc<Boolean> = (A, B, C); Interesting, but I assume this is only applicable to this exact example, right? Can this be used if A,B and C have arguments? Share this post Link to post
Attila Kovacs 629 Posted August 20, 2020 (edited) As you are always obfuscating your code with love, I can't imagine why didn't you go with Result := Ord(a) + Ord(b) + Ord(c) + Ord(Result) > 0; Edited August 20, 2020 by Attila Kovacs 1 Share this post Link to post
Mike Torrettinni 198 Posted August 20, 2020 2 minutes ago, Attila Kovacs said: As you are always obfuscating you code with love Don't we all? 🙂 (well, only if boss allows, of course 🙂 ) 2 minutes ago, Attila Kovacs said: Result := Ord(a) + Ord(b) + Ord(c) + Ord(Result) > 0; Interesting. Share this post Link to post
Stefan Glienke 2002 Posted August 20, 2020 (edited) 1 hour ago, Remy Lebeau said: How about something like this? That code does not compile, method references cannot be declared as consts. What you probably meant was this: const Funcs: array[0..2] of function: Boolean = (A, B, C); And yes, that only works if they are parameterless otherwise you would have to declare that differently - but again only works if they are have homogeneous signatures. Talking about possibly overengineering: https://en.wikipedia.org/wiki/Specification_pattern Edited August 20, 2020 by Stefan Glienke Share this post Link to post
David Heffernan 2345 Posted August 21, 2020 I can’t see past // must call all functions, defeat short circuit evaluation aVal := A(); bVal := B(); cVal := C(); Result := aVal or bVal or cVal; I don’t care for temporarily disabling short circuit evaluation. I’d rather have the predictability of one rule for expression evaluation. Mix and match adds an impedance to understanding for the reader. 3 1 Share this post Link to post