Recent

Author Topic: ways to avoid begin-end’s?  (Read 8231 times)

Thaddy

  • Hero Member
  • *****
  • Posts: 18376
  • Here stood a man who saw the Elbe and jumped it.
Re: ways to avoid begin-end’s?
« Reply #30 on: May 09, 2024, 05:51:45 pm »
Code: Pascal  [Select][+][-]
  1.     if X=a then X:=1  >>  increment(i);
That is always zero, btw.
Is perfectly legal:
Code: Pascal  [Select][+][-]
  1. {$mode objfpc}{$H+}{$J+}
  2.  
  3. function increment:integer;
  4. const i:integer = 0;
  5. begin
  6.   inc(i);
  7.   result := i;
  8. end;
  9. var
  10.   x, a:integer;
  11. begin
  12.   x:=100;
  13.   a:=100;
  14.   if x=a then X:=a  >>  increment;
  15.   writeln(x);
  16. end.
« Last Edit: May 09, 2024, 05:57:34 pm by Thaddy »
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

alpine

  • Hero Member
  • *****
  • Posts: 1410
Re: ways to avoid begin-end’s?
« Reply #31 on: May 09, 2024, 06:06:18 pm »
Quote
Is perfectly legal:
Of course, but it is not the point. X will be affected unless you craft the expression as no-op (e.g. X OR 0).
Just to remind, the OP wants to execute 2 operations without enclosing them in begin/end.

Edit: bitwise OR, not to short-circuit.
« Last Edit: May 09, 2024, 06:07:58 pm by alpine »
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

MarkMLl

  • Hero Member
  • *****
  • Posts: 8505
Re: ways to avoid begin-end’s?
« Reply #32 on: May 09, 2024, 09:13:52 pm »
Apparently your programming knowledge starts with C/C++. You so wrongly interpreted the assignment statement with the C assignment operator , which is defined to have a result. The pascal statement does not have a result. Furthermore, even the C/C++ assignment operator have a very low priority, lower than almost every other operator. It will be executed after the shift, and, or whatever is the right-hand operator.

And you should better bet on the 'OR with 0' operator instead of 'AND with -1' just because zero is the only constant compatible with most of the types.

In Pascal there is no 'empty value', neither in C. Not assigning a value to a function result, doesn't mean it will be 'empty value'. BTW FPC always gives a warnings about this.

The only viable way to combine several function invocations without begin/end was given in reply #19 by bx440. But also care must be taken because of the short-circuit evaluation of the logical operators.

I think you're being unfair. The way I read it is that he failed to understand that a function is... let's call it an isolated compilation unit, the fact that a result isn't assigned doesn't have some magic effect on the code generation of expressions in which it appears, and that any types in the expressions in which it appears cannot be communicated back to the function's own code generation.

And I'd suggest that a constant (e.g. 2 in his examples) without a defined width should never be used for bitwise operations: even in the case of +ve numbers a bitwise-not cannot be reliably applied without knowing the width, and that fact should be enough to disqualify any other bitwise operations.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

alpine

  • Hero Member
  • *****
  • Posts: 1410
Re: ways to avoid begin-end’s?
« Reply #33 on: May 10, 2024, 11:11:51 am »
And I'd suggest that a constant (e.g. 2 in his examples) without a defined width should never be used for bitwise operations: even in the case of +ve numbers a bitwise-not cannot be reliably applied without knowing the width, and that fact should be enough to disqualify any other bitwise operations.
I wouldn't condone the use of side effects in the least, and only for aesthetic purposes. Hasn't it been the goal of the programmers all along to limit the side effects? Or similarly, the absence of any effects?
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

MarkMLl

  • Hero Member
  • *****
  • Posts: 8505
Re: ways to avoid begin-end’s?
« Reply #34 on: May 10, 2024, 11:34:17 am »
And I'd suggest that a constant (e.g. 2 in his examples) without a defined width should never be used for bitwise operations: even in the case of +ve numbers a bitwise-not cannot be reliably applied without knowing the width, and that fact should be enough to disqualify any other bitwise operations.
I wouldn't condone the use of side effects in the least, and only for aesthetic purposes. Hasn't it been the goal of the programmers all along to limit the side effects? Or similarly, the absence of any effects?

Yes, but that's nothing to do with side-effects.

