-Se<x> Error options. <x> is a combination of the following:
<n> : Compiler halts after the <n> errors (default is 1)
w : Compiler also halts after warnings
n : Compiler also halts after notes
h : Compiler also halts after hints
People who keep insisting on introducing such non-sense clearly have no idea about the origin and idea's behind pascal programming language.
Such features adds complexity, introduces inconsistency and is plain ugly to debug. On the fly-untyped variables... *barf*
first check
http://www.freepascal.org/faq.var#extensionselect
before suggesting language features[/b][/size]
In this case just change warnings to errors, and you have the safety part:Quote-Se<x> Error options. <x> is a combination of the following:
<n> : Compiler halts after the <n> errors (default is 1)
w : Compiler also halts after warnings
n : Compiler also halts after notes
h : Compiler also halts after hints
Non declaration is shorthand, and the extension faq covers that.
It is not complexity - it is simplicity. I'd venture that 90% or more of my loop control variables are named i,j,k,m,n,p,q (in about that order) and that 90% of them, further, are used for 15 lines of code, or less (maybe more if nested deep enough). They are ephemeral by their nature.Of course they are ephemeral by their nature. But really, in all those discussion i have seen and what i miss in your arguments as well, what on earth is the benefit of having scoped variables (let alone having them as untyped ones).
What I suggest is very natural however. In context, any programmer can see that a for loop needs an index. Needing to declare a type for it is quite redundant. Using the correct type for it is something the compiler can divine easily enough from the range or type of the begin/end values of the loop.That we as humans/programmer see this as natural, i will not disagree with.
Although i'm fairly new as in having an account over here, i watch these forums for quite some time now, and believe it or not the proposal of wanting to introduce on the fly or scoped variables is a topic that passes here on the forums as well as on mailing list every couple of months.
It is of course more than allowed to express your wishes, wanting to introduce new features trying to convince others, work on and discuss proposals etc.
I agree that over time Pascal evolved, and indeed not all for the better or what N.W. envisioned. Do keep in mind though that some of the introduced features are part of maintaining compatibility with Delphi.It is not complexity - it is simplicity. I'd venture that 90% or more of my loop control variables are named i,j,k,m,n,p,q (in about that order) and that 90% of them, further, are used for 15 lines of code, or less (maybe more if nested deep enough). They are ephemeral by their nature.Of course they are ephemeral by their nature. But really, in all those discussion i have seen and what i miss in your arguments as well, what on earth is the benefit of having scoped variables (let alone having them as untyped ones).QuoteWhat I suggest is very natural however. In context, any programmer can see that a for loop needs an index. Needing to declare a type for it is quite redundant. Using the correct type for it is something the compiler can divine easily enough from the range or type of the begin/end values of the loop.That we as humans/programmer see this as natural, i will not disagree with.
However, having untyped variables is in my opinion very unnatural for the Pascal language, and adds complexity to the parser/compiler, while the benefits are next to none.
Maybe it is a personal taste of reading sources, but when i dive into c code i am always amazed how some people are able to actually read and understand the code they've written when scoped variables are used and abused all over the place.
Right now things are pretty much clear, as you declare a variable and its type. And even though you can use and abuse that variable to your likings, you will never have to ask yourself, was that variable a byte, an integer, a char, or no the last iteration it went through made it a real (with all the consequences that comes along with that, especially with a typed language). I truly do not understand how they managed to justify this to allow in ADA.
...I think it shall be SynEditor-Autocomplete's job. Or be CodeTool's job.
(* ---------------------------------------------------------------------------------------- *)
Procedure foobar;
var
p, q: word;
begin
for i := 1 to 22 do
begin // variable i (word) exists only between here <<<
p := i * 2;
foo (p);
bar (i);
end; // and here<<<
//....
for i := -3000000 to 0 do bigfoo (i); // variable i is a longint this time.
end;
(* ---------------------------------------------------------------------------------------- *)
1) i would not need to be declared.
2) i would be a "word" the first time and a longint the 2nd time.
3) i would only exist within the for statement (including within its begin/end block)
..
Note that such a change has no impact on any existing code but would make future coding less work (not a lot less, but ....)
I like the idea.Well, there is no such things as bad idea. I respect to the any new idea.
The x2nie's suggestion does not resolve the issue!
Some variables do not deserve to be in the VAR list! They just increase the line of code and make the code less readable.
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++.
Note that such a change has no impact on any existing code but would make future coding less workSo, if you want to code faster less work, let the SynEdit do that (by using autocomplete / codetool?)
Finally, Pascal now allows the abomination of C operations like a+ = c albeit permitted by compiler directive (relief - may it never see my machine).I didn't know when fpc allow a+=c,
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'd like to suggest an addition to fpc's "Pascal" definition:
that for loop indexes could be like those in Ada - that is, do not require a
variable declaration. They would always be word/integer (longword/longint/
Qword/int64) as needed and would only "exist" within the for loop block.
Not sure why you believe massive fonts make your reply better.
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.
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 )).
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.
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).
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).
4)Hides a global var. Of course same can happen with any local var in the var section.
for NameOfAGlobalVar :=
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.
signed or unsigned? if it is int64 then this can affect comparison, depending on the other values sign.
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
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.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.
Well aware of all the locations.4)Hides a global var. Of course same can happen with any local var in the var section.
for NameOfAGlobalVar :=
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
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.
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.
unit secret;
type TFoo = class
...
end;
unit public;
uses secret;
type TFoo = secret.TFoo;
Let me make my example clearer.
procedure Bar(x: integer); overload; procedure Bar(x: int64); overload; // can not be used as replacement for the above ... for a := 0 to foo() do bar(a);
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)
Of course you can use unsigned. length/count - 1 is not the only upper bound.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, but if you want a different behaviour from codetools then suggest a change/option for that. dont change the pascal languageCode: [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.
Why? it could be a AdjustMax(arg) that keeps different value for each type of param. Then GetMax(out argOfSameType) to get the value.
procedure Bar(x: integer); overload; procedure Bar(x: int64); overload; // can not be used as replacement for the above ... for a := 0 to foo() do bar(a);
Such a bar should not be in the program anyways.
There can be 100 nested and/or in-sequence loops (well 100 may be an urgent case for refactor, but anyway).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
@DelphiFreakBelieve it or not, somebody already asked to replace begin end with {}.
Sooner or later someone will ask here, if we could make Pascal become "cAseSenSensiTIVE". :D
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 .
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.
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++.
As I said, I like the idea but I think it needs a deep understanding of its consequences.
Anyway, my suggestion is based on what AlanTheBeast described by himself in first post:QuoteNote that such a change has no impact on any existing code but would make future coding less workSo, if you want to code faster less work, let the SynEdit do that (by using autocomplete / codetool?)
Quote from: AlanTheBestFinally, Pascal now allows the abomination of C operations like a+ = c albeit permitted by compiler directive (relief - may it never see my machine).I didn't know when fpc allow a+=c,
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.
but if fpc did, the variables still must be declared in exact type, aren't they?
@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.
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.
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.
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.
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.
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 typesconfusing, since "a" in the same procedure is at some time int, and then bool.
begin for a := 0 to 9 do write(a); for a := false to true do write(a); end
4)Hides a global var. Of course same can happen with any local var in the var section.
for NameOfAGlobalVar :=
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.
Sooner or later someone will ask here, if we could make Pascal become "cAseSenSensiTIVE". :DPlease ask it and I'll simply say that would invalidate billions of lines of code. Thanks, cheers and goodbye.
But still better if I never got the error in first.2) "reserving" the identifier.Short answer: no big deal - the error will be at compile time.
"an Ada programmer is used", but what about pascal programmers?confusing, since "a" in the same procedure is at some time int, and then bool.
for a := 0 to 9 do write(a); for a := false to true do write(a);
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.
"should" But there is no warranty. So the problem will exist.4)Hides a global var.
for NameOfAGlobalVar :=
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.
Really? Laughter? Does that means you agree, and you are a good loser, taking it with laughter? ;)5) There is no optional.
Bwahahahahaahahahahahahah!!!!! :D
"an Ada programmer is used", but what about pascal programmers?
fpc is pascal, not Ada.
4)Hides a global var.
for NameOfAGlobalVar :=
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.
To be fair: Every feature brings good and bad. The only question is, if the good outweighs the bad. Saving one line in the declaration to me does not any good, so it does not outweigh the problems.
If you are worried about reading the one line in declaration, use code folding.
You could provide a patch to hide (entirely fold, no visible line left) "{$region}". And have it fold/hide on load. Then put anything you dislike seeing into such region.
5) There is no optional.
well agree to disagree.At this point I don't even know what you're on about. You seem to be throwing objections for that sake alone.
You (appear) to believe, that optional exists for such a feature.
I disagree. Based on my experience, optional does not exist (yes I am serious, no laughter this time please).
If (for argument sake) optional does not exist, then the above will cause harm (to some people).
This is not about how you would use it, you would not be the only one using it.
Besides what are the benefits?
- less typing (IIRC that was dismissed / should be taken care of, by codetool)
- less code to read (apparently not, since hiding/folding is dismissed as solution
That leaves automatically follow the type of the bounds if they change.
Using a smaller (word instead of int) type for optimization? I am not sure that really will optimize a lot (maybe on embedded), well and 2 bytes on the stack, if it is not in a register.
Besides, a variable that is declared as int, can be optimized the same way, if the compiler can detect that it never holds values that do not fit into word (and is not accessed via pointer or similar)
In any case the rules for the optimization are the same in both cases.
So what are the benefits then?
Maybe that the loop originally written for integer, can still compile if the bounds change to some enum? How likely is that? Both bounds would need to change in the same way. And if they do, any operation (compare, add, use as index,...) on the loop var, done in the loop must be supported on the new type. IMHO rather unlikely.
What did I miss, what is the benefit?
--------------
the "looser" comment was clearly marked as a joke. I never indented to make any statement with this.
At this point I don't even know what you're on about. You seem to be throwing objections for that sake alone.Not at all, or not intentional.
This is not about implementation. I am not maintaining the compiler, so that does not matter do me. And I wouldn't ever notice, if fpc would change a few millisec in speed (faster/slower), or fpc.exe grew a bit in size. None of that is my problem.This is not about how you would use it, you would not be the only one using it.at how it would be implemented would really find all that much issue.
Ok.This is personal preference. So it cant be argued.- less typing (IIRC that was dismissed / should be taken care of, by codetool)a- you might dismiss it, I don't
And as I said, to me personally, this decreases readability of the overall code. (And I am probably not alone on this) So this argument goes both ways.- less code to read (apparently not, since hiding/folding is dismissed as solution
Not so much that it is "less code to read" as it is "less clutter in the VAR list"
I dont understand. You still havent explained what the benefit is (well: less typing, is now on).That leaves automatically follow the type of the bounds if they change.So, no real issue given sober constraints. If the range is variable, then the variable define the range. ...
Using a smaller (word instead of int) type for optimization? ...
In any case the rules for the optimization are the same in both cases.
You didn't miss making the simple into complex, that is for sure.Sorry, I did not MAKE it complex. I merely pointed out how complex this is (and always was).
I dont understand. You still havent explained what the benefit is (well: less typing, is now on).
{$region 'loop vars' /hide} var i: integer; {$endregion}
There are a lot of small benefits (like those you listed). They add upThats "less typing" / "less reading" (clutter) only. (and from below: less clean up).
You still see that, when you commit the files.you can put it all on one line. then that line is also easy to ignore during commits.
And now you have 4 lines for what used to be one. This is way worse.
Also CodeTools do not remove the declaration, when you remove the loop. Then you have to search through the entire file to remove old loop vars to fix pointless hints1) A clean up of this kind could be added (delete selection and clean variables)
Is this a valid code?
procedure Test; procedure ShowA; begin writeln(a); end; begin for a:=0 to 10 do ShowA; end; �
And of course this should not be valid either:NO, I DON'T THINK SO.
procedure Test; begin for a:=0 to 10 do begin procedure ShowA; begin writeln(a); end; end; ShowA; end;
but this one again would:
procedure Test; var p: TProcedure; begin for a:=0 to 10 do begin p := ( procedure ShowA; begin writeln(a); end) end; p(); end;
and print 10 and nothing else
while this should print 0 to 10 :
procedure Test; var p: array[0..10] of TProcedure; begin for a:=0 to 10 do begin p[a] := ( procedure ShowA; begin writeln(a); end) end; for q in p do q(); end;
Is this not awesome?
procedure "ShowA" is in the same scope as the "a" was declared and i can't access "a"?
procedure Test; var a:byte; //<-- this was suppress
The proposal of this post is suppress the var declaration from for control variables, to simplify or make the code more "readable"
Thanks benibella. you have a good point, but i really can't see a real advantage to this proposal, except make lazys programmers happy.
i remember my teacher saying how angry any new pascal student when compiler show messages like:
";" found, expected ")"
... and saying "why not just compile it and closing by himself?"
I believe compiler suppress is a bad idea in any cases;
By the way:Yups, that's a very annoying one. Especially when converting code from c.
See here:
http://wiki.freepascal.org/Example:_Why_the_loop_variable_should_be_of_signed_type
However, this should be valid code:
procedure Test; begin for a:=0 to 10 do begin procedure ShowA; begin writeln(a); end; ShowA; end; end;
And I am not kidding
You can't declare a procedure within the executing part of a procedure.https://en.wikipedia.org/wiki/Anonymous_procedure (https://en.wikipedia.org/wiki/Anonymous_procedure)
However, this should be valid code:
procedure Test; begin for a:=0 to 10 do begin procedure ShowA; begin writeln(a); end; ShowA; end; end;
And I am not kidding
You can't declare a procedure within the executing part of a procedure.
However, this should be valid code:
procedure Test; begin for a:=0 to 10 do begin procedure ShowA; begin writeln(a); end; ShowA; end; end;
And I am not kidding
You can't declare a procedure within the executing part of a procedure.
But I want to!
I just found a great example with a for in loop. There you must use this automatically typed variable. You cannot loop without it:If there's such a library, that's a badly written one. Seriously, ask the author to write Pascal correctly. Structured types must be defined and exported in interface section. Laziness has no support in Pascal.
var a: array of record x, y: integer; end; begin SetLength(a, 10); for r in a do begin writeln(r.x, ' ', r.y); end; end
You cannot declare r as r: record x, y: integer; end. It would be another record type. If a is from a library, it is given and you cannot change its type.
It is impossible to use for-in without autodeclared types.
If there's such a library, that's a badly written one. Seriously, ask the author to write Pascal correctly. Structured types must be defined and exported in interface section. Laziness has no support in Pascal.+1
I actually agree with Benibela that this is a weak point, but it can't really be helped, except by declaring a separate type.
Pascal is a strong typed language, and too much weakening of the principle will make the whole system come crashing down. And there has been quite some weakening already (like variants, though for a more lofty goal than saving on typing)
If there's such a library, that's a badly written one. Seriously, ask the author to write Pascal correctly. Structured types must be defined and exported in interface section. Laziness has no support in Pascal.
Pascal is a strong typed language
then do it correctly no half a$$ solutions
If there's such a library, that's a badly written one. Seriously, ask the author to write Pascal correctly. Structured types must be defined and exported in interface section. Laziness has no support in Pascal.
I wrote that library!
I think it is a great way to handle internal types that have to be there, but the library user should be discouraged to create new instances of them. Exporting them would be the worst.
I wrote that library!I stand with my words that it's a badly written library, so fix it.
I wrote that library!
I think it is a great way to handle internal types that have to be there, but the library user should be discouraged to create new instances of them. Exporting them would be the worst.
And ADA is supposed to be an even strongerly typed language!
You can't declare a procedure within the executing part of a procedure.https://en.wikipedia.org/wiki/Anonymous_procedure (https://en.wikipedia.org/wiki/Anonymous_procedure)
What would be the advantage over this valid code?
procedure Test; var a: Integer; procedure ShowA; begin writeln(a); end; begin for a:=0 to 10 do begin ShowA; end; end;
@ AlanTheBestIs this a valid code?
procedure Test; procedure ShowA; begin writeln(a); end; begin for a:=0 to 10 do ShowA; end;
because my scope concept says "Are you kiding me?"
And ADA is supposed to be an even strongerly typed language!
By the way:Yups, that's a very annoying one. Especially when converting code from c.
See here:
http://wiki.freepascal.org/Example:_Why_the_loop_variable_should_be_of_signed_type
Unfortunately it is not always possible to use a signed type in which case you end up using while loops (or a lot of casting) :-(
Pascal is a strong typed language, and too much weakening of the principle will make the whole system come crashing down. And there has been quite some weakening already (like variants, though for a more lofty goal than saving on typing)
freepascal is a bit behind from other pascal compilers but as far as I know there is already some kind of implementation in SVN I just don't remember if it is a fork or it has been merged to the developers version already. So yeah it will be possible in the future.You can't declare a procedure within the executing part of a procedure.https://en.wikipedia.org/wiki/Anonymous_procedure (https://en.wikipedia.org/wiki/Anonymous_procedure)
... in Pascal? I tried compiling one a few minutes ago and it certainly did not work.
For loop variable values are undefined after the loop so loosing the declaration will not be that bad. I just don't like auto declared variables outside the for loop, I had a huge number of problems with this feature in VB 6 until I disabled it. So as long as this feature is 1) application wide not unit specific and 2) a choice I can turn off for all packages units that are used in that application I'm ok with it I guess.This may seem heresy to Pascal programmers (and I am one) but I also see the simple clarity of it. I've written some small Ada projects and this becomes the absolute least of ones worries.
And ADA is supposed to be an even strongerly typed language!
freepascal is a bit behind from other pascal compilers but as far as I know there is already some kind of implementation in SVN I just don't remember if it is a fork or it has been merged to the developers version already. So yeah it will be possible in the future.You can't declare a procedure within the executing part of a procedure.https://en.wikipedia.org/wiki/Anonymous_procedure (https://en.wikipedia.org/wiki/Anonymous_procedure)
... in Pascal? I tried compiling one a few minutes ago and it certainly did not work.
For loop variable values are undefined after the loop so loosing the declaration will not be that bad. I just don't like auto declared variables outside the for loop, I had a huge number of problems with this feature in VB 6 until I disabled it. So as long as this feature is 1) application wide not unit specific and 2) a choice I can turn off for all packages units that are used in that application I'm ok with it I guess.This may seem heresy to Pascal programmers (and I am one) but I also see the simple clarity of it. I've written some small Ada projects and this becomes the absolute least of ones worries.
And ADA is supposed to be an even strongerly typed language!
The example cited is pretty awful, because another thing I strenuously avoid is using the last value of an index after a for loop. That's always been considered dangerous for portability as you don't really know how different compilers, versions of compilers or even modes within compilers will leave the variable after the loop is finished.
AList.Clear;
for i:=0 to AList.Count-1 do
WriteLn(i:3, ': '{, AList[ i]}); // exception if uncomment
WriteLn('-------------');
AsShortInt := AList.Count-1;
AsByte := AList.Count-1;
WriteLn('ShortInt = ', AsShortInt);
WriteLn('Byte = ', AsByte);
why not unsigned?
why not byte from 0 to 10?
Any ordinal types with range can be a for loop long as you respect this range.
"loop variable usually should be of signed type"
instead "loop variable always must be of signed type"
And this has bothered me all the time. How does one determine the importance of a variable?Readability of the vars section: focus on things that are important/relevant
Now you say you wrote it that way, to prevent people from using the type, and then you say that the language should be changed so that people can use the type.
Do you or do you not want that type to be used?
Well, if ADA commonly infers the type of loopvariables, we can lay that illusion to rest.
And that is one of the big issues with this. The compiler can only do best guess, and it sometimes will go wrong.
"Not a problem", I was told. In those cases I can still declare the loop var:qword is needed because count could be a very large value ( >high(int64) ). And yes, this can happen, e.g. with sparse lists, or if values are calculated rather than stored.
var i: qword; ... for i := OldCount to Count - 1 do // at this point, it is guaranteed that count will be >=1 ...
Loop variables are variables too, they are important too, just as much as any other. (If they were not, that would imply, that the entire loop was not important, and leave the question why I did write the loop at all)
for i := 0 to stringlist.count - 1 do
writeln(stringlist[i]);
map(stringlist, writeln)
stringlist ! writeln(.)
Anyways, the compiler should detect that both sides are QWord and promote them to a signed type. Now, the signed version of a QWord is not int64, it is int65 !There is not an int65. Of course it is possible to create one. But the computation overhead, and that in a potentially big loop. talk about de-optimizing the code.
"variables are just an abbreviation for the actual data"
Loop variables are variables too, they are important too, just as much as any other. (If they were not, that would imply, that the entire loop was not important, and leave the question why I did write the loop at all)
They are not important, if they are only used as index inside the loop. Then the variables are just an abbreviation for the actual data.
In functional programming languages you use map, and do not even have loop variables for it.
E.g.:Code: [Select]for i := 0 to stringlist.count - 1 do
writeln(stringlist[i]);
would beCode: [Select]map(stringlist, writeln)
In functional programming languagesmap exists in OO style too.
And this has bothered me all the time. How does one determine the importance of a variable?Readability of the vars section: focus on things that are important/relevant
My code doesn't have unimportant or less important variables.
Loop variables are variables too, they are important too, just as much as any other. (If they were not, that would imply, that the entire loop was not important, and leave the question why I did write the loop at all)
If anything (not just loops) is not or less relevant to the current procedure, then it should be placed into its own procedure (where it then will be relevant). And I should call the procedure, rather than inlining the code.
So really the only reason not to have a variable in the var block, is because the code using it should not be in the code block (of this procedure) either. But hey, that is already supported.
When I have to program in JAVA, I need to see and to think diferent in order to make things work.
Do I miss the simple and straight forward Pascal's ways? Hell yes!!! But my pascalish way of doing things won't help. Even if they change the language to make me feel more comfortable.
My own code is deluged with variables i,j,k,m,n,p,qSo is my code, but they all are important. After all they (usually / see below) get accessed inside the loop, that must mean they are needed.
There is one case. But for that, omitting declaration is not the solution either.
If the loop variable is not used at all.
Example: servers usually store the hash of a password only. To make the hashing more time consuming, and harden against brute force (if the hashes get stolen), they store the hash of the hash of the hash of the hash....
So you execute the code in the loop 100 times. But never access (not even read) the loop counter.
In that case the solution would be a loop that does not take a variable.
loop 100 times do x = crypt(x);
Loop control variable types are often, even very often in the case of math, not important wrt to understanding the code. My own code is deluged with variables i,j,k,m,n,p,q that I know are not likely to be anything else and simply reading the code confirms this. (though P, Q (coded in upper case) usually mean a pointer - but that's my quirk).From what you are saying (and suggesting), it looks like you have issues in your own code. As a general rule of the thumb, if you have method that is larger than your code view screen, you should refactor it into multiple smaller methods. Same applies to local variables - if your declaration becomes clogged with them, it's time to refactor the method into few multiple ones. Also, you seem to use poor and inconsistent naming scheme mixing upper and lower 1-letter variables - even if you work alone on your code, for sake of maintenance you should use more context-sensitive names. For instance, although "I" is typically used as general-purpose counter, since you have many such variables, you might want it to be more descriptive, i.e. ElementCount or ItemIndex. In some cases, you might want to learn how enumerators work, so you can implement them for your own objects/types - this will further help code maintenance.
, if you have method that is larger than your code view screen, you should
var n: IXQValue;
begin
for n in something do
for n in n.getsomething do
...
end;
Loop control variable types are often, even very often in the case of math, not important wrt to understanding the code. My own code is deluged with variables i,j,k,m,n,p,q that I know are not likely to be anything else and simply reading the code confirms this. (though P, Q (coded in upper case) usually mean a pointer - but that's my quirk).From what you are saying (and suggesting), it looks like you have issues in your own code. As a general rule of the thumb, if you have method that is larger than your code view screen, you should refactor it into multiple smaller methods. Same applies to local variables - if your declaration becomes clogged with them, it's time to refactor the method into few multiple ones. Also, you seem to use poor and inconsistent naming scheme mixing upper and lower 1-letter variables - even if you work alone on your code, for sake of maintenance you should use more context-sensitive names. For instance, although "I" is typically used as general-purpose counter, since you have many such variables, you might want it to be more descriptive, i.e. ElementCount or ItemIndex. In some cases, you might want to learn how enumerators work, so you can implement them for your own objects/types - this will further help code maintenance.
The "hack" that was proposed here to avoid declaring variables used in FOR loop counters is actually counter-intuitive both for the developer and the compiler. Just because a language X has certain "syntax trick" and even if such language in some way "looks similar" to Pascal syntax, is under no circumstances a good/sufficient justification by itself to introduce this "syntax trick" to another language.
Martin_fr is absolutely right that whatever optional feature (though I myself don't consider what's discussed here a "feature", but more like a dirty code trick) is implemented, at one point or another some people will start using it, which eventually will affect much larger developer audiences in terms of development, extensibility and maintenance (again, as Martin_fr accurately described), contributing to Pascal language becoming less readable overall.
Well I'm done, to everyone's relief I expect.
Now it does not even give a hint.Why a hint?
And now my program crashed again, because there are loop-scoped variables.Page 57 (http://www.pascal-central.com/docs/iso7185.pdf):
I had a function like
...
copy/pasted dosomething. The value of i seems to have changed between fpc versions.
Why would the index be valid after that? It is not an index anymore.
Note that the compiler"could"should see that a variable is read that is not defined at that point and emit a warning.
Note that the compilerftfy"could"should see that a variable is read that is not defined at that point and emit a warning.
When there are ada-like patches they are not merged anyways (like the ifthen intrinsic debacle)...
If you like ADA, use ADA. 8)
[My experience with GoLang however tells me that GoLang code is much easier to write, than it is to read. Whenever I am looking at someone's golang code there are virtually no declarations of local variables anywhere (well there are some in rare occasions) and this makes the code much harder to read because you have no clue what type a variable is, for example when a function returns a value.. You have to go to the documentation to see what the function returns as a type, because it's not declared in the program.Add "no idea what interfaces this struct implement" to the list.
But for local loop counters, everyone knows what the loop counter "i" is supposed to be for so I can see your point about not declaring itWell, if the compiler knows about i and about the scope you can even skip it's declaration completely by using for in do... Which implies i... 8-)