Recent

Author Topic: Ada style "for" loop counters  (Read 59904 times)

Leledumbo

  • Hero Member
  • *****
  • Posts: 8746
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Ada style "for" loop counters
« Reply #15 on: January 08, 2016, 05:25:30 am »
Feel free to talk and suggest whatever you have, but it would never be in the compiler unless someone wants to implement and maintain it and the dev team accepts the patch. The C-like operator was a legacy extension and the only one I consider as "mistake", but existing code might have used it already, hence it can't be removed. I always disable that though, thanks to the controllability through compiler option.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: Ada style "for" loop counters
« Reply #16 on: January 08, 2016, 09:56:06 am »

Not sure why you believe massive fonts make your reply better.

You noticed, didn't you ?  :)

Quote
The next point says:
The extension must have real value. Anything that is only a shorter notation does not apply, unless it is out of compatibility with an existing Pascal/Delphi codebase. Practically it means it must make something possible that cannot be done otherwise or be a compatibility item

My suggestion does not invalidate that notion at all except that it eliminates the _formal_ declaration of loop control variables.

Well, the netto result vs turning the current warning into an error is shorthand, so I think it does. 

But actually a quote the FAQ more because of the second part, making a complete proposal (e.g. you don't say anything about defining the loopvar type) making a decent plan and find implementation resources etc.

Suggestions are pretty pointless without.

Quote
Of course it would only apply to the fpc compiler versions that incorporate it and therefore to IDE's that use those fpc's.  Some editors/IDE's may flag it.  It could be directive flagged on/off in case there are SQA objections (just as the unholy abomination of C operators (    a+ = c    )).

For the record, I didn't like them when they were implemented, and still don't. But they originate before 2000, multi arch and current extension policies.

Quote
Yes, a
Then it goes onto:
The change must fit in with the scope of the project: implementing a Pascal compiler with support for RAD and a generic DB system. This excludes features like inline SQL, and large garbage collected object frameworks.

(and IMHO implicit inline declarations are not Pascal)

Quote
As to the rest, the desirability for such is obvious (at least to me) - it simplifies and accelerates coding and is a well proven language feature of the most safety/mission-critical oriented language that there ever has been (Ada). 

I don't put Ada on a pedestal. It went too far IMHO. Maybe it achieved its purposes for certain highly specialized industry (like defense and medical applications), but that is as much attributed (and probably, much, much more) to the general procedures to do projects in that field, and less the result of these kinds of safety micro-syntax.

I think in general people always want to implement more detail syntax optimization in the language, while the main issues of software engineering are much more in the libraries nowadays.

And I think these kind of borrowing syntax from all sides (that is incompatible with Delphi to start with) is pointless.
 

garlar27

  • Hero Member
  • *****
  • Posts: 652
Re: Ada style "for" loop counters
« Reply #17 on: January 08, 2016, 01:41:07 pm »
I'm sorry, in spite I understand what you wish and it's benefits. I also see what I think is a drawback:
   o- you will have a time pennalty when the for loop is nested inside another loop. Why? Because creating the variable and releasing it for each iteration.

You might think "well, compiler should add the index var to the method's init part" then compiler might get more complicated than needed just because "var section needs to gets simpler".

According to my experience:
   If var section has too many variables it can be caused by one of the following reasons:
   a- You are doing to much in a single method. You should split it.
   b- You have in hands a very rare method which is very complicated and can not be splitted. You should be very carefull with what you do and add comments to the var section as well as to the code. You will need it sooner than you might think  ;)

The same if a method has more than 50 lines and or it has 3 or more nestings (if, case, and or loops)

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9792
  • Debugger - SynEdit - and more
    • wiki
Re: Ada style "for" loop counters
« Reply #18 on: January 08, 2016, 02:12:45 pm »
There are a few issues.

1) auto determining the correct size of the integer type (word, int ,int64, un/signed)

IIRC (not tested) you can have overloaded procedures (word vs int). Without declaration there is a lack of clarity which one is called.