What I'm saying is that I believe that (or, perhaps more accurately, it is my opinion that) a literal number (whether explicitly declared as a constant, or implicitly used in an expression) shouldn't have a bitwise operator applied to it unless the size (width in bits) is explicitly specified.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

alpine

  • Hero Member
  • *****
  • Posts: 1410
Re: ways to avoid begin-end’s?
« Reply #35 on: May 10, 2024, 11:54:02 am »
Sorry, inappropriate quoting at my side. My comment was quite more general.

As for the literal number, I use such quite often bitwise, e.g. OutOfPaper := DeviceStatus and 1, etc.
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

MarkMLl

  • Hero Member
  • *****
  • Posts: 8505
Re: ways to avoid begin-end’s?
« Reply #36 on: May 10, 2024, 12:56:35 pm »
As for the literal number, I use such quite often bitwise, e.g. OutOfPaper := DeviceStatus and 1, etc.

I think we all do, but I'm not sure we should: that's what sets based on enumerations are for.

However that does raise an interesting point. If you declare an enumeration (of e.g. result codes) e.g. associated with class tA, the last time I investigated there was no safe way of extending that when it was e.g. subclassed to tB. OK, you can obviously declare a more detailed enumeration, but that introduces the burden of making sure that the common part of the enumerations remains in step.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

kupferstecher

  • Hero Member
  • *****
  • Posts: 604
Re: ways to avoid begin-end’s?
« Reply #37 on: May 10, 2024, 02:08:39 pm »
Wouldn’t it be neat if I could say something like
Code: Pascal  [Select][+][-]
  1.  if x=1 then x:=2 AND DoSomething(x)

rather than currently
Code: Pascal  [Select][+][-]
  1. if x=1 then
  2.      begin
  3.        x:=2;
  4.        doSomething(x)
  5.      end;
  6.  

Why no custom formatting?
Code: Pascal  [Select][+][-]
  1. if x = 1 then begin x:=2; DoSomething(x); end;

Code: Pascal  [Select][+][-]
  1. if x = 1
  2. then begin x:= 2; DoSomething(x); end;

Code: Pascal  [Select][+][-]
  1. if x = 1
  2. then begin x:= 2; end
  3. else begin x:= 0; DoSomething(x); end;

Code: Pascal  [Select][+][-]
  1. if x = 1
  2. then begin x:= 2; DoSomething(x); end
  3. else begin x:= 0; DoSthElse(x); end;



Thaddy

  • Hero Member
  • *****
  • Posts: 18376
  • Here stood a man who saw the Elbe and jumped it.
Re: ways to avoid begin-end’s?
« Reply #38 on: May 10, 2024, 09:30:33 pm »
it is about avoiding begin end. As long as DoSomething returns true everyting is fine ;)
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

MarkMLl

  • Hero Member
  • *****
  • Posts: 8505
Re: ways to avoid begin-end’s?
« Reply #39 on: May 31, 2024, 11:09:35 pm »
Chained assignments, automatic type conversion, confusion between logical and bitwise operations...

I hope the community will tolerate my throwing this in as a belated illustration of just /how/ problematic that sort of thing can be.

Code: C  [Select][+][-]
  1. if ((options == (__WCLONE|__WALL)) && (current->uid = 0))
  2.         retval = -EINVAL;
  3.  

That was a backdoor that person-unknown attempted to get into the Linux kernel back in 2003, as discussed at https://lwn.net/Articles/57135/

HINT: consider carefully the placement of == and = in that.

The C-derivative community's response to that has been to mandate a style where comparisons have their less-mutable expression on the left, which reduces (but does not eliminate) the risk of a rogue assignment.

Frankly, this should not be necessary in a computer language: it is an abomination.

To spell it out: the result of (options == (__WCLONE|__WALL)) is a boolean, the result of (current->uid = 0) is an integer. The && (logical-and) operator should only be compatible with booleans, not integers or a mixture of the two.

ALL automatic type conversions are a problem, which is why Wirth became far more strict post-Pascal. In addition, many cases need to distinguish between a bitwise conversion (with assumed zero padding/removal) and functional conversion (e.g. between an integer and float with significant difference in representation): Modula-2 had distinct type-transfer and VAL() operations for this.

Two recent threads provide examples of these problems: https://forum.lazarus.freepascal.org/index.php/topic,67448.msg518992.html#msg518992 (where a boolean is extended to register size under certain conditions) and https://forum.lazarus.freepascal.org/index.php/topic,67215.msg516777.html#msg516777 where part of OP's confusion was apparently caused by a shift operator applied to a constant without an explicit associated size.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Thaddy

  • Hero Member
  • *****
  • Posts: 18376
  • Here stood a man who saw the Elbe and jumped it.
Re: ways to avoid begin-end’s?
« Reply #40 on: June 01, 2024, 04:29:36 pm »
Well, Mark, we have = and :=...
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

Warfley

  • Hero Member
  • *****
  • Posts: 2022
Re: ways to avoid begin-end’s?
« Reply #41 on: June 01, 2024, 05:11:31 pm »
C has such a feature, it's called a comma operator and it's pretty much the most disliked and least used C feature there is. Most C books don't even cover it for that reason.

Learn from the mistakes others made, just type begin end, it's not going to hurt you.

Also additionaly I'd even argue you should always use begin...end even for single statement blocks, because when you later want to change a single statement to a multi statement block (e.g. when adding logging), it can happen that you forget adding the begin end and just broke your control flow.

IMHO there should be an option to throw an error if there is no begin end. It would also fix this atrocious bug:
Code: Pascal  [Select][+][-]
  1. if condition then; // semicolon after ; closes the statement
  2. begin
  3.   Exit;
  4. end

440bx

  • Hero Member
  • *****
  • Posts: 5823
Re: ways to avoid begin-end’s?
« Reply #42 on: June 01, 2024, 06:01:33 pm »
It would also fix this atrocious bug:
Code: Pascal  [Select][+][-]
  1. if condition then; // semicolon after ; closes the statement
  2. begin
  3.   Exit;
  4. end
That "atrocious bug" is one of the features I love most about Pascal.

I very often code something like this:
Code: Pascal  [Select][+][-]
  1. if <some error condition> then
  2. begin
  3.   <error handling code>
  4. end;
  5.  
To test the error handling code, I force its execution by simply adding a semicolon after the "then" and recompiling.  This is a very convenient way of testing error handling code.

Also, I commonly put that semicolon in an {$ifdef test_error_handler} ; {$endif} that way I can choose which error handlers get tested.   Combine that with the judicious use of IsDebuggerPresent() and DebugBreak() and that semicolon activates tracing the code (which does not need to be present in the release version of the code.)  Good stuff all around... best "atrocious bug" in town. :)

I completely agree with you that begin/end should be used even when the language does not require them.  Makes maintenance much simpler and also makes debugging simpler and easier.
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

Warfley

  • Hero Member
  • *****
  • Posts: 2022
Re: ways to avoid begin-end’s?
« Reply #43 on: June 01, 2024, 07:00:48 pm »
Why not put // ( or put it between { and } ) in front of the line? It's more visible than the ; and changes the syntax highlighting to make it immediately visible this is deactivated

The chance that you accidentally overlook a semicolon is much higher than seeing a whole line being marked as a comment.

Also you can do this if begin end was forced, just instead of only ; put begin end; in there. That's much more visible and clearly signs that this is intentional and not a mistake

If you do something out of the ordinary it should require non Ordinary clearly visible syntax

440bx

  • Hero Member
  • *****
  • Posts: 5823
Re: ways to avoid begin-end’s?
« Reply #44 on: June 01, 2024, 07:58:59 pm »
Why not put // ( or put it between { and } ) in front of the line? It's more visible than the ; and changes the syntax highlighting to make it immediately visible this is deactivated
If I use a lone semicolon it's because I just want to immediately test the code and also immediately remove the semicolon after the code is tested.

when the error handling code is for a condition that is not "uncommon" then I put it between {$ifdef test_condition} ; {$endif} which, as you suggested, makes it very visible and repeatable by the activation of a define condition.

IOW, I basically agree with you that just using a semicolon is something that should only be done when it is extremely unlikely that it is going to be inadvertently forgotten.  The reason I don't use // instead is because that is a much bigger change in the code.  The semicolon doesn't remove the test condition, // does.  I want the test code to be as close as possible to the original code.
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

 

TinyPortal © 2005-2018