Recent

Author Topic: Question ?!!!!  (Read 13113 times)

ASerge

  • Hero Member
  • *****
  • Posts: 1796
Re: Question ?!!!!
« Reply #45 on: April 24, 2020, 02:10:45 pm »
However I do think that we are missing some syntax sugar. For example implementing unified try-except-finally block would bring more clarity to complex code since FreePascal does not have garbage collector and we already have to use try-finally block in order to avoid memory leaks and make sure that each object creation always ends with destruction:
Code: Pascal  [Select][+][-]
  1. try
  2.   ..
  3. except
  4.   ..
  5. finally
  6.   ..
  7. end;
I strongly disagree. These are two different expressions. The fact that they are united by the word "try" is not a reason for their combined. Moreover, most likely, you mean (will also have to strain attention) a more frequent option:
Code: Pascal  [Select][+][-]
  1. try
  2.   try
  3.   finally
  4.   end;
  5. except
  6. end;
But in most languages where the construction is combined, the following is assumed:
Code: Pascal  [Select][+][-]
  1. try
  2.   try
  3.   except
  4.   end;
  5. finally
  6. end;
Combining will cause the habit of doing extra initialization of the variable that will be in the finally block, precisely because the blocks are combined and you need to somehow mark the situation when the resource was not allocated. A couple of years ago, here on the forum, I gave the code that investigated the sources of Delphi 7 for try blocks. The vast majority (more than 90%) are try finally blocks. For me, this is normal and for the sake of the remaining percent there is no point in combining.

440bx

  • Hero Member
  • *****
  • Posts: 2372
Re: Question ?!!!!
« Reply #46 on: April 24, 2020, 02:26:00 pm »
We can agree that we disagree. I do not have a problem to stay it that way.
I understand and have no problem in agreeing to disagree.

I just want to mention that I did qualify that it is a nice feature when it is not abused/misused.    When abused and/or misused, just like any other feature, it can make things complicated.
FPC v3.0.4 and Lazarus 1.8.2 on Windows 7 64bit.

PascalDragon

  • Hero Member
  • *****
  • Posts: 3075
  • Compiler Developer
Re: Question ?!!!!
« Reply #47 on: April 24, 2020, 02:58:53 pm »
However I do think that we are missing some syntax sugar. For example implementing unified try-except-finally block would bring more clarity to complex code since FreePascal does not have garbage collector and we already have to use try-finally block in order to avoid memory leaks and make sure that each object creation always ends with destruction:
Code: Pascal  [Select][+][-]
  1. try
  2.   ..
  3. except
  4.   ..
  5. finally
  6.   ..
  7. end;

No, we don't miss that. In most cases you'll have the following scheme:

Code: Pascal  [Select][+][-]
  1. try
  2.   somevar := AcquireResource; // e.g. call a constructer
  3.   try
  4.     DoSomething(somevar);
  5.   finally
  6.     ReleaseResource(somevar); // e.g. Free
  7.   end;
  8. except
  9.   HandleException;
  10. end;

The point here is that you protect the whole handling of the resource including its acquisition with a tryexcept block while only the dealing with the acquired resource is protected by a tryfinally block. This way one does not need to care about the value of somevar. What is suggested with the combined block however is this:

Code: Pascal  [Select][+][-]
  1. try
  2.   try
  3.     somevar := AcquireResource;
  4.     DoSomething(somevar);
  5.   finally
  6.     ReleaseResource(somevar);
  7.   end;
  8. except
  9.   HandleException;
  10. end;