Further, if you change the return type of foo in "for a := 0 to foo", the loop will call a different foo function, that might do something completely different. (and yes there could be reasons why such overloaded functions may not be interchangeable). Similar for conflicts when mixing signed and unsigned.

2) "reserving" the identifier.
If "a" is in the var section then, I can see it is used. If it is not I might add a new boolean (or otherwise incompatible) "a", and get an error as it conflicts with the loop.

3) one identifier 2 types
Code: Pascal  [Select][+][-]
  1. begin
  2.   for a := 0 to 9 do write(a);
  3.   for a := false to true do write(a);
  4. end
  5.  
confusing, since "a" in the same procedure is at some time int, and then bool.

4)
Code: Pascal  [Select][+][-]
  1. for NameOfAGlobalVar :=
Hides a global var. Of course same can happen with any local var in the var section.
But if loop vars are no longer declared in the var block, then I must search *ALL* surrounding "for" statements, instead of just one var section.

5) There is no optional. Even if by default loop vars must be declared, and the proposal must be explicitly enabled (mode/flag).
Someone will use it, and eventually I will have to look at code that uses this.

BeniBela

  • Hero Member
  • *****
  • Posts: 905
    • homepage
Re: Ada style "for" loop counters
« Reply #19 on: January 08, 2016, 04:46:11 pm »

1) auto determining the correct size of the integer type (word, int ,int64, un/signed)

IIRC (not tested) you can have overloaded procedures (word vs int). Without declaration there is a lack of clarity which one is called.

The loop should promote all the small ints to at least integer



Further, if you change the return type of foo in "for a := 0 to foo", the loop will call a different foo function, that might do something completely different. (and yes there could be reasons why such overloaded functions may not be interchangeable).

That is a good thing.

Especially if combined with for .. in ... Then you can make a library and hide the implementation details of the container/elements. The user does not need to know what types he is iterating over, just what methods they have. It is like using the private modifier on the types itself.

 
4)
Code: Pascal  [Select][+][-]
  1. for NameOfAGlobalVar :=
Hides a global var. Of course same can happen with any local var in the var section.
But if loop vars are no longer declared in the var block, then I must search *ALL* surrounding "for" statements, instead of just one var section.

Do not search one var section. That is just plain wrong.

You already need to check the function arguments, too. And the class fields and  properties. The fields and properties of every class and record that is used in any surrounding with block


Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9792
  • Debugger - SynEdit - and more
    • wiki
Re: Ada style "for" loop counters
« Reply #20 on: January 08, 2016, 05:35:48 pm »

1) auto determining the correct size of the integer type (word, int ,int64, un/signed)

IIRC (not tested) you can have overloaded procedures (word vs int). Without declaration there is a lack of clarity which one is called.

The loop should promote all the small ints to at least integer
signed or unsigned? if it is int64 then this can affect comparison, depending on the other values sign.

If the function for the loop bounds changes in type, then the programs outcome may suddenly be unpredictable.

Quote

Further, if you change the return type of foo in "for a := 0 to foo", the loop will call a different foo function, that might do something completely different. (and yes there could be reasons why such overloaded functions may not be interchangeable).

That is a good thing.

Especially if combined with for .. in ... Then you can make a library and hide the implementation details of the container/elements. The user does not need to know what types he is iterating over, just what methods they have. It is like using the private modifier on the types itself.
Off topic (to my point): The type is always known at compile time (and for a library it can only depend on code inside the lib). So I do not see how your example can actually be achieved. But that is not the point I was making.

Let me make my example clearer.
Code: Pascal  [Select][+][-]
  1. procedure Bar(x: integer); overload;
  2. procedure Bar(x: int64); overload; // can not be used as replacement for the above
  3. ...
  4. for a := 0 to foo() do
  5.   bar(a);

If the "foo" changes in type, then the programs outcome may suddenly be unpredictable, because the other Bar() will not do the same thing (maybe it does act on a different set of data, and that set is not usable in the loop).

So the code will no longer work as it should. I cant see how this  is supposed to be a "good thing"

