Recent

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

PascalDragon

  • Hero Member
  • *****
  • Posts: 5446
  • Compiler Developer
Re: Question ?!!!!
« Reply #45 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: 1829
    • http://wiki.lazarus.freepascal.org/User:Zoran
Re: Question ?!!!!
« Reply #46 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: 14201
  • Probably until I exterminate Putin.
Re: Question ?!!!!
« Reply #47 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 »
Specialize a type, not a var.

BeniBela

  • Hero Member
  • *****
  • Posts: 905
    • homepage
Re: Question ?!!!!
« Reply #48 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: 14201
  • Probably until I exterminate Putin.
Re: Question ?!!!!
« Reply #49 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.
Specialize a type, not a var.

munair

  • Hero Member
  • *****
  • Posts: 798
  • compiler developer @SharpBASIC
    • SharpBASIC
Re: Question ?!!!!
« Reply #50 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 »
keep it simple

Thaddy

  • Hero Member
  • *****
  • Posts: 14201
  • Probably until I exterminate Putin.
Re: Question ?!!!!
« Reply #51 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 »
Specialize a type, not a var.

munair

  • Hero Member
  • *****
  • Posts: 798
  • compiler developer @SharpBASIC
    • SharpBASIC
Re: Question ?!!!!
« Reply #52 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 »
keep it simple

PascalDragon

  • Hero Member
  • *****
  • Posts: 5446
  • Compiler Developer
Re: Question ?!!!!
« Reply #53 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: 798
  • compiler developer @SharpBASIC
    • SharpBASIC
Re: Question ?!!!!
« Reply #54 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.
keep it simple

440bx

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

smaniok

  • Newbie
  • Posts: 3
Re: Question ?!!!!
« Reply #56 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: 14201
  • Probably until I exterminate Putin.
Re: Question ?!!!!
« Reply #57 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 »
Specialize a type, not a var.

440bx

  • Hero Member
  • *****
  • Posts: 3944
Re: Question ?!!!!
« Reply #58 on: June 01, 2020, 12:21:51 pm »
in my oppinion it brings too much overload to the language syntax.
On the contrary, unlike inline variables it does not overload the "begin" and "end" keywords as block delimiters.

I think a feature like this is justified only if it brings considerable gains in performance.
That feature has nothing to do with performance.  It wouldn't affect performance one way or the other.  What that feature is about is localizing constant, type and variable definitions within a function/procedure.  That means, instead of potentially having a significant number of locals, which turn out to be globals within the function/procedure/method, it would allow a much smaller number of locals because "throw away temporary variables" would be confined to the scope.  That would make the code easier to understand and maintain.

By the way, would not this syntax cause some confusion with a possible future implementation of anonymous methods?
It shouldn't.  Inline scopes should always be identified by a keyword to indicate their presence.


Delphi actually allows scoping inline variables if you put then INSIDE a nested begin..end block.
THAT is syntax overloading.  "begin"/"end" are very poor block delimiters.  The reason is, in a Pascal block, the programmer is supposed to be able to declare constants and types but, apparently these block features would not be available by overloading "begin"/"end".  Overloading "begin"/"end" as block delimiters is just a hack.  Another "writable constants" bright idea.

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;
That's not the only potential problem with type inference.  Pascal's strong type checking depends on explicit type declarations, type inference has the potential to create situations where the compiler would infer a type that is not the one the programmer had in mind.

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.  
With inline scopes you can do that and then some, all without altering the way variables are declared.

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.
Too late for that.  If memory serves, writable constants were the first "Frankengimmick" that Borland put into Pascal and, unfortunately, far from the last one.

Fortunately, or maybe unfortunately, it's quite likely that the probability of seeing the Pope named the sexiest male on earth is likely greater than seeing inline scopes implemented in FPC.



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..
And how would a two dimensional array "A" element be addressed ?... A[index, index] ? being able to address only the elements on the diagonals of square arrays doesn't seem to be a very useful "feature".

As far as controlling repetitions, that nested loop is basically a convoluted way of writing "for i := 1 to 25 do ;"  The other examples you showed have the same problems.

(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Thaddy

  • Hero Member
  • *****
  • Posts: 14201
  • Probably until I exterminate Putin.
Re: Question ?!!!!
« Reply #59 on: June 01, 2020, 01:03:28 pm »
They are not really problems for the compiler side. But as I stated many times that I find it important that declaration and implementation are separated. Such constructs as I presented are cleaner though, because of inference and there is less wrong with that.
I'd rather see only inference for those kind of instructions than explicit declarations in an implementation part: that is NOT Pascal.
IF such things are implemented, try to keep the separation, is more or less my way of thinking.
Many C and C++ programmers agree, btw, - e.g. Linus Torvalds - inline declarations are evil. Perhaps apart from loop variables as intrinsic.
Not from a point of convenience, but from a point of maintainability and team work.
People tend to focus on convenience..., which is wrong for large code bases.
« Last Edit: June 01, 2020, 01:11:38 pm by Thaddy »
Specialize a type, not a var.

 

TinyPortal © 2005-2018