If AcquireResource raises an exception then no value is assigned to somevar so ReleaseResource might work on garbage thus resulting in another crash. This means that you need to manually ensure that somevar is valid (e.g. by doing a somevar := Nil if it's a class instance variable before the tryfinallyexcept block). And no, it does not matter whether the finally is first or the except is first. The initialization is required either way.

We had a thread on one of the mailings lists some years ago where this was discussed till exhaustion (cause someone had suggested this feature again) and we've rejected it back then as well... A pity I can't find that thread anymore...

Zoran

  • Hero Member
  • *****
  • Posts: 1670
    • http://wiki.lazarus.freepascal.org/User:Zoran
Re: Question ?!!!!
« Reply #48 on: April 24, 2020, 03:47:40 pm »
Inline variables is a nice feature
We can agree that we disagree. I do not have a problem to stay it that way.

Avra, you cut the main part of 440bx's sentence:

Inline variables is a nice feature provided it is well implemented.

Did you read what 440bx actually suggested (see here)?

That is something quite different from what Delphi introduced. These would be actually "block scope" varables, not "inline" variables. And, unlike Delphi's inline variables, I would like to have it. Declaring a variable in a scope as small as possible is a good practise, at least it is very helpful in debugging.

I fully agree with you that inline variables, implemented as in Deplhi, are a bad feature. Hopefully, FPC will never follow this.

Thaddy

  • Hero Member
  • *****
  • Posts: 10785
Re: Question ?!!!!
« Reply #49 on: April 24, 2020, 03:57:37 pm »
I fully agree with you that inline variables, implemented as in Deplhi, are a bad feature. Hopefully, FPC will never follow this.
Yes. Again, if only because the separation of declaration and implementation is an essential Pascal feature. Although I am less against type inference inside implementation blocks. That achieves the same but is less error prone.
I'd rather not see it, but e.g. extend the meaning of index to ordinal types for use in loops would not be too intrusive. That can be type inferred.
Code: Pascal  [Select][+][-]
  1. for index := 0 to 9 do; // index is type inferred as a loop variable and index is now an extended language element
Such code would be like declaring i as index variable and then loop. i stands already for index for most programmers.
Problem is nested loops (i,j,k), maybe:
Code: Pascal  [Select][+][-]
  1. for index(0) := 0 to 9 do for index(1) := 10 to 90;//etc
Although this may be solved by the compiler since that knows inner from outer loops..
Code: Pascal  [Select][+][-]
  1. for index := 0 to 9 do for index := 10 to 90;// get the point.
Then again less readable than separation.
OTOH inline variables seem to be mainly used for loops, so what do you think?
« Last Edit: April 24, 2020, 04:26:14 pm by Thaddy »

BeniBela

  • Hero Member
  • *****
  • Posts: 794
    • homepage
Re: Question ?!!!!
« Reply #50 on: April 24, 2020, 06:10:12 pm »
Point 1 is not an issue because using the iterator for something else before the loop means it should be regarded as a normal variable (which it is) that might need initialization.

Point 2 depends on compiler policy. For example, I remember from QuickBASIC that if a loop completes, the iterator was always max_iter_value + 1  and when the loop was short-cut, the iterator returned the value of the last iteration. There was never an ambiguous situation.

I do not see the problem with point 3 either. Although I cannot remember ever having used a global variable in a sub-scope as iterator, the state of the variable during and after the loop is the same as any other iterator. Naturally, if the iterator is not declared in the respective scope, the compiler will try to find a match in an encompassing scope or the global scope, but that is entirely the programmer's responsibility. In this respect, good programming practice is key and no compiler can beat that.

FreePascal just has the worst policy. The variable becomes uninitialized, but fpc often  does not show a warning about it when using uninitialized variables.


The problem with 3 is that two functions can use the same global variable as loop iterator. And when one function calls the other function in the loop, the outer loop might never terminate.

Modern compilers enforce good programming practice.






With inline variables and the new managed records, there would be an alternative to the try..except..finally:


Code: Pascal  [Select][+][-]
  1.     try
  2.       var somevar: SMARTPOINTER := AcquireResource; // e.g. call a constructer
  3.       DoSomething(somevar);
  4.     except
  5.       HandleException;
  6.     end;
  7.  

Thaddy

  • Hero Member
  • *****
  • Posts: 10785
Re: Question ?!!!!
« Reply #51 on: April 24, 2020, 06:51:29 pm »
Code: Pascal  [Select][+][-]
  1.     try
  2.       var somevar: SMARTPOINTER := AcquireResource; // e.g. call a constructer
  3.       DoSomething(somevar);
  4.     except
  5.       HandleException;
  6.     end;
  7.  
Thanks for ruining my eyesight. Horrible, and against Pascal principles.

munair

  • Hero Member
  • *****
  • Posts: 699
  • keep it simple
    • SharpBASIC
Re: Question ?!!!!
« Reply #52 on: April 24, 2020, 07:08:46 pm »
FreePascal just has the worst policy. The variable becomes uninitialized, but fpc often  does not show a warning about it when using uninitialized variables.

Yep, not good.

Quote
The problem with 3 is that two functions can use the same global variable as loop iterator. And when one function calls the other function in the loop, the outer loop might never terminate.

I would always advice against the use of a global variable as iterator in a local loop. Compilers can warn about that or even disallow it. But then it should also check inc/dec of variables inside loops like repeat... and while...
« Last Edit: April 24, 2020, 07:10:25 pm by Munair »

Thaddy

  • Hero Member
  • *****
  • Posts: 10785
Re: Question ?!!!!
« Reply #53 on: April 24, 2020, 07:39:45 pm »
Or this sidenote:
Code: Pascal  [Select][+][-]
  1. {$mode delphi}{$H+}
  2. var
  3.   i:integer;
  4. begin
  5.   for i := 0 to 10 do
  6.   begin
  7.     writeln(i);
  8.     inc(pinteger(@i)^);
  9.   end;    
  10. end.
It is not only globals....maybe a defined inferred index variable is a good idea after all

(code also works in Delphi)
« Last Edit: April 24, 2020, 07:41:43 pm by Thaddy »

munair

  • Hero Member
  • *****
  • Posts: 699
  • keep it simple
    • SharpBASIC
Re: Question ?!!!!
« Reply #54 on: April 25, 2020, 08:15:05 am »
I haven't checked what code FPC generates with inline variables. However, with for-loops the undefined state of the iterator has a disadvantage. I remember using the iterator - in particular if the loop was shortcut - as flag and also as upper bound index. It would require an additional variable to do the counting if the iterator itself cannot be used afterwards.

Point is, without making things complicated, you keep the natural state. In the following example 'i' returns its natural state after the loop, which is always max_iter + 1 guaranteed and if the loop was short-cut, 'i' returns the number of iterations (i <= max_iter). IOW it doesn't need to be set or adjusted afterwards by the compiler to return that result.
« Last Edit: April 25, 2020, 09:36:20 am by Munair »

PascalDragon

  • Hero Member
  • *****
  • Posts: 3075
  • Compiler Developer
Re: Question ?!!!!
« Reply #55 on: April 25, 2020, 03:38:07 pm »
FreePascal just has the worst policy. The variable becomes uninitialized, but fpc often  does not show a warning about it when using uninitialized variables.

FPC does warn/hint/note about uninitialized variables. However in case of a for-loop the counter variables becomes undefined (at least if the loop isn't left with a break or goto). I agree however that FPC should warn/hint/note in this case.

munair

  • Hero Member
  • *****
  • Posts: 699
  • keep it simple
    • SharpBASIC
Re: Question ?!!!!
« Reply #56 on: April 28, 2020, 11:53:56 am »
A scope has the same characteristics as a function/procedure except it is not callable.
... and doesn't pass parameters.

440bx

  • Hero Member
  • *****
  • Posts: 2372
Re: Question ?!!!!
« Reply #57 on: April 28, 2020, 11:59:59 am »
... and doesn't pass parameters.
Correct. :)
FPC v3.0.4 and Lazarus 1.8.2 on Windows 7 64bit.

smaniok

  • Newbie
  • Posts: 3
Re: Question ?!!!!
« Reply #58 on: June 01, 2020, 07:48:10 am »
A scope has the same characteristics as a function/procedure except it is not callable.  It can only be inside a function/procedure.  That is fully consistent with the essence of Pascal and offers some very nice abilities.  For instance...
Code: Pascal  [Select][+][-]
  1. SomeProc(parameters : types, ...);
  2. const
  3.   aconst : 123;
  4. type
  5.   sometype = 1..10;
  6. var
  7.   whatever : sometype;
  8. begin
  9.   statement;
  10.   statement;
  11.   ...
  12.   scope step1;
  13.   { any definitions/declarations within a scope are local to the scope }
  14.     type
  15.       scopetype = sometype;
  16.     const
  17.       scopeconst = 3;
  18.     var
  19.       scopevar : integer;
  20.   begin
  21.     statement;
  22.     statement;
  23.  
  24.     if somecondition then break; { breaks out of the scope - not the function/procedure - just like in a loop }
  25.  
  26.     statement;
  27.     statement;
  28.   end;
  29.  
  30.   scope step2;
  31.   begin
  32.    statement;
  33.    statement;
  34.    ...
  35.   end;
  36. end;
  37.  

Your suggestion for scoped block declaration is more Pascal-like than the Delphi implementation, but in my oppinion it brings too much overload to the language syntax. I think a feature like this is justified only if it brings considerable gains in performance. By the way, would not this syntax cause some confusion with a possible future implementation of anonymous methods? Just saying because it seems similar to Delphi's anonymous methods syntax (of course I don't know if FPC plans to implement the same way), only differs the lack of the procedure keyword, like in this case:

Code: Pascal  [Select][+][-]
  1. procedure TMyClass.DoSomething;
  2. type
  3.   TProc = reference to procedure;
  4. var
  5.   Proc: TProc;
  6. begin
  7.   Proc := procedure
  8.   var
  9.     a: string;
  10.   begin
  11.     a := 'Hello';
  12.     ShowMessage(a);
  13.   end;
  14.   Proc;
  15. end;
  16.  

But getting back to the subject, I am not totally against the Delphi way of implementing inline variables.

So, var section must be just above begin keyword. Then varible has block-scope.
Then, these are truly block-scope variables, not just "inline variables", that Emarcadero introcuded.

Delphi actually allows scoping inline variables if you put then INSIDE a nested begin..end block. Type inference makes some assignments a little less redundant to write and adds simplicity to the code. The only negative point I see is the syntax that not follows the original Pascal concepts of declaring everything BEFORE the begin..end;

However, I wish I could declare a variable in a loop like this in FPC:
Code: Pascal  [Select][+][-]
  1. for var i := 1 to 5 do
  2.  
but I understand that if it costs turning the language into a Frankenstein, with various pieces without consistency, I prefer FPC stays the way it is.

Thaddy

  • Hero Member
  • *****
  • Posts: 10785
Re: Question ?!!!!
« Reply #59 on: June 01, 2020, 10:32:53 am »
hence I suggested for the latter example to create index as a keyword. The compiler can know that an index variable is required, even nested, and the ugly var is gone.
Code: Pascal  [Select][+][-]
  1. // in this case suppose index is a keyword, requesting the compiler to create it
  2. for index := 0 to 4 do
  3.   for index := 3 to 7 do;
  4.  
Effect is the same, but I believe the syntax is a lot cleaner..
Other example I thought of is to extend for to forindex, like:
Code: Pascal  [Select][+][-]
  1.  
  2. // this assumes forindex is a new keyword in the for family
  3. forindex :=0 to 4 do
  4.   forindex := 3 to 7 do;

And I also thought of simply:
Code: Pascal  [Select][+][-]
  1. for 0 to 4 do
  2.   for 3 to 7 do;
All are to simplify for loop syntax. All are possible. All are things that are not necessary, but at least they are more natural.
« Last Edit: June 01, 2020, 10:39:07 am by Thaddy »

 

TinyPortal © 2005-2018