Quote
4)
Code: Pascal  [Select][+][-]
  1. for NameOfAGlobalVar :=
Hides a global var. Of course same can happen with any local var in the var section.
But if loop vars are no longer declared in the var block, then I must search *ALL* surrounding "for" statements, instead of just one var section.

Do not search one var section. That is just plain wrong.

You already need to check the function arguments, too. And the class fields and  properties. The fields and properties of every class and record that is used in any surrounding with block
Well aware of all the locations.
That does not change the validity of my point. The undeclared variable makes the search even more challenging.

Especially because it forces to repeat the work.
Right now, within a given procedure, I can establish for the entire procedure which "FOO" it refers to.
With the change, I need to repeat that search/verification, because FOO can have (any amount of) different meanings within a single procedure.
 
(Actually: using "with" blocks can cause similar issues, but the existence of one evil, is no reason to add a 2nd)
« Last Edit: January 08, 2016, 05:41:58 pm by Martin_fr »

BeniBela

  • Hero Member
  • *****
  • Posts: 905
    • homepage
Re: Ada style "for" loop counters
« Reply #21 on: January 08, 2016, 06:43:15 pm »
signed or unsigned? if it is int64 then this can affect comparison, depending on the other values sign.

If the function for the loop bounds changes in type, then the programs outcome may suddenly be unpredictable.

It always must be signed

Or it will blow up, when you write for i := 0 to list.length - 1 do ...
 
You cannot use int64 in a for-loop, or did that change? So it would always be int for numbers, so there is not much to change.

Off topic (to my point): The type is always known at compile time (and for a library it can only depend on code inside the lib). So I do not see how your example can actually be achieved.

I just discussed  that in another thread. Like this:

Code: [Select]
unit secret;

type TFoo = class
 ...
end;

unit public;
uses secret;
type TFoo = secret.TFoo;

Then you can uses public and get TFoo, but the implementation is in secret.

If you do it now, Lazarus's code tools will import secret and declare a type var v: secret.TFoo; which is not helpful. Worse than putting it in an include file.


Let me make my example clearer.
Code: Pascal  [Select][+][-]
  1. procedure Bar(x: integer); overload;
  2. procedure Bar(x: int64); overload; // can not be used as replacement for the above
  3. ...
  4. for a := 0 to foo() do
  5.   bar(a);

Such a  bar should not be in the program anyways.


Especially because it forces to repeat the work.
Right now, within a given procedure, I can establish for the entire procedure which "FOO" it refers to.
With the change, I need to repeat that search/verification, because FOO can have (any amount of) different meanings within a single procedure.
 
(Actually: using "with" blocks can cause similar issues, but the existence of one evil, is no reason to add a 2nd)

But it is just a single varible / for. A single with can bring an unlimited number of them

And usually i, j, .., then you know that they mean the nearest for loop


Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9792
  • Debugger - SynEdit - and more
    • wiki
Re: Ada style "for" loop counters
« Reply #22 on: January 08, 2016, 07:12:31 pm »
signed or unsigned? if it is int64 then this can affect comparison, depending on the other values sign.

If the function for the loop bounds changes in type, then the programs outcome may suddenly be unpredictable.

It always must be signed

Or it will blow up, when you write for i := 0 to list.length - 1 do ...
 
You cannot use int64 in a for-loop, or did that change? So it would always be int for numbers, so there is not much to change.
Of course you can use unsigned. length/count - 1 is not the only upper bound.

If both bound are positive then unsigned loop vars will work just fine.

Quote
Code: [Select]
unit secret;

type TFoo = class
 ...

Then you can uses public and get TFoo, but the implementation is in secret.

If you do it now, Lazarus's code tools will import secret and declare a type var v: secret.TFoo; which is not helpful. Worse than putting it in an include file.
off topic, but if you want a different behaviour from codetools then suggest a change/option for that. dont change the pascal language

Quote
Code: Pascal  [Select][+][-]
  1. procedure Bar(x: integer); overload;
  2. procedure Bar(x: int64); overload; // can not be used as replacement for the above
  3. ...
  4. for a := 0 to foo() do
  5.   bar(a);

Such a  bar should not be in the program anyways.
Why? it could be a AdjustMax(arg) that keeps different value for each type of param. Then GetMax(out argOfSameType) to get the value.
Sure this could be coded better. But it is valid code, and someone might have a good reason.

As far as opinions go, IMHO it is still better than omitting the declaration of loop var.

Or it could be overloaded operators for an enum (a for loop can loop an enum). change the type of the enum, and it will no longer work.

Or a type helper, that depends on the type.

The end is: without declaring the loop var, its type can change. This change may compile, but break at run time.
If the type is fixed in the declaration, then it cant change. You may get an error at compile time, but that is (in almost all cases) so much easier to find and fix than a runtime error.

Quote
Right now, within a given procedure, I can establish for the entire procedure which "FOO" it refers to.
With the change, I need to repeat that search/verification, because FOO can have (any amount of) different meanings within a single procedure.
 
(Actually: using "with" blocks can cause similar issues, but the existence of one evil, is no reason to add a 2nd)

But it is just a single variable / for. A single with can bring an unlimited number of them

And usually i, j, .., then you know that they mean the nearest for loop
There can be 100 nested and/or in-sequence loops (well 100 may be an urgent case for refactor, but anyway).

Also as I said: "the existence of one evil, is no reason to add a 2nd"

DelphiFreak

  • Sr. Member
  • ****
  • Posts: 255
    • Fresh sound.
Re: Ada style "for" loop counters
« Reply #23 on: January 08, 2016, 08:28:46 pm »
Sooner or later someone will ask here, if we could make Pascal become "cAseSenSensiTIVE".   :D
Linux Mint 20.3, Lazarus 2.3, Windows 10, Delphi 10.3 Rio, Delphi 11.1 Alexandria

balazsszekely

  • Guest
Re: Ada style "for" loop counters
« Reply #24 on: January 08, 2016, 08:31:21 pm »
Quote
@DelphiFreak
Sooner or later someone will ask here, if we could make Pascal become "cAseSenSensiTIVE".   :D
Believe it or not, somebody already asked to replace begin end with {}.

AlanTheBeast

  • Sr. Member
  • ****
  • Posts: 348
  • My software never cras....
Re: Ada style "for" loop counters
« Reply #25 on: January 08, 2016, 09:45:41 pm »
I think it shall be SynEditor-Autocomplete's job. Or be CodeTool's job.


So, (no matter AutoComplete or CodeTool) must be easy to able to write "var i : longint" into correct place within the procedure, somehow .

Which is not the proposition. 

The proposition is to eliminate the formal declaration of for loop control variables altogether and make them intelligently implicit (derived type from context - in that sense no different than what you propose - except no modification would be made to the source code.  Further, in the first instance of "i" in my example the type would be word; in the second instance the type would be longint).

Everyone talks about the weather but nobody does anything about it.
..Samuel Clemens.

AlanTheBeast

  • Sr. Member
  • ****
  • Posts: 348
  • My software never cras....
Re: Ada style "for" loop counters
« Reply #26 on: January 08, 2016, 09:54:23 pm »
I like the idea.

Some variables do not deserve to be in the VAR list! They just increase the line of code and make the code less readable.

Precisely.

What I am not sure is why one should stop with just the loop variables: Why should not Pascal allow all the variables to be like this?  Essentially it is like the "auto" type in C++.

I would never agree to auto typing, generally.  Formalism has its place and that's why Ada has taken so much from Pascal.

OTOH, the Ada designers also realized that simple for loop controls were very often trivial and didn't need the formalism of a declaration.  So they leave it to the programmer to decide "hey, this thing counts from 1 to 10, big deal" and you don't declare it; OR "hey, this variable is very important to the understanding of the code, so let's declare it and make it clear what it does".


As I said, I like the idea but I think it needs a deep understanding of its consequences.

I believe them to be shallow in impact and clearly do not affect code from the past.  The impact on debuggers can be mitigated by symbol generation that lists each repeated temp variable with an appendage ( I_1, I_2, ...).  The only conseuence, really, is once you code with it you're restrained to compliant compilers (duh) and some might find that limiting enough.

Thanks for your positive support!
Everyone talks about the weather but nobody does anything about it.
..Samuel Clemens.

AlanTheBeast

  • Sr. Member
  • ****
  • Posts: 348
  • My software never cras....
Re: Ada style "for" loop counters
« Reply #27 on: January 08, 2016, 10:11:40 pm »
Anyway, my suggestion is based on what AlanTheBeast described by himself in first post:
Quote
Note that such a change has no impact on any existing code but would make future coding less work
So, if you want to code faster less work, let the SynEdit do that (by using autocomplete / codetool?)

No.  That means the VAR declaration is still cluttered with trivial things that are not very useful to understanding or maintaining the code.  That is another benefit of the proposal: cleaner code that is less maintenance over the life cycle of the code.  (I'm still using stuff from the late 80's).

Example: "initialization"/"finalization" added to units.  Obviating declaring a save pointer to save the default pointer to finish the unit and restoring during the execution of that procedure; obviated setting a pointer to that finalization code -  those are still there under the hood, but the code is clearer and much more readable without them).

Quote from: AlanTheBest
Finally, Pascal now allows the abomination of C operations like       a+ = c      albeit permitted by compiler directive (relief - may it never see my machine).

Now that is awful.  Stupid.  Insane bad style.  Just as bad as curly braces.  Of course that's not at all what I've suggested.
I didn't know when fpc allow a+=c,
but if fpc did, the variables still must be declared in exact type, aren't they?

Yep: http://www.freepascal.org/docs-html/prog/progsu10.html

Of course they need to be declared as they are operated on.  I'm referring to the most simple of "counter" types.

I was attempting to make the point that some in the fpc community are allowing abominable things from the cess pit of c - and mine is not abominable - indeed it's blessed by the designers of Ada!

@AlanTheBest: if you really dislike to declare variable (is it the stupid awful?), use python!
No, do't be offended. Just maybe the best you can get: never typed-variable at all. it help you less work.

You can use insults all you like, but the fact is there are primitive things that don't need the formalism of a cluttered VAR list.  The Ada designers (who had a much more critical/safety mission in mind) recognized this despite all that they took from Pascal. 

You are not disallowed from declaring - you are given the permission to decide: oh, hell, another "i" variable is needed.  ...  OTOH, the variable might be CRITICAL_TABLE_EVENT_INDEX.  Hmm, maybe that one should go in the VAR list with a bit of explanation.

This suggestion is as much about readability and reducing errors as it is about less work and life cycle management of the source code.
Everyone talks about the weather but nobody does anything about it.
..Samuel Clemens.

AlanTheBeast

  • Sr. Member
  • ****
  • Posts: 348
  • My software never cras....
Re: Ada style "for" loop counters
« Reply #28 on: January 08, 2016, 10:25:32 pm »

Well, the netto result vs turning the current warning into an error is shorthand, so I think it does. 

But actually a quote the FAQ more because of the second part, making a complete proposal (e.g. you don't say anything about defining the loopvar type) making a decent plan and find implementation resources etc.

Suggestions are pretty pointless without.


Suggestions start somewhere.  I think I've been very clear about what the intent and limitations are as well as some of the challenges.  With support, then I'd be happy to write a more detailed proposal and flesh out the idea much further.  But some signal that it would be seriously considered would be welcome.  The more conservative will say "don't need it" the more flexible will say "doesn't hurt me" (or "go ahead - I'll turn it off").


Quote
Of course it would only apply to the fpc compiler versions that incorporate it and therefore to IDE's that use those fpc's.  Some editors/IDE's may flag it.  It could be directive flagged on/off in case there are SQA objections (just as the unholy abomination of C operators (    a+ = c    )).
For the record, I didn't like them when they were implemented, and still don't. But they originate before 2000, multi arch and current extension policies.

Quote
Then it goes onto:
The change must fit in with the scope of the project: implementing a Pascal compiler with support for RAD and a generic DB system. This excludes features like inline SQL, and large garbage collected object frameworks.

(and IMHO implicit inline declarations are not Pascal)

No, but then a lot of things have changed in Pascal over the years.

Quote
As to the rest, the desirability for such is obvious (at least to me) - it simplifies and accelerates coding and is a well proven language feature of the most safety/mission-critical oriented language that there ever has been (Ada). 

I don't put Ada on a pedestal. It went too far IMHO. Maybe it achieved its purposes for certain highly specialized industry (like defense and medical applications), but that is as much attributed (and probably, much, much more) to the general procedures to do projects in that field, and less the result of these kinds of safety micro-syntax.

I think in general people always want to implement more detail syntax optimization in the language, while the main issues of software engineering are much more in the libraries nowadays.

And I think these kind of borrowing syntax from all sides (that is incompatible with Delphi to start with) is pointless.

Actually this is borrowing the absence of syntax  ;).

It is also is why I stated Pascal's influence on Ada from the start.  Yes, Ada can be huge, hairy and immovable, but it did improve disciplined programming in a lot of ways.  IMO, borrowing the simple loop control from Ada for Pascal would be in the best traditions of making Pascal a stronger language that is easier to write, read, debug and maintain.
Everyone talks about the weather but nobody does anything about it.
..Samuel Clemens.

AlanTheBeast

  • Sr. Member
  • ****
  • Posts: 348
  • My software never cras....
Re: Ada style "for" loop counters
« Reply #29 on: January 08, 2016, 11:01:53 pm »

1) auto determining the correct size of the integer type (word, int ,int64, un/signed)

IIRC (not tested) you can have overloaded procedures (word vs int). Without declaration there is a lack of clarity which one is called.

Further, if you change the return type of foo in "for a := 0 to foo", the loop will call a different foo function, that might do something completely different. (and yes there could be reasons why such overloaded functions may not be interchangeable). Similar for conflicts when mixing signed and unsigned.

I believe that would be a case where a would have to be declared a priori -if- foo was indeed overloaded to the point that the correct type for a could not be determined at compile time.

2) "reserving" the identifier.
If "a" is in the var section then, I can see it is used. If it is not I might add a new boolean (or otherwise incompatible) "a", and get an error as it conflicts with the loop.

Short answer: no big deal - the error will be at compile time.

3) one identifier 2 types
Code: Pascal  [Select][+][-]
  1. begin
  2.   for a := 0 to 9 do write(a);
  3.   for a := false to true do write(a);
  4. end
  5.  
confusing, since "a" in the same procedure is at some time int, and then bool.

Confusion is in the eye of the beholder.  To be sure an Ada programmer is used to this notion and would not worry about it.  At the point where the context of "a" expires he knows it simply no longer exists.

I'd add that for style a programmer would be less likely to use this feature for false true loops (I think).  They're a bad idea in any case since one assumes false is 0 and true is 1 - so for to works - but what if it's the reverse and downto is needed....)

4)
Code: Pascal  [Select][+][-]
  1. for NameOfAGlobalVar :=
Hides a global var. Of course same can happen with any local var in the var section.
But if loop vars are no longer declared in the var block, then I must search *ALL* surrounding "for" statements, instead of just one var section.

That's very true. OTOH, the usual variable names for such are quite short (i, j, k, m, n, p, q) and usually used over a short number of lines of code.

Further, the use of simple loop control variables in a procedure should (generally) not use globally declared variable names; in turn global variable names should (generally) not be simple and undescriptive as simple loop variables typically (i,j, ..) are.  Yes, that 's style to an extent.


5) There is no optional. Even if by default loop vars must be declared, and the proposal must be explicitly enabled (mode/flag).
Someone will use it, and eventually I will have to look at code that uses this.

Bwahahahahaahahahahahahah!!!!!  :D
Everyone talks about the weather but nobody does anything about it.
..Samuel Clemens.

 

TinyPortal © 2005-2018