Why do loop control variables need to be local in delphi 7 ?
I don't think this was the case in previous delphi versions ?
Ttest = class
private
public
Something : integer;
procedure Test;
end
procedure Tsomething.test;
begin
for Something:=1 to 10 do ; // not allowed something must be local
variable ?
end;
Bye,
Skybuck.
To help ensure that the control variable doesn't change over the course
of the loop. The control variable is typically cached in a register, but
the compiler doesn't cache the values of fields or global variables. The
loop might call other procedures, and those procedures might change the
value of the field that's acting as a control variable. Neither the
compiler nor the loop can detect that event, but the loop relies on the
control variable being an invariant within the body of the loop.
That's also why you aren't allowed to pass the control variable as a var
parameter. There's nothing stopping you from passing a pointer to the
variable, though, so it's not completely fool-proof.
> I don't think this was the case in previous delphi versions ?
It's been the case in every version of Delphi. There is an exception for
global variables for backward compatibility; you only get a warning
instead of an error in that case.
You're welcome to rewrite the for loop as a while or repeat loop
instead. You can use whatever variable you want for those.
--
Rob
> There is an exception for
>global variables for backward compatibility; you only get a warning
>instead of an error in that case.
I get an error for that in D6.
---
Replace you know what by j to email
Euhm, excuse.. but eh... isn't pascal/delphi supposed to be a high level
language ?! ;D
Anyway, it still doesn't make much sense... since if a procedure is called
within the loop... shouldn't all registers
be pushed onto the stack anyway ? :D
If I see a debug asm statement like this:
call TForm.SomeProcedure
what does call exactly do ?
I don't think call pushes anything ?
So that might make call fast ?
I know delphi pushes stuff onto the stack when it needs to like
push var1
push var2
Call TForm.SomeProcedure.
I think the compiler could detect it :P
Just a matter of parsing :) etc.
>
> That's also why you aren't allowed to pass the control variable as a var
> parameter. There's nothing stopping you from passing a pointer to the
> variable, though, so it's not completely fool-proof.
>
> > I don't think this was the case in previous delphi versions ?
>
> It's been the case in every version of Delphi. There is an exception for
> global variables for backward compatibility; you only get a warning
> instead of an error in that case.
>
> You're welcome to rewrite the for loop as a while or repeat loop
> instead. You can use whatever variable you want for those.
Well it all doesn't make much sense to me.
Anyway the only reason why I would like a control variable to be 'unit
global' or 'class global' is for speed reasons.
The thought was: using 'global' variables is faster than using 'local'
variables which might need to be pushed onto the stack.
By the way: Delphi doesn't really have global variables does it ?
Delphi only has 'unit variable' and 'class variable'
I think fricking fucking C does have global variable... I never understand
how 'unit variables' work in C since it uses include which is just copy
paste...
I knew once... I think it has to do something with C libraries etc... anyway
I don't want to know how it works in C since C is crap anyway :D
Just so nobody excuses me of bad programming style saying like: 'global'
vars are bad !
Delphi doesn't have global vars ?! :)
Except maybe some global system vars ;)
Bye,
Skybuck.
Sort of. But that's the problem. By saving all the registers, the value
of the control variable will be retained, but the way the code is
*written*, the variable should be able to change. Since the variable is
not allowed to change outside the influence of the loop, the compiler
does what it can to disallow such circumstances.
> If I see a debug asm statement like this:
>
> call TForm.SomeProcedure
>
> what does call exactly do ?
>
> I don't think call pushes anything ?
It pushes the current value of the EIP register, which is the
instruction pointer. By the time it gets pushed, that register actually
holds the address of the instruction *after* the CALL instruction.
That way, when the called procedure eventually reaches a RET
instruction, the CPU simply pops the return address off the stack in
into the EIP register, automatically jumping to the next instruction in
the caller. (It's really a little more complicated than that, but the
general idea is the same.)
> So that might make call fast ?
If you have two pieces of code that perform the same operations and are
equally easy to read and understand, prefer the one that makes fewer
subroutine calls.
The bare overhead of calling and returning is very small, but, like all
small things, adds up when used in large quantities -- within loops, for
instance. As always, use a profiler to determine whether the extra time
even matters.
> I know delphi pushes stuff onto the stack when it needs to like
>
> push var1
> push var2
> Call TForm.SomeProcedure.
Most often, that's because SomeProcedure uses a calling convention other
than register, and so the parameters need to be passed on the stack.
Otherwise, the compiler very rarely pushes a variable onto the stack.
Instead, the compiler allocates stack space for all the variables in the
function's prologue and then reads and writes directly into the stack
instead of pushing and popping. You will occasionally see variables
pushed onto the stack in Borland's hand-written assembler code, like in
the System unit. Knowing when to do that requires a better understanding
of the code's intent than what the compiler can figure out.
> I think the compiler could detect it :P
>
> Just a matter of parsing :) etc.
It would need to know what the called procedure does. That is not a
trivial task, and it's very time- and memory-intensive.
> Well it all doesn't make much sense to me.
>
> Anyway the only reason why I would like a control variable to be 'unit
> global' or 'class global' is for speed reasons.
Heh. That's like saying you want to run with scissors for safety reasons.
> The thought was: using 'global' variables is faster than using 'local'
> variables which might need to be pushed onto the stack.
Wrong. Fields and global variables are always read from memory. Local
variables may be stored in registers. Register access is faster than
memory access.
There used to be a Web site called Optimal Code at
http://www.optimalcode.com/. It contained lots of information on
improving code. It's gone now, but you can read it via the Wayback
Machine at http://www.archive.org/.
> By the way: Delphi doesn't really have global variables does it ?
>
> Delphi only has 'unit variable' and 'class variable'
Right. But since the term "global variable" cannot have any other
meaning in Delphi, the term is appropriated to take on the meaning it
currently has, which is a unit variable. In a way, "global" is just
taken to be "not local." "Class variables" are called fields, not variables.
> Just so nobody excuses me of bad programming style saying like: 'global'
> vars are bad !
>
> Delphi doesn't have global vars ?! :)
When someone in a Delphi forum tells you that global variables are bad,
and it's apparent from the context of the discussion that the subject is
Delphi code, then you should take it to mean that he's talking about
unit-scoped variables, which are the closest things Delphi has to true
global variables. If you don't like the terminology, file a report in
the documentation category of Quality Central.
> Except maybe some global system vars ;)
You mean the ones in the System and SysInit units? Those aren't global,
either. Those are still unit-scoped variables. Those units are
automatically included in everything else, though, so it's impossible to
not have access to them.
--
Rob
Euhm I still disagree with you.
Delphi has many warnings like 'variable may not be initialized'.
Delphi could give a warning: 'for loop control variable may not be
changed.Changes have no effect.'
Or even a compile error: 'for loop control variable may not be changed.'
And besides.... changing the for loop control variable should and will have
no effect.
I can remember a turbo pascal bug... the runtime error 200 bug.
CX was initialized with for loop control variable, I am not sure by the way
if it had to do with the bug,
but I investigated how for loops work on asm level for pascal.
It comes down to
for i:=0 to 1000 do
Delphi/Pascal then creates some sort of variable like Count := 1001;
And then just some compare is done like:
Count := 1001;
Jmp Condition
Loop:
..
Condition:
Dec Count
Cmp Count
jnz Loop;
The Count variable could or should be a compiler generated variable which is
completely inaccessable by the user.
That way the count variable can never be changed by any pascal code.
That solves it completely.
Even if other pascal/delphi code which is called by procedures inside the
loop is called. It won't have any effect.
So the only thing left to do is give an error or warning.
Because the way things are now, I don't like.
It means loss of functionality ! I don't like that in general :D
> > I know delphi pushes stuff onto the stack when it needs to like
> >
> > push var1
> > push var2
> > Call TForm.SomeProcedure.
>
> Most often, that's because SomeProcedure uses a calling convention other
> than register, and so the parameters need to be passed on the stack.
> Otherwise, the compiler very rarely pushes a variable onto the stack.
> Instead, the compiler allocates stack space for all the variables in the
> function's prologue and then reads and writes directly into the stack
> instead of pushing and popping. You will occasionally see variables
> pushed onto the stack in Borland's hand-written assembler code, like in
> the System unit. Knowing when to do that requires a better understanding
> of the code's intent than what the compiler can figure out.
Yes I have seen this as well.
const variables are best for prototypes so data is written/copied directly
into the stack space.
( but compiler still checks that it's not modified ) var also works like
const ;) but things can be modified ofcourse ;)
Otherwise copy-by-value takes place and stuff is pushed and probably later
copied again into stack space.
So that's two copies instead of one.
>
> > I think the compiler could detect it :P
> >
> > Just a matter of parsing :) etc.
>
> It would need to know what the called procedure does. That is not a
> trivial task, and it's very time- and memory-intensive.
No it doesn't... since modifieing the loop control variable shouldn't have
any effect anyway since under-water it should use a compiler
created variable. (temporarely variable, there should be no way to access
that from pascal/delphi )
>
> > Well it all doesn't make much sense to me.
> >
> > Anyway the only reason why I would like a control variable to be 'unit
> > global' or 'class global' is for speed reasons.
>
> Heh. That's like saying you want to run with scissors for safety reasons.
Not so fast buddy ! :)
How many loop control variables can be placed inside registers ?!?
CPU's only have limited ammount of registers !
I have many nested loops like:
for i:=0 to 10 do
begin
for j:=0 to 15 do
begin
for k:=0 to 20 do
begin
end;
end;
end;
Can delphi have 3 loop control variables inside registers ???
How about 4 or 5 ?
What's the maximum ammount ?!?
At some point it probably needs to do a memory access or even a push/pop or
something with many nested loops ;)
>
> > The thought was: using 'global' variables is faster than using 'local'
> > variables which might need to be pushed onto the stack.
>
> Wrong. Fields and global variables are always read from memory. Local
> variables may be stored in registers. Register access is faster than
> memory access.
As I wrote above... 'may'... that's uncertainty.
It might be pushed which is slower than accessing class fields ?
>
> There used to be a Web site called Optimal Code at
> http://www.optimalcode.com/. It contained lots of information on
> improving code. It's gone now, but you can read it via the Wayback
> Machine at http://www.archive.org/.
>
> > By the way: Delphi doesn't really have global variables does it ?
> >
> > Delphi only has 'unit variable' and 'class variable'
>
> Right. But since the term "global variable" cannot have any other
> meaning in Delphi, the term is appropriated to take on the meaning it
> currently has, which is a unit variable. In a way, "global" is just
> taken to be "not local." "Class variables" are called fields, not
variables.
Well we should try to call things for what they are ;)
Let's not call peers, apples shall we :)
> > Just so nobody excuses me of bad programming style saying like: 'global'
> > vars are bad !
> >
> > Delphi doesn't have global vars ?! :)
>
> When someone in a Delphi forum tells you that global variables are bad,
> and it's apparent from the context of the discussion that the subject is
> Delphi code, then you should take it to mean that he's talking about
> unit-scoped variables, which are the closest things Delphi has to true
> global variables. If you don't like the terminology, file a report in
> the documentation category of Quality Central.
Well, it's not global. But I would know what he is talking about, just 1%
uncertainty.
You never know ;) A new delphi compiler might have global vars :D
Not that I want or need it :D
>
> > Except maybe some global system vars ;)
>
> You mean the ones in the System and SysInit units? Those aren't global,
> either. Those are still unit-scoped variables. Those units are
> automatically included in everything else, though, so it's impossible to
> not have access to them.
Yeah probably those.
I mean when you write a bare-bones program like:
program Bla;
{$console something like that }
begin
end.
Some things might still be accessable... but no uses clausule anywhere...
Maybe writeln still works... or StdIn StdOut I am not sure...
I think there are some system vars that are accessable from a bare-bones
program like that.
Can't remember ;)
As always your post was an interesting read.
Byes,
Skybuck.
If the changes would have no effect, why allow that code in the first place?
> The Count variable could or should be a compiler generated variable which is
> completely inaccessable by the user.
>
> That way the count variable can never be changed by any pascal code.
>
> That solves it completely.
OK, let's take a step back, here. It's apparent to me that you have some
idea of what sort of code you'd like to be able to write. Why don't you
post a short example of that before we get too far into discussions of
assembler? I just want to be clear about what you're talking about --
exactly *what* has been solved completely -- since so far, I'm not sure
I see where the benefit of any of that code would be.
> No it doesn't... since modifieing the loop control variable shouldn't have
> any effect anyway since under-water it should use a compiler
> created variable. (temporarely variable, there should be no way to access
> that from pascal/delphi )
If the compiler allows me to pass a variable as a var parameter,
*that's* the variable I want to modify. If the compiler allowed me to
pass a loop-control variable as a var parameter, I would fully expect to
be able to change its value within the called procedure and see those
changes upon return from that procedure. That's the way var parameters
work. If the changes to that variable were ignored, I *know* you would
just be here complaining about that instead.
>>>Well it all doesn't make much sense to me.
>>>
>>>Anyway the only reason why I would like a control variable to be 'unit
>>>global' or 'class global' is for speed reasons.
>>
>>Heh. That's like saying you want to run with scissors for safety reasons.
>
>
> Not so fast buddy ! :)
>
> How many loop control variables can be placed inside registers ?!?
How many angels can dance on the head of a pin?
> Can delphi have 3 loop control variables inside registers ???
Probably. Depends on what else is happening in the loop.
> How about 4 or 5 ?
>
> What's the maximum ammount ?!?
Four is probably pushing it. Although it's possible to write assembler
code that performs even seven loops entirely with registers, there's a
limit to what the compiler would do by itself. It has certain registers
that it favors for certain purposes.
> At some point it probably needs to do a memory access or even a push/pop or
> something with many nested loops ;)
I guarantee there would be no pushing or popping. The compiler would
know how much stack space is needed in advance, and it would allocate
that space in the prologue. Thereafter, it would access that stack space
through offsets from EBP or ESP.
When possible, the compiler would use a register for the control
variable. Even if the variable had to be stored on the stack for the
duration of the loop, the variable would be loaded back into a register
at the end of the loop, incremented or decremented, and compared for a
jump, all without writing it back into RAM.
>>> The thought was: using 'global' variables is faster than using 'local'
>>> variables which might need to be pushed onto the stack.
>>
>> Wrong. Fields and global variables are always read from memory. Local
>> variables may be stored in registers. Register access is faster than
>> memory access.
>
> As I wrote above... 'may'... that's uncertainty.
You didn't write "may"; I did. And I was using that word only partly as
a synonym for "might." Mostly as a synonym for "are allowed to."
> It might be pushed which is slower than accessing class fields ?
Here are the steps for loading a field:
1. If Self is already in a register, go to step 3.
2. Load Self off the stack and into a register.
mov eax, [ebp-8]
3. Calculate an appropriate offset from Self, and load the value into a
register.
mov ecx, [eax+10]
If the probability of step 2 needing to be run is 1/2, then that's an
average of 1.5 memory accesses.
To load a value from a global variable takes just one step:
1. Load the value at the given address into a register.
mov ecx, [$00401bc0]
That's an average of 1.0 memory access.
Finally, here are the steps for loading a local variable into a register.
1. If the value isn't already in a register, then perform step 2.
2. Load the value at the appropriate offset from EBP into a register.
mov ecx, [ebp-10]
That's an average of 0.5 memory accesses.
If speed is your top priority, then you should copy a field into a local
variable, perform your calculations, and then copy the result back into
the field when you're finished. Most of the time, though, the speed
difference is negligible, so there's no use cluttering the code with
unnecessary copying.
--
Rob
I just want to use 'unit variable' or 'class fields' as loop control
variables. :)
I see no reason why that should not be possible.
Delphi's for loop works differently than say C's loop.
I would not complain about Delphi's for loop because it makes sense.
It's ment to do a fixed ammount of looping which is only determined once.
The pascal/delphi documentation clearly states that the for loop condition
is only checked once.
Then the for loop is just executed that ammount of times.
Skybuck :)
Making loops like this should still work:
for I:=0 to 99 do
begin
for I:=0 to 99 do
begin
for I:=0 to 99 do
begin
// in here I is the most inner loop
end;
// here I is outer loop
end;
// here I is outer outer loop
end;
I see absolutely no problem with this kind of looping, if a programmer
chooses to do so.
Even calling other procedures from inside loops like this should not affect
any I.
The loss of functionality is that the inner loop no longer knows where the
outer loop is at.
That's perfectly ok if the programmer/program doesn't have a need to know.
This code example clearly demonstrates what I mean with 'temp variable'.
Delphi should calculate for each loop the number of times it has to loop and
store it in a 'temp variable'. (The temp variable is un-accessable and is
just decremented every iteration and the loop stops when it reaches zero. )
Bye,
Skybuck.
That seems very much like using a "with" statement: An identifier has
totally different meanings depending on which part of the procedure it's
in. No thanks.
Allowing such syntax would make the code harder to read and would make
the compiler harder to implement. And what would be the gain? Nothing.
The code above could just as easily be accomplished by declaring three
separate variables. I know you like to have as few local variables as
possible, but you're taking that desire to extremes.
> Even calling other procedures from inside loops like this should not affect
> any I.
Not even if you pass i as a var parameter? No thanks.
> The loss of functionality is that the inner loop no longer knows where the
> outer loop is at.
So what's the point of nesting them?
> Delphi should calculate for each loop the number of times it has to loop and
> store it in a 'temp variable'.
It already does.
> (The temp variable is un-accessable and is
> just decremented every iteration and the loop stops when it reaches zero. )
If the variable is inaccessible, then how is the code within that loop
supposed to know how far through the loop it is? How would you process
each character of a string if you didn't know which character you're at?
--
Rob
And you said that was for "speed reasons." I think I've shown that
reason to be misguided.
> I see no reason why that should not be possible.
It opens the possibility for the control variable to be modified outside
the context of the loop.
> Delphi's for loop works differently than say C's loop.
>
> I would not complain about Delphi's for loop because it makes sense.
>
> It's ment to do a fixed ammount of looping which is only determined once.
>
> The pascal/delphi documentation clearly states that the for loop condition
> is only checked once.
The loop condition is not the same as the loop control variable. I fail
to see how it's relevant.
> Then the for loop is just executed that ammount of times.
(Except for when exit, break, goto, or raise are used.)
--
Rob
>Making loops like this should still work:
>for I:=0 to 99 do
> for I:=0 to 99 do
> for I:=0 to 99 do
Coding horror!
This is an invalid statement since the meaning of identifiers/variables/code
is always location dependant.
>
> Allowing such syntax would make the code harder to read and would make
Nope.
> the compiler harder to implement. And what would be the gain? Nothing.
Nope. Turbo Pascal already allowed this kind of syntax/code.
> The code above could just as easily be accomplished by declaring three
Requiring more memory and name space. In your words: no thx ;)
> separate variables. I know you like to have as few local variables as
> possible, but you're taking that desire to extremes.
No, I don't like being confined to local variables...
What if I don't have procedures but only a main program ?!
What if I don't want local variables for whatever reasons !
Think about turbo pascal's interrupt keyword... stack space is very limited.
>
> > Even calling other procedures from inside loops like this should not
affect
> > any I.
>
> Not even if you pass i as a var parameter? No thanks.
Yes, thanks... as long as the procedure is called from within the loop I
shouldn't be changed... after
that it can be changed as well.
>
> > The loss of functionality is that the inner loop no longer knows where
the
> > outer loop is at.
>
> So what's the point of nesting them?
Using the other loops to do other things.
>
> > Delphi should calculate for each loop the number of times it has to loop
and
> > store it in a 'temp variable'.
>
> It already does.
I know... that's not the problem... :)
>
> > (The temp variable is un-accessable and is
> > just decremented every iteration and the loop stops when it reaches
zero. )
>
> If the variable is inaccessible, then how is the code within that loop
> supposed to know how far through the loop it is?
> How would you process each character of a string if you didn't know which
character you're at?
Ok, It should be read-only.
In short delphi breaks turbo pascal syntax. :)
I respect and value the delphi compiler and the hints and warnings that it
gives me... sometimes a bit annoying...
But this is going to far :D The compiler is saying to me: "no global loop
control variable are bad"... that's just pushing it :D
That's going to far... I the programmer will be the judge of that... Most of
the time I'll use a local variable but SOMETIMES I want to use a global loop
variable and that functionality is now lost/deprived.
Hint/Warnings ok... but not an error ;)
Bye,
Skybuck.
Suppose I want to do this:
type
Tengine = class
private
GridCell : array of array of Tcell;
GridX, GridY : integer; // for loop control variable not allowed
?!?!?!
procedure InitializeCell;
procedure ProcessCell;
procedure DisplayCell;
public
procedure SingleLoop;
end;
procedure TEngine.InitializeCell;
begin
GridCell[GridX,GridY] := ...;
end;
procedure TEngine.ProcessCell;
begin
GridCell[GridX,GridY] := ..;
end;
procedure TEngine.DisplayCell;
begin
Display( GridCell[GridX,GridY] );
end;
procedure TEngine.SingleLoop;
begin
for GridY := 0 to 100 do
begin
for GridX := 0 to 100 do
begin
InitializeCell;
ProcessCell;
DisplayCell;
end;
end;
end;
Now I have a major problem.
I want to seperate the code for initializing, processing and displaying the
cells.
I want to use two loops to do this for all cells in the 2d array.
The solution would be to pass the 'loop control variables' (GridX,GridY) as
parameters to the other functions.
But since we are programming in OO (object oriented) fashion this should not
be required... the 'loop control variables' (as you call it) could easily be
implemented/embedded into the class itself.
This frees the programmer from having to pass the parameters everywhere
etc... I am tempted to talk about speeds as well... surely avoiding passing
parameters could lead to just a little bit of speed improvement... however
my knowledge of asm is limited and speed is not the main concern.
I am hoping that you will agree with me that in this case passing the GridX
and GridY 'loop control variables' would be pretty bad design since it's
totally unneccesary and a borden.
If one does pass the parameters we are back to square one 'procedural
languages' where everything had to be passed via parameters... just take a
look at win32 api ;)
If we choose to pass the parameters things will get very ugly when we wanted
to modify the code... we might need to pass extra parameters that would mean
all code where the procedures are called have to be changed !
In your words I would say: No thanks =D
I think this example is a very convincing example :)
Bye,
Skybuck.
>Nope. Turbo Pascal already allowed this kind of syntax/code.
It allowed it, but it didn't give the results you would want.
Hmmm indeed, interesting, I just tested it :)
This program would loop for ever :D
var
i : integer;
begin
writeln('start');
for i:=0 to 3 do
begin
writeln('i1 before: ', i ); // I will always be 3 after the other
inner loop is done.
for i:=0 to 2 do
begin
writeln('i2: ', i );
end;
writeln('i1 after: ', i ); // I would now be reset to 2
end;
end.
Oops another little turbo pascal bug :)
Bye,
Skybuck.
1. You have provided no alternative solution.
2. You fail to see the resemblence with properties.
3. Properties are an OO concept. GridX and GridY could have been properties,
yet as mentioned in 2 you fail to see that :D
So alas, your post adds nothing to this discussion :D
Bye,
Skybuck
Ok, I'll give you some slack.
With global variables you mean unit variables since there is nothing else in
non-OO.
In that respect units are like classess they encapsulate things.
Unit Unit1;
interface
var
BlaBla : integer;
implementation
end.
BlaBla will only be visible in other units that use Unit1.
It's even possible to write:
Unit1.BlaBla := 5; // from another unit
Is like:
type
Tclass1 = class
BlaBla : integer;
end;
end.
Class1.BlaBla := 5; // almost same thing ;)
Yet the unit example is harder to achieve in C I think... therefore it's not
done ;)
Bye,
Skybuck.
Unless the unit variable is in the implementation section...
So if it's in the implementation section I'll agree with you that it's not
limited to OO in itself.
That just makes matters worse :D
Since now we can't use global 'loop control variables' in non-OO code as
well :)
And therefore we have to pass everything via parameters !
Catch my drift ! ;)
In OO it's more usual to pass everything IMPLICITLY via properties or in my
case simply fields ;)
Thereby avoiding the parameter hell =D
By restricting for loops to local variables one potentially re-introduces
the parameter hell !
So to be fair:
1. You successfully recognized that it's not restricted to OO, but you
failed to see the importance to OO since OO is hit harder by this
restriction since implicity passing parameters is probably used more in OO
than in procedural languages... but now I am just guessing... lol... if you
look at quake source code you might start thinking the opposite :D
Bye,
Skybuck.
Not true, loop-control variables can be global as well:
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils;
var
I : integer;
procedure Test1;
begin
writeln('test 1 i:', I );
end;
procedure Test2;
begin
writeln('test 2 i:', I );
end;
begin
for i:=0 to 10 do
begin
Test1;
Test2;
end;
readln;
end.
HA-HA inconsistency !
>
> >2. You fail to see the resemblence with properties.
> >
> Because there is no similarity.
Now you're in denial.
> >3. Properties are an OO concept. GridX and GridY could have been
properties,
> >yet as mentioned in 2 you fail to see that :D
> >
> When you determine how to make the control statement a property then
> the control variables can be properties as well.
?
> >So alas, your post adds nothing to this discussion :D
> >
> I could not provide an answer or alternative solution for one very
> simple reason; you are trying to solve a problem which does not exist.
There is a problem :) a compiler/language problem :)
> An "enhancement" such as you desire would introduce many many more
> complexities than the few it would supposedly resolve.
Bullshit.
Skybuck.
No, it isn't. Within a procedure, an identifier always refers to the
same location on the stack. With your proposed syntax, a single
identifier could refer to at least three totally different values within
the same procedure, and at the same time.
>> Allowing such syntax would make the code harder to read and would
>> make
>
> Nope.
I found your code harder to read.
>> the compiler harder to implement. And what would be the gain?
>> Nothing.
>
> Nope. Turbo Pascal already allowed this kind of syntax/code.
Then I guess Borland wised up.
>> The code above could just as easily be accomplished by declaring
>> three
>
> Requiring more memory and name space. In your words: no thx ;)
More memory? Where? Certainly not within the running program. In the
compiler? I doubt it. It would still need to maintain information for
the three separate variables, even if they're all represented by the
same identifier name.
And another thing: "thx" is most definitely *not* one of my words.
>> separate variables. I know you like to have as few local variables
>> as possible, but you're taking that desire to extremes.
>
> No, I don't like being confined to local variables...
Is that really true, or is this just another of the things you've
decided to be contrary about for a week?
> What if I don't have procedures but only a main program ?!
As unlikely as that scenario is, it's an irrelevant concern. You're
allowed to use global variables in for loops in the program's main block
and within unit initialization and finalization sections.
> What if I don't want local variables for whatever reasons !
"Whatever reasons"? Come on.
> Think about turbo pascal's interrupt keyword...
What would you like me to think about it? I've never used it. I never
programmed in an environment that needed interrupts.
> stack space is very limited.
News flash: With the switch from Windows 3.1 to Windows 95, the stack
became comparitively huge. If you get a stack overflow nowadays, it's
probably because of a bug in your code -- either a misdeclared variable
that's bigger than you expected, or a recursive function without a
termination condition.
>>> Even calling other procedures from inside loops like this should
>>> not affect any I.
>>
>> Not even if you pass i as a var parameter? No thanks.
>
> Yes, thanks... as long as the procedure is called from within the
> loop I shouldn't be changed... after that it can be changed as well.
But that's the way it already works. The compiler prevents the variable
from being changed by disallowing the kind of code that would lead to it
getting changed in the first place.
>> If the variable is inaccessible, then how is the code within that
>> loop supposed to know how far through the loop it is? How would you
>> process each character of a string if you didn't know which
>> character you're at?
>
> Ok, It should be read-only.
It already is.
> In short delphi breaks turbo pascal syntax. :)
If that's really true, then it's the kind of complaint you should have
made ten years ago, not now.
Just how much Turbo Pascal code are you trying to use, anyway? And how
much of it doesn't compile because of the change in the rules for
loop-control variables? And how much of that code requires anything
beyond a trivial change to fix it?
> That's going to far... I the programmer will be the judge of that...
> Most of the time I'll use a local variable but SOMETIMES I want to
> use a global loop variable and that functionality is now
> lost/deprived.
You have yet to show an example where using a global variable would be
useful. Show a real example. Show me something that cannot be done with
local control variables and can be done easily with global control
variables.
--
Rob
Exactly. That makes those routines able to function independently of the
surrounding context. At any time -- not just within a single loop -- you
can initialize, process, or display any cell you want.
Another solution would be to not even tell those procedures the
coordinates of the cell they are to work on. Instead, pass the reference
to the cell itself:
procedure InitializeCell(const Cell: TCell);
With that kind of method signature, InitializeCell wouldn't even need to
be a member of TEngine. I could make all sorts of procedures that
operate of TCell objects, and none of them would need to know anything
about the internal storage method of TEngine.
Another reason for passing parameters directly to a procedure instead of
indirectly via fields is that the procedure's declaration helps serve as
documentation. Just from looking at the declaration, you can see how the
procedure knows which cell to operate on. With your way, you'd need to
read the body of the procedure, and then you'd need to find the
declarations of GridX and GridY in the class declaration, and then you'd
need to search the rest of the code to determine where those fields get
their values. If those values had been passed as parameters, you could
see right away where the values came from -- they were passed in with
the procedure call.
> But since we are programming in OO (object oriented) fashion this
> should not be required... the 'loop control variables' (as you call
> it) could easily be implemented/embedded into the class itself.
If they are indeed loop-control variables, then they are *not* instance
data and they have no business being defined by the class. They are an
implementation detail of the mechanism SingleLoop uses to iterate over
all the cells.
Even while the SingleLoop procedure is not running, those two fields are
still occupying space in memory. If they were local variables, they
would have been released from memory when SingleLoop returned to its caller.
> This frees the programmer from having to pass the parameters
> everywhere etc...
No, it limits the programmer to always initializing, processing, and
displaying all the fields solely via the SingleLoop interface.
> I am tempted to talk about speeds as well... surely avoiding passing
> parameters could lead to just a little bit of speed improvement...
> however my knowledge of asm is limited and speed is not the main
> concern.
Good. I already showed you that accessing field values is slower than
accessing local variables. (Method parameters are a kind of local variable.)
> I am hoping that you will agree with me that in this case passing the
> GridX and GridY 'loop control variables' would be pretty bad design
> since it's totally unneccesary and a borden.
No, I do not agree. It is not a bad design to pass a procedure the
information that it needs to perform its job.
> If one does pass the parameters we are back to square one 'procedural
> languages' where everything had to be passed via parameters...
The variables could be global instead. Or all the current engine's data
could be passed in a record pointer, including the two looping variables.
> just take a look at win32 api ;)
I'm not sure I see the connection.
> If we choose to pass the parameters things will get very ugly when we
> wanted to modify the code... we might need to pass extra parameters
> that would mean all code where the procedures are called have to be
> changed !
I don't see that as a bad thing, necessarily. When you forget to pass a
required parameter to a procedure, the compiler will tell you about it.
If you forget to set a required field before calling a procedure, the
compiler will never tell you. The more places you call the procedure,
the more places you'll have to remember to set all the other fields in
advance.
> In your words I would say: No thanks =D
At least you have the words right this time.
> I think this example is a very convincing example :)
But you're not the one who needs to be convinced.
--
Rob
Really? Are there statistics to back you up on that statement?
> Thereby avoiding the parameter hell =D
And what's that?
When you want to call a method, most modern code editors will present
you will a list of that method's parameters, so you know what that
method needs. The editor can also provide you with a list of the
object's properties, but it will not tell you which of those properties
need to be set before you call parameterless methods.
> By restricting for loops to local variables one potentially
> re-introduces the parameter hell !
Potentially? So you mean it hasn't actually happened yet? And the
local-variable restriction has been in place for how many years already
without any problems?
> So to be fair:
>
> 1. You successfully recognized that it's not restricted to OO, but
> you failed to see the importance to OO since OO is hit harder by this
> restriction since implicity passing parameters is probably used more
> in OO than in procedural languages...
It's hit harder, is it? Please elaborate. Object-oriented programming
has been around for quite a long time now, so surely there must be some
other people who have written recommending the use of fields or
properties as loop-control variables (in the languages that allow such
things, such as C++). A Web site, a newsgroup post, a trade journal --
anything.
--
Rob
I have the quake 2 source code.
Many, many, many procedures have no parameters at all.
void Something1(void)
{
// Yet it uses all kinds of variables in here.
}
void Something2(void)
{
// Same here
}
That's what I wanted you to see :)
Yes there are also some simple small procedure with parameters...
But the most important part has frequently only (void) or 1 parameter.
The rest is global
Bye,
Skybuck.
Example please, since I have no clue what you mean :)
>
> >> Allowing such syntax would make the code harder to read and would
> >> make
> >
> > Nope.
>
> I found your code harder to read.
Hardly... never seen 3 nested loops ? :)
>
> >> the compiler harder to implement. And what would be the gain?
> >> Nothing.
> >
> > Nope. Turbo Pascal already allowed this kind of syntax/code.
>
> Then I guess Borland wised up.
They fell a sleep ;)
>
> >> The code above could just as easily be accomplished by declaring
> >> three
> >
> > Requiring more memory and name space. In your words: no thx ;)
>
> More memory? Where? Certainly not within the running program. In the
3 local variables vs 1 variable.
You assume the are register variables... that could be compiler specific.
Think 'high level language' not 'low level language' :)
> compiler? I doubt it. It would still need to maintain information for
> the three separate variables, even if they're all represented by the
> same identifier name.
> >> separate variables. I know you like to have as few local variables
> >> as possible, but you're taking that desire to extremes.
> >
> > No, I don't like being confined to local variables...
>
> Is that really true, or is this just another of the things you've
> decided to be contrary about for a week?
I have encountered this restriction in the past as well.
I'd like to store for-loop control variable in the thread's calls
definetion.
I don't feel comfortable making it local variable in the execute procedure.
I rather keep the number of local variables in the thread execute method as
low as possible.
It seems a wise thing to do... since it runs millions of times... so keep
memory requirement low and fast.
>
> > What if I don't have procedures but only a main program ?!
>
> As unlikely as that scenario is, it's an irrelevant concern. You're
> allowed to use global variables in for loops in the program's main block
> and within unit initialization and finalization sections.
Ohhhhhhh so now it is allowed ! gjeeee.
>
> > What if I don't want local variables for whatever reasons !
>
> "Whatever reasons"? Come on.
Yeah, what if I have zero stack space !
Big problem.
>
> > Think about turbo pascal's interrupt keyword...
>
> What would you like me to think about it? I've never used it. I never
> programmed in an environment that needed interrupts.
Low stack space.
>
> > stack space is very limited.
>
> News flash: With the switch from Windows 3.1 to Windows 95, the stack
> became comparitively huge. If you get a stack overflow nowadays, it's
> probably because of a bug in your code -- either a misdeclared variable
> that's bigger than you expected, or a recursive function without a
> termination condition.
Sure now we have powerfull computers that doesn't mean let's fuckup the
language :D
>
> >>> Even calling other procedures from inside loops like this should
> >>> not affect any I.
> >>
> >> Not even if you pass i as a var parameter? No thanks.
> >
> > Yes, thanks... as long as the procedure is called from within the
> > loop I shouldn't be changed... after that it can be changed as well.
>
> But that's the way it already works. The compiler prevents the variable
> from being changed by disallowing the kind of code that would lead to it
> getting changed in the first place.
No, that's not the way it worked.
The way it worked was that the loop control variable could not be changed
during the looping.
So you can pass it as var, const, whatever you like... that would all be
bullshit... :D
>
> >> If the variable is inaccessible, then how is the code within that
> >> loop supposed to know how far through the loop it is? How would you
> >> process each character of a string if you didn't know which
> >> character you're at?
> >
> > Ok, It should be read-only.
>
> It already is.
Ok, so you can forget about passing it as a var parameter, since that is
what you wanted to do in the first place !
So what you wanted isn't possible at all !
You're just making it up as you go along aren't you :)
Ok, that was a bit of joke... but having wrote it I suddenly realize the
problem is now again worse !
procedure Something( var A : integer );
begin
end;
procedure Something2;
var
i : integer;
begin
for i:=0 to 10 do
begin
Something( A ); // not allowed ?
end;
end;
I haven't tested this code yet...
But you say this code would not compile ?!
Oh that's just fucking great !
Now all my procedures with stupid parameters have to be constants or call by
value as well...
Now we can forget about var parameter all together !
>
> > In short delphi breaks turbo pascal syntax. :)
>
> If that's really true, then it's the kind of complaint you should have
> made ten years ago, not now.
Bullshit.
> Just how much Turbo Pascal code are you trying to use, anyway? And how
> much of it doesn't compile because of the change in the rules for
> loop-control variables? And how much of that code requires anything
> beyond a trivial change to fix it?
It has nothing to do with TP... TP is just an example how things were back
then.
And how fucked up it is now :D
>
> > That's going to far... I the programmer will be the judge of that...
> > Most of the time I'll use a local variable but SOMETIMES I want to
> > use a global loop variable and that functionality is now
> > lost/deprived.
>
> You have yet to show an example where using a global variable would be
> useful. Show a real example. Show me something that cannot be done with
> local control variables and can be done easily with global control
> variables.
I have shown you many examples by now.
Skybuck.
It can do that already.
GridX := 5;
GridY := 6;
InitializeCell;
No problem.
The cool thing is... I can even call
ProcessCell;
and
DisplayCell;
Without having to pass any parameters... since they are all ready set !
(implicityly);
Ahhhhh now that's relaxing ! :D
Especially for story telling like quake2/game code... or mario for all I
care :)
WalkMarioDownThePath;
FindALittleSnakeToKill;
:)
For applications parameters might be more usefull.
>
> Another solution would be to not even tell those procedures the
> coordinates of the cell they are to work on. Instead, pass the reference
> to the cell itself:
Yak... what if i need to pass other parameters ?! for different behaviour
purposes...
bleh. Not to mention I then have to pass it alwaaaayysss those extra
parameters
what a drag.
I just need to set them once... or not at all and use default values...
That's the great thing about classes... initialize fields with default
values...
and then only change the necessary stuff via properties...
Suppose properties are completely illiminated from classess then we would
have to pass everything via parameters.
Properties are thus a bit like global variables... or class fields if you
like.
So... to piss you off... I could just as well say... "you dont need
parameters"
"You could just as well have a property"
CurrentCell : TCell
CurrentCell ::= WhatEverCell;
Same thing expect no stupid parameters :P
> procedure InitializeCell(const Cell: TCell);
>
> With that kind of method signature, InitializeCell wouldn't even need to
> be a member of TEngine. I could make all sorts of procedures that
> operate of TCell objects, and none of them would need to know anything
> about the internal storage method of TEngine.
If you would do that than Tcell is isolated...
The initialize cell, process cell, and display cell could need
properties/fields from the grid itself...
In fact cell does need stuff from grid !
So now you have isolated it wayyyyyy to much... <- that's really fucky. :)
The engine is not about cells... it's about a grid...
It's a grid engine... not a cell engine... but you didn't know that... now
you do... :)
I coulnd't care less about what you can do with cells :)
> Another reason for passing parameters directly to a procedure instead of
> indirectly via fields is that the procedure's declaration helps serve as
> documentation. Just from looking at the declaration, you can see how the
> procedure knows which cell to operate on. With your way, you'd need to
> read the body of the procedure, and then you'd need to find the
> declarations of GridX and GridY in the class declaration, and then you'd
> need to search the rest of the code to determine where those fields get
> their values. If those values had been passed as parameters, you could
> see right away where the values came from -- they were passed in with
> the procedure call.
Bullshit.
Blabla( GridX, GridY )
1. Now you still have to find where GridX, GridY came from.
2. You still need to read BlaBla's documentation to know what it does.
You still need to do the same things.
>
> > But since we are programming in OO (object oriented) fashion this
> > should not be required... the 'loop control variables' (as you call
> > it) could easily be implemented/embedded into the class itself.
>
> If they are indeed loop-control variables, then they are *not* instance
> data and they have no business being defined by the class. They are an
> implementation detail of the mechanism SingleLoop uses to iterate over
> all the cells.
What if I have multiple procedures which need to iterate...
Now I have to declare local loop control variables everywhere ! Such a drag
!
I could just gave them a very good descriptive name in the class type to
avoid any possibly conflicts, document it well and then happily re-use it in
any procedure where I'd like. If I ever have any loop problems that's easy
to find out with a trace.. no problem at all.
Now a new problem is introduced... if I want to share the loop's work with
the rest of the code I have fucked-up options:
1. Pass loop control variables via parameters <- yak.
2. Can't even pass local loop control variables via var parameters <- OUCH
3. Copy them to other variables <- yak, copy is slow, unneccesary, a drag,
and even more sources of confusion ! Now I would end up with local loop vars
and global loop vars ! GridXLocal, GridXGlobal <- no thanks !
4. Alternatives ? using a while statement, or repeat statement ? gjezus
fucking christ get real... <--- way to much work. Can I just use a fricking
for loop for what it's ment to do... looping code ! thank you !
"Looze the fucking shit: nonono may only loop inside procedures, and only
with local vars, and in main, init and finalization sections, everything
else is
badddddddddddddd" HAHAHAHA give me a break ! LOOPING IS LOOPING
hahahahahahahahaha
Question:
Can properties be used for looping ?
type
Tclass = class
private
public
GridX : integer property read mGridX write mGridX;
end;
for GridX := 0 to 10 do
begin
? maybe I can use properties ?
end;
>
> Even while the SingleLoop procedure is not running, those two fields are
> still occupying space in memory. If they were local variables, they
> would have been released from memory when SingleLoop returned to its
caller.
Fucking great... allocate, deallocate, allocate, deallocate <-
slooowwwwwwwww
And don't start that register shit on me again... !
That only works when there are few loop control variables !
I have a procedure with 20 loop control variables ! :)
Ok the code is shitty and old but still... it's reality :P
>
> > This frees the programmer from having to pass the parameters
> > everywhere etc...
>
> No, it limits the programmer to always initializing, processing, and
> displaying all the fields solely via the SingleLoop interface.
Oh get real... it's easy to add new code to do whatever you want.
>
> > I am tempted to talk about speeds as well... surely avoiding passing
> > parameters could lead to just a little bit of speed improvement...
> > however my knowledge of asm is limited and speed is not the main
> > concern.
>
> Good. I already showed you that accessing field values is slower than
> accessing local variables. (Method parameters are a kind of local
variable.)
Bullshit that only works for few local parameters.
You were unable to see how much loop variables can fit in registers...
Further you talked about stack space... etc... where is stack space located
?
In main memory or in cpu cache ?!
If it is in cpu cache you might have a point... if not then it's bullshit :D
Frankly I don't care how delphi compiler does it... since that might change
in the future:
My point is a valid one:
allocating, deallocating, allocating deallocating, allocating deallocating
local variables.
That concept is slow.
My concept is fast: only allocate once !
I rest my case ;)
>
> > I am hoping that you will agree with me that in this case passing the
> > GridX and GridY 'loop control variables' would be pretty bad design
> > since it's totally unneccesary and a borden.
>
> No, I do not agree. It is not a bad design to pass a procedure the
> information that it needs to perform its job.
Fine you use win32api...
I'll use .NET or Delphi VCL instead :)
>
> > If one does pass the parameters we are back to square one 'procedural
> > languages' where everything had to be passed via parameters...
>
> The variables could be global instead.
No they can't DUH <- loop variables.
> Or all the current engine's data could be passed in a record pointer,
including the two looping variables.
Or all the program data could be in the program DUH, booorrring.
>
> > just take a look at win32 api ;)
>
> I'm not sure I see the connection.
Look at it and you ll see it :P
win32api_any_method( v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11 )
Most not even used... =D
Need extra parameters to store it all which you ll never use...
it's just filling of the parameter layout... bleh.
Sick of it yet ? :)
>
> > If we choose to pass the parameters things will get very ugly when we
> > wanted to modify the code... we might need to pass extra parameters
> > that would mean all code where the procedures are called have to be
> > changed !
>
> I don't see that as a bad thing, necessarily.
Try changing 10 million lines of code :) just because some fucko went from
call by value to call by reference parameters in C ;)
test( a );
to
test( &a ); <- ouch a million tests no thx :)
You'll get sick of it :)
Actually I never got sick of it... since I recognized that C flaw immediatly
and trashed C into the garbage bin.
Thank god this aint C ;)
>When you forget to pass a
> required parameter to a procedure, the compiler will tell you about it.
> If you forget to set a required field before calling a procedure, the
> compiler will never tell you. The more places you call the procedure,
> the more places you'll have to remember to set all the other fields in
> advance.
Maybe, maybe not. Delphi could give warning, var not initialized.
This is the only valid point so far...
Search is your solution.
Copy pasting all necessary 'procedure control variables' and checking if all
are set somewhere along the path is also part of the solution.
No big deal there.
At least not for single programmer projects.
P.S.: Programming applications is different from Programming games.
My mentioned style of programming is more suitable for games <- more
flexible :P
For applications which are critical I would not recommend my mentioned style
:)
Bye,
Skybuck.
Because you have knowledge of how the compiler works.
My unit/class concept is superior to the local concept.
My concept is allocate/deallocate only once.
The local concept is allocate/deallocate/allocate/deallocate every time the
procedure is called.
Therefore the local concept is a slower concept since it has to do more work
every time !
Delphi's compiler could change in the future making your assumption about
speed/registers/stack etc invalid.
Maybe your assumptions are already invalid for procedures with many local
variables. !!!
Even if delphi's compiler implemention changes my concept will still hold !
:) If it doesn't that would be funny =D
>
> > I see no reason why that should not be possible.
>
> It opens the possibility for the control variable to be modified outside
> the context of the loop.
NO BECAUSE IT'S READ ONLY !
Ok, stupid programmers will try to do that... and then find out they don't
know the language
as well as they thought.. painfull but wise lesson.
That lesson can be less painfull/avoided if delphi compiler simply gives a
warning:
'loop control variable is read only'
Tada ! No more pain for anybody ! :D
>
> > Delphi's for loop works differently than say C's loop.
> >
> > I would not complain about Delphi's for loop because it makes sense.
> >
> > It's ment to do a fixed ammount of looping which is only determined
once.
> >
> > The pascal/delphi documentation clearly states that the for loop
condition
> > is only checked once.
>
> The loop condition is not the same as the loop control variable. I fail
> to see how it's relevant.
The loop condition initializes the loop control variable.
After that the loop control variable is simply increment or decremted... but
now we are getting to compiler implementation specific again !
YOU ARE COMPILER IMPLEMENTATION HORNY !
YOU ARE BETTER OFF PROGRAMMING IN ASM ! :D
SINCE YOU CARE MORE ABOUT SPECIFICS/DETAILS THAN GENERAL HIGH LEVEL CONCEPTS
:D
>
> > Then the for loop is just executed that ammount of times.
>
> (Except for when exit, break, goto, or raise are used.)
Ok.
Bye,
Skybuck.
Ok maybe this helps:
for I:=0 to 99 do
begin
KickJack;
for I:=0 to 99 do
begin
KickMum;
for I:=0 to 99 do
begin
KickYouLol;
end;
end;
end;
How is that different from this:
for A:=0 to 99 do
begin
KickJack;
for B:=0 to 99 do
begin
KickMum;
for C:=0 to 99 do
begin
KickYouLol;
end;
end;
end;
ABSOLUTELY NO DIFFERENCE WHAT SO EVER ! :D
Coding horror BAHAHAHAHAHAHA YOU ARE TOO FUNNY !
( Actually the last one is probably even more difficult since now you have
to think about
why is A,B,C used ? Since it only does simple looping !
Ok on the other side it's maybe hard to see in the first example that it's 3
dimensional
I x I x I is maybe harder to see than A x B x C,
I can just whimp that off by saying: the first one needs getting used too :P
:) )
Bye, Bye,
Skybuck.
Side-effects ???
Diserable effects !
It's like properties !
Properties change the behaviour of an object.
What I am trying to do is use GridX and GridY to tell the object where to
apply changes.
Since it's a grid... I dont want everything to change... only a certain
cell.
So I am trying to tell the object "where the change" takes place and not
"what or how".
Not true... the data is used to influence the objects behaviour...
Like vcl properties change the vcl objects behaviour.
I don't want to change the objects complete behaviour.
I just want to change part of it... a given cell identified by GridX and
GridY.
Sometimes I might want to change all cell's... so it would be handy if I
could do that
with a loop... yet delphi prevents me from doing so !
That's only stupid, dumb, frustrating, lame, idiotic, nothing else ! :)
I don't want to use parameters, I want to use fields or properties to do
that !
Just as properties are used to change an object behaviour !
Bye,
Skybuck.
Skybuck Flying wrote:
> Hello,
>
> Why do loop control variables need to be local in delphi 7 ?
>
> I don't think this was the case in previous delphi versions ?
>
> Ttest = class
> private
>
> public
> Something : integer;
> procedure Test;
> end
>
> procedure Tsomething.test;
> begin
> for Something:=1 to 10 do ; // not allowed something must be local
> variable ?
> end;
>
> Bye,
> Skybuck.
>
>
>ABSOLUTELY NO DIFFERENCE WHAT SO EVER ! :D
Yes, there is a difference. For one thing, it changes the value of I
inside the inner loops. Secondly, what if you want the value of an
outer loop counter inside an inner loop?
That's all beside the point since the loop control variables aren't used :)
It's about the readibility of the current code. :)
Skybuck
GridY := 0; // don't forget this otherwise you screwed
while GridY < 100 do
begin
GridX := 0; // don't forget this otherwise you screwed
while GridX < 100 do
begin
Inc(GridX); // don't forget this otherwise you screwed
end;
Inc(GridY); // don't forget this otherwise you screwed
end;
I rather write:
for GridY := 0 to 99 do
begin
for GridX:=0 to 99 do
begin
end;
end;
Ahhhhhh now that's much more relaxing, short and clean THANK YOU VERY MUCH
!!!!! :D
Skybuck.
"Jamie" <jamie_5_not_vali...@charter.net> wrote in message
news:10c6c1a...@corp.supernews.com...
> i never saw so much flack over loop control.
> if your trying to global loop variables then
> just use a "While control Loop"
> that will do any exotic loop that C can do.
P.S.: Fuck C :)
1. Download quake 2 source code.
2. Wipe the shit out of your eyes.
3. Take a longgggggggggg harddddd look at quake 2 source code.
4. Notice how many routines use global vars.
Case closed ! :D
Alternatively
1. Buy Delphi's VCL source code or Download any VCL Component.
2. Wipe the shit out of your eyes
3. Take a longgggg harrrddd look at the component's source code.
4. Notice how properties change the component behaviour without using
parameters in component's usage code.
5. Kiss my pinky :D
Bye, Bye,
Skybuck
>That's all beside the point since the loop control variables aren't used :)
They could be.
>It's about the readibility of the current code. :)
I don't see any advantages to your construction, and there are plenty
of disadvantages.
At the expense of longer running times and increased probability of
coding errors.
> The local concept is allocate/deallocate/allocate/deallocate every
> time the procedure is called.
>
> Therefore the local concept is a slower concept since it has to do
> more work every time !
No. Because of the wonders of the CPU's stack, it takes exactly the same
amount of time to allocate four bytes as it does to allocate 400 bytes.
Besides, if the same identifier is going to be used in multiple nested
loops simultaneously, then the values for the outside loops need to be
stored somwhere while the inner loops execute. The values can't all be
stored in the same place. If you call the looping procedure recursively,
there would need to be an arbitrarily large amount of space to hold all
the outer-loop values. That's a perfect place to use a stack.
> Delphi's compiler could change in the future making your assumption
> about speed/registers/stack etc invalid.
Oh, this argument again. If we're going to talk about things that don't
exist, I'd really prefer to argue about the mating rituals of invisible
pink unicorns rather than the code generation of hypothetical compilers
that have been designed specifically to break existing code.
I know how the system's stack works. I know how object's fields are
accessed. The two are necessarily different.
You're trying to optimize your code for a compiler that doesn't exist.
Good for you. Go ahead and do that, and let us all know how that turns
out. I know the BDN is always looking for more articles to publish.
> Maybe your assumptions are already invalid for procedures with many
> local variables. !!!
No matter how many local variables there are, they all reside on the
stack or in registers. They will never be slower to access than fields,
which are stored in RAM and accessed through a memory offset.
> Even if delphi's compiler implemention changes my concept will still
> hold ! :) If it doesn't that would be funny =D
You would find it funny for your concept to fail and have thousands of
programmers' code stop working?
> Ok, stupid programmers will try to do that... and then find out they
> don't know the language as well as they thought.. painfull but wise
> lesson.
A lesson that you continue to refuse to learn.
Every thread you start seems to be the result of you trying something
that doesn't work, and then you blow up because it didn't work the way
*you* expected it to. The world doesn't revolve around you. There are
certain things the language allows, and certain things it doesn't. I
think you'd find the whole thing a lot more enjoyable if you'd simply
learn to work with the things you have instead of complaining
incessantly about all things you don't.
> That lesson can be less painfull/avoided if delphi compiler simply
> gives a warning:
>
> 'loop control variable is read only'
Consider the following program. It won't compile in any existing version
of Delphi, but I think it would compile in your ideal version. At what
places should your compiler issue a warning? And what should the
program's output be?
program Loop;
var
X: Integer;
procedure IncrementVar(var A: Integer);
begin
A := A + 1;
WriteLn('A = ', A);
end;
procedure IncrementX;
begin
X := X + 1;
WriteLn('X = ', X);
end;
begin
for X := 0 to 4 do begin
IncrementVar(X);
IncrementX;
WriteLn(X);
end;
end.
--
Rob
You'd better hope those procedures don't change the values of GridX and
GridY. That might happen in a future version of the program, after all.
> Blabla( GridX, GridY )
>
> 1. Now you still have to find where GridX, GridY came from.
I know exactly where they came from. They were provided with the
procedure in the form of parameters.
> 2. You still need to read BlaBla's documentation to know what it does.
I certainly do, with a name like Blabla.
> What if I have multiple procedures which need to iterate...
>
> Now I have to declare local loop control variables everywhere ! Such a drag
> !
So use a visitor. A visitor lets you wrap all the looping code into an
object. None of the rest of the code needs to know how the loop works,
and you only have to write the looping code once. You could change the
way the loop works -- sequential order, random order, tree traversal,
reverse iteration, etc. -- and that change would be reflected
automatically every place you need to apply an action to all the items
in the collection.
> I could just gave them a very good descriptive name in the class type to
> avoid any possibly conflicts, document it well and then happily re-use it in
> any procedure where I'd like. If I ever have any loop problems that's easy
> to find out with a trace.. no problem at all.
But you've already shown that you might set the fields without actually
being in a loop -- when you only want to act on a single cell. What if
the loop code calls a procedure that needs to work on a different cell
before doing its work on the current cell?
> allocate, deallocate, allocate, deallocate <-
> slooowwwwwwwww
Got any profiling statistics to back up that claim? How do they compare
to the time needed to fetch values from fields instead of local variables?
> That only works when there are few loop control variables !
>
> I have a procedure with 20 loop control variables ! :)
I somehow doubt that. Have you considered breaking the routine into
smaller blocks? It would probably be easier to manage.
Nonetheless, those 20 variables are allocated simply with one
instruction like this:
add esp, $50
Would you like 40 variables instead?
add esp, $a0
>> No, it limits the programmer to always initializing, processing, and
>> displaying all the fields solely via the SingleLoop interface.
>
> Oh get real... it's easy to add new code to do whatever you want.
Not when GridX, GridY, InitializeCell, ProcessCell, and DisplayCell are
all private members of TEngine. The only public access is SingleLoop.
>> Good. I already showed you that accessing field values is slower than
>> accessing local variables. (Method parameters are a kind of local
>> variable.)
>
> Bullshit that only works for few local parameters.
No, it works for as many local variables as the compiler will allow. To
access a field, there will *always* be at *least* one memory access.
Sometimes two. To access a local variable, there will be at *most* one
memory access. Sometimes none. Therefore, there are certain situations
in which a field and a local will take equal amounts of time, and there
are other cases when a local will take less time to access than a field,
but there are never any times when a local will take more time to access.
> I rest my case ;)
If only we were so lucky.
> Fine you use win32api...
>
> I'll use .NET or Delphi VCL instead :)
Gee, I seem to see a lot of .Net and VCL methods that take parameters.
How do you explain them?
>>> If one does pass the parameters we are back to square one 'procedural
>>> languages' where everything had to be passed via parameters...
>>
>> The variables could be global instead.
>
> No they can't DUH <- loop variables.
Duh, yourself. We were talking about passing information to procedures.
If you want a called procedure to have access to a loop variable, you
can't do it with fields or properties, either. You're getting your wires
crossed.
> Or all the program data could be in the program DUH, booorrring.
Sometimes the right way to do something isn't the most fun. The right
way might very well be boring, but that doesn't make it any less right.
> Look at it and you ll see it :P
>
> win32api_any_method( v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11 )
>
> Most not even used... =D
How do you know they're not used? Which ones aren't used?
How about an excercise: Let's consider the CreateFile API function. It
has lots of parameters. Seven of them. Suppose we wanted to make a
version of CreateFile that didn't take any parameters at all. I guess it
would be a method of the TWin32 class. We'd need a declaration like this:
type
TWin32 = class
public
procedure CreateFile;
property FileName: string;
property DesiredAccess: DWord;
property ShareMode: DWord;
property SecurityAttributes: TSecurityAttributes;
property CreationDisposition: DWord;
property FlagsAndAttributes: DWord;
property TemplateFile: THandle;
property CreateFileResult: THandle;
end;
Is that about what you had in mind?
Now, suppose we want to call CreateFile twice. The file names will need
to be different. I want to open the first file for read access and
default values for all the other "parameters," so I would go like this,
right?
Win32.FileName := 'file1.txt';
Win32.DesiredAccess := Generic_Read;
Win32.CreateFile;
File1Handle := Win32.CreateFileResult;
Now, I want to open the next file, but I want to use the default values
for all the "parameters." How do I un-set the DesiredAccess property?
How do I know that the last time the CreateFile method was called that
the caller didn't set some of the other properties to values that I
don't want this time? In order to be absolutely sure that I get the
behavior I want, I think I would need to explicitly set all the
properties, wouldn't I?
> Try changing 10 million lines of code :) just because some fucko went from
> call by value to call by reference parameters in C ;)
>
> test( a );
> to
> test( &a ); <- ouch a million tests no thx :)
>
> You'll get sick of it :)
How would that be any different if A were set via a field instead of
passed as a parameter? Either way, the Test method's object would need
to have a reference to A instead of just its value. So it would be a
matter of changing all the lines from
obj.A = a;
to
obj.A = &a;
> Actually I never got sick of it... since I recognized that C flaw immediatly
> and trashed C into the garbage bin.
>
> Thank god this aint C ;)
Since you dislike C so much, how come *you're* the one who keeps talking
about it? You keep on saying that such-and-such isn't like it is in C. I
already know that. If the C code isn't relevant to the discussion, then
stop talking about it.
>> When you forget to pass a
>> required parameter to a procedure, the compiler will tell you about it.
>> If you forget to set a required field before calling a procedure, the
>> compiler will never tell you. The more places you call the procedure,
>> the more places you'll have to remember to set all the other fields in
>> advance.
>
> Maybe, maybe not. Delphi could give warning, var not initialized.
How would it know it was initialized? An object's fields are all given
default values when the class is instantiated. How would it know whether
you intentionally omitted a field for the second call because you know
you want the value to carry over from the previous call?
> This is the only valid point so far...
>
> Search is your solution.
Not for method pointers. They allow a method's invocation to be greatly
separated from any mention of the method's name. Some procedures' names
are never mentioned in code. Message handlers, for instance, are called
by index.
Searching is also ineffective when your search criteria are more
detailed than simply the name of a method. Maybe it's only methods
called on instances of a certain class. You'd first have to search for
the class name to determine the names of all the fields and variables of
that class, and then you'd need to search for each of those identifier
names in conjunction with the method name.
You've turned what would notmally be a simple task (let the compiler
tell you where the errors are) to a complicated task (don't forget to
search for all uses of the method).
> Copy pasting all necessary 'procedure control variables' and checking if all
> are set somewhere along the path is also part of the solution.
>
> No big deal there.
"Somewhere along the path"? Get real. Properly analyzing the flow of
code is no trivial task.
And if you're just going to paste the list of properties each time you
call the method, you may as well just pass them as parameters instead.
> At least not for single programmer projects.
>
> P.S.: Programming applications is different from Programming games.
Games are applications.
> My mentioned style of programming is more suitable for games <- more
> flexible :P
>
> For applications which are critical I would not recommend my mentioned style
> :)
I think you've just insulted game programmers all over the world. Just
because you're writing recreational programs doesn't mean you have to
throw the tenets of good design out the window.
--
Rob
You don't get it... I'll explain it to you:
There are two sorts of programming styles:
1. Structured programming style.
2. Loose/implicit structured programming style.
The first style is best one when knows exactly what one is suppose to
make...
Think designs, specs, software engering, diagrams etc.
The second style is best one when doesn't know what to progam.
The second style is mostly used for games programming.
That's not an insult in any way... that's simply a fact.
The quake 2 source code is a perfect example of mostly 2 and a little bit of
1.
:P
Skybuck.
Well,
If we want a compiler that generates loop control variables which are read
only then see code example below.
Actually I see no reason why we would not be allowed to change loop control
variables,
since we already have: goto, break, continue, raise, etc..
So modifieing the loop control variable is just another little step.
In case a programmer wants to know if some loop control variable is changed
outside the for statement the Delphi ide could have
a special debug/code quality enhancement by examining all code for this
'programming error'.
Actually I like that idea !
A Delphi IDE Code Examinator Tool !
In such a tool borland can put all their little, big, twisted, wacky, fucked
up, einstein brilliant, crazy, lunatic, fantastic programming styles, do's,
don't, bad style, good style, everything you ever dreamed off !
And then a programmer can just say...."Ok I have this app... I don't want
this, and this and this to happen in my code, now go check for this '''bad
programming''' styles and tell me about it :D"
Then everybody is happy =D
>
> program Loop;
>
> var
> X: Integer;
>
> procedure IncrementVar(var A: Integer);
> begin
> A := A + 1;
> WriteLn('A = ', A);
> end;
>
> procedure IncrementX;
> begin
> X := X + 1;
Error: "Can't modify loop control variables. X is read only"
> WriteLn('X = ', X);
> end;
>
> begin
> for X := 0 to 4 do begin
> IncrementVar(X);
Error: "Can't pass loop control variable as var parameter"
> IncrementX;
> WriteLn(X);
> end;
> end.
Bye,
Skybuck.
procedure TEngine.SingleLoop;
begin
GridY:=0;
while GridY<=100 do
begin
GridX:=0;
while GridX<=100 do
begin
InitializeCell;
ProcessCell;
DisplayCell;
inc(GridX);
end;
inc(GridY);
end;
end;
The difference between "while" and "for" is that with "while" you
explain in detail how you want your loop to run. You don't with "for".
You leave it to the compiler - and the compiler can't be sure to
figure it all out if using globals to count with (these can, in
theory, be modified elsewhere; their value might be used elsewhere).
Well you managed to sucker us again. You are an obvious fool whos only
interest is generating a large number of posts. Any sane programmer who
gives your suggestion 30 seconds of though realizes that all it would do is
make Delphi programs much less robust. If you want to work with a language
that lets you shoot yourself with every step please, PLEASE switch to a C
derivative. Leave us alone.
You posted one yourself. The three nested loops, all using the same
identifier for the control variable.
>> I found your code harder to read.
>
> Hardly... never seen 3 nested loops ? :)
Not with the same control variable, no.
>> More memory? Where? Certainly not within the running program.
>
> 3 local variables vs 1 variable.
>
> You assume the are register variables... that could be compiler specific.
>
> Think 'high level language' not 'low level language' :)
You had three nested loops. The values of the control variables for all
three loops need to be stored *somewhere*. On the stack, on the heap, in
the data segment, in registers -- somewhere. And since those loops are
all active simultaneously, you must have three separate places to store
the values. Whether those variables all happen to share a name is
irrelevant; they still take up space, no matter what level of the
language you're talking about. And it has nothing to do with registers.
Thus, using the "same" variable for three nested loops does nothing to
reduce a program's memory usage.
> I'd like to store for-loop control variable in the thread's calls
> definetion.
In the what?
> I don't feel comfortable making it local variable in the execute procedure.
Why not? It's the Execute procedure that's doing the looping, isn't it?
> I rather keep the number of local variables in the thread execute method as
> low as possible.
>
> It seems a wise thing to do... since it runs millions of times... so keep
> memory requirement low and fast.
But it doesn't run recursively, does it? Each thread gets its *own*
stack. There is a minimum size to a thread's stack. Windows won't allow
anything smaller. (I don't remeber what the precise limit is; I think
it's 1 MB.)
It runs millions of times at once? Tell me more about this computer of
yours that can handle millions of threads.
>> You're
>> allowed to use global variables in for loops in the program's main block
>> and within unit initialization and finalization sections.
>
> Ohhhhhhh so now it is allowed ! gjeeee.
It's always been allowed. You even pointed it out. You're more of a
Turbo Pascal expert than I am.
>>> What if I don't want local variables for whatever reasons !
>>
>> "Whatever reasons"? Come on.
>
> Yeah, what if I have zero stack space !
>
> Big problem.
When did you wind up with zero stack space? If you have zero stack
space, you also can't make any calls to subroutines, even ones that have
no local variables or parameters.
>>> Think about turbo pascal's interrupt keyword...
>>
>> What would you like me to think about it? I've never used it. I never
>> programmed in an environment that needed interrupts.
>
> Low stack space.
Yes... Go on.
> Sure now we have powerfull computers that doesn't mean let's fuckup the
> language :D
The language didn't really change all that much. The change in the
operating system's memory model meant that if a problem called for a
recursive solution, you could implement such a solution with fewer
worries that you'd exceed the limits of the operating system. It meant
you could write code that more accurately reflected your intentions
instead of having to think of different, less expressive ways of writing
your code so as not to disturb the delicate system.
>>>>> Even calling other procedures from inside loops like this should
>>>>> not affect any I.
>>>>
>>>> Not even if you pass i as a var parameter? No thanks.
>>>
>>> Yes, thanks... as long as the procedure is called from within the
>>> loop I shouldn't be changed... after that it can be changed as well.
>>
>> But that's the way it already works. The compiler prevents the variable
>> from being changed by disallowing the kind of code that would lead to it
>> getting changed in the first place.
>
> No, that's not the way it worked.
When didn't it work in the way I described?
> The way it worked was that the loop control variable could not be changed
> during the looping.
And that's the way it still works. And that's the way you proposed it
should work.
> So you can pass it as var, const, whatever you like...
No, you can't pass it as var. Passing as const is no problem.
> Ok, so you can forget about passing it as a var parameter, since that is
> what you wanted to do in the first place !
>
> So what you wanted isn't possible at all !
You started out asking why loop variables need to be local variables. I
told you it was because non-local variables may be accessed outside the
context of the loop and potentially changed, which would break the
integrity of the loop. I then added that this same "outside influence"
problem was the reason loop variables may not be passed as var parameters.
Did I muddy the waters by offering additional information regarding a
phenomenon you inquired about? I'm sorry. I should know better by now
not to elaborate with you, lest I prompt more questions.
> procedure Something( var A : integer );
> begin
>
> end;
>
> procedure Something2;
> var
> i : integer;
> begin
>
> for i:=0 to 10 do
> begin
>
> Something( A ); // not allowed ?
>
> end;
>
> end;
>
> I haven't tested this code yet...
Yes, I can see that it's rather complicated. I wouldn't want to test
something like that, either. I'd much prefer to yell and swear.
--
Rob
Ah yes, you are thinking implementation specific again. And your point is a
valid one !
It does however safe memory space for the sources :P
var
a,b,c : integer;
versus
var
a : integer;
I just safed 4 chars wow ! lol
And the compression factor on my low disk space harddisk will even be higher
! Totally wicked ! :)
Don't underestimate the power of safing 4 chars lol :D
Asshole.
:)
YES, EXACTLY !
AND THAT IS MY WHOLE POINT !
BORLAND/DELPHI/COMPILER SHOULD STILL ALLOW THE LOOP CONTROL
VARIABLE TO BE PASSED EVEN TO VAR PARAMETERS !
SO THAT THE LOOP CONTROL VARIABLE CAN BE USED INSIDE THE PROCEDURE.
IT IS PERFECTLY SAFE TO DO SO, SINCE THE VAR PARAMETER CAN NOT BE CHANGED
I RECOMMEND THAT THE COMPILER GIVE A WARNING WHEN THE PROGRAMMER DOES
TRY TO CHANGE THE LOOP CONTROL VARIABLE !
**** SO MY BIG POINT IS ***
*** IT SHOULD STILL BE ALLOWED ***
*** DON'T DISALLOW IT SINCE THAT IS RETARDED !!! ***
FURTHER MORE MY ORIGINAL POINT WAS
LOOP CONTROL VARIABLES SHOULD ALSO BE ALLOWED TO BE """GLOBAL"""
*** DON'T DISALLOW IT SINCE THAT IS RETARDED !!! ***
SAME THING:
*** JUST GIVE A WARNING WHEN A LINE OF CODE TRIES TO CHANGE THE LOOP CONTROL
VARIABLE
WWWWWWHHHHILLLLLEEEEEEE IT'S BEING USED BY A LOOP !!!!!!! ***
THERE IS YOUR SOLUTION RIGHT THERE !
THE COMPILER/RUNTIME ENVIRONMENT CAN SIMPLY ADD A BOOLEAN INDICATING IF THE
LOOP CONTROL
VARIABLE IS BEING USED BY A LOOP !
IF IT IS BEING USED THAN IT IS NOT ALLOWED TO CHANGE THE LOOP CONTROL
VARIABLE VIA EXTERNAL/USER SPECIFIC CODE. ONLY THE GENERATED CODE FOR THE
LOOP CONTROL VARIABLE MAY CHANGE THE LOOP CONTROL VARIABLE.
A LOCK CAN BE CONSTRUCTED ON THE LOOP CONTROL VARIABLE SO THAT ONLY THAT
LINE OF CODE MAY CHANGE THE LOOP CONTROL VARIABLE ! =D
That doesn't seem so hard to do ! :D
THANK YOU !
PEACE OUT ! :)
Skybuck =D
Those don't change the loop variable. All but one of them exits the
loop, and the remaining one simply skips the tail portion of a loop.
> So modifieing the loop control variable is just another little step.
Turning the for loop into a while or repeat loop is also just a little step.
>>procedure IncrementX;
>>begin
>> X := X + 1;
>
>
> Error: "Can't modify loop control variables. X is read only"
>
>
>> WriteLn('X = ', X);
>>end;
I thought that might be your response. (Previously, you've been saying
that it would be warning rather than an error, by the way.) Now try this
one:
program Loop;
var
X: Integer;
procedure IncrementX;
begin
X := X + 1;
end;
begin
IncrementX;
WriteLn(X);
for X := 0 to 4 do begin
WriteLn(X);
end;
WriteLn(X);
end.
Note the difference: IncrementX is not called from within the loop
anymore. But X is still used as a loop variable. Should IncrementX still
be prohibited from compiling?
I hope you recognize that I can make the code arbitrarily complex. Even
if the compiler knows that IncrementX is never called in this program
while the loop is active, I can construct other code that does call
IncrementX within the loop, but indirectly, such as via a procedure
pointer, or by using RTTI to call the procedure by name at run time.
(That last possibility would of course require IncrementX to be a method
instead of a procedure, but that change is easy to make.)
I could move the loop to another unit. Suppose Unit A contained the
declarations for X and IncrementX. They get compiled and stored in a DCU
file. Next, I introduce Unit B, which uses X as a loop variable. Do you
now want the compiler to detect this new use for X, and then go back to
recompile Unit A? That's what it would have to do if it was to issue a
message at X's use within IncrementX. That would have a significant
effect on Delphi's compilation speed (which is something that Borland is
famous for) if it was forced to re-inspect all the compiled units,
looking for new uses of already-compiled variables.
--
Rob
Ah, you're grasping at straws, now.
--
Rob
Really? Then why is it that *I'm* the one who introduced the topic of
var parameters?
> BORLAND/DELPHI/COMPILER SHOULD STILL ALLOW THE LOOP CONTROL
> VARIABLE TO BE PASSED EVEN TO VAR PARAMETERS !
>
> SO THAT THE LOOP CONTROL VARIABLE CAN BE USED INSIDE THE PROCEDURE.
>
> IT IS PERFECTLY SAFE TO DO SO, SINCE THE VAR PARAMETER CAN NOT BE CHANGED
Read that sentence again. Do you realize what you're saying? You're
asking for a var parameter that isn't really a var parameter. And you've
said that such a thing would make code *easier* to understand.
Read-only var parameters. Sounds like the bastard sibling of writable
consts.
> I RECOMMEND THAT THE COMPILER GIVE A WARNING WHEN THE PROGRAMMER DOES
> TRY TO CHANGE THE LOOP CONTROL VARIABLE !
>
> **** SO MY BIG POINT IS ***
>
> *** IT SHOULD STILL BE ALLOWED ***
>
> *** DON'T DISALLOW IT SINCE THAT IS RETARDED !!! ***
But in one of my other examples, you said the compiler should issue an
error. Errors disallow compilation. Whatever shreds of an argument you
once had are slipping right through your fingers.
> FURTHER MORE MY ORIGINAL POINT WAS
>
> LOOP CONTROL VARIABLES SHOULD ALSO BE ALLOWED TO BE """GLOBAL"""
>
> *** DON'T DISALLOW IT SINCE THAT IS RETARDED !!! ***
>
> SAME THING:
>
> *** JUST GIVE A WARNING WHEN A LINE OF CODE TRIES TO CHANGE THE LOOP CONTROL
> VARIABLE
>
> WWWWWWHHHHILLLLLEEEEEEE IT'S BEING USED BY A LOOP !!!!!!! ***
How does the compiler know when it's being used in a loop and when it isn't?
A procedure that takes a var parameter may be called within a loop, and
it may be called at other times. Its parameter may or may not be a
reference to a loop variable.
unit A;
var
X, Y, Z: Integer;
procedure IncrementVar(var V: Integer);
begin
V := V + 1;
end;
-------------
unit B;
begin
for X := 0 to 4 do begin
IncrementVar(X);
IncrementVar(Y);
end;
IncrementVar(Z);
end;
The compiler cannot issue a warning within the IncrementVar procedure
since it's a perfectly valid procedure and makes no reference to any
loop variables. The compiler cannot issue a warning when IncrementVar is
called on Y or Z since those aren't loop variables.
The only place a warning could possibly be appropriate is the place
where IncrementVar is called on X. For the compiler to be able to do
that, it would need to be aware of everything that IncrementVar does,
even after IncrementVar had already been compiled and written to a DCU
file. It would need to load the entire contents of that DCU file
whenever it compiled the loop, just in case one of the called procedures
tries to modify its var parameter.
If a procedure is declared as having a var parameter, isn't it a very
good chance that it will modify that parameter, even without having to
actually look at the code to confirm it?
> THERE IS YOUR SOLUTION RIGHT THERE !
>
> THE COMPILER/RUNTIME ENVIRONMENT CAN SIMPLY ADD A BOOLEAN INDICATING IF THE
> LOOP CONTROL
> VARIABLE IS BEING USED BY A LOOP !
Would that Boolean be something in the compiler's internal data
structures, or would it be something that got checked at run time? I
think it would need to be available at run time so that the IncrementVar
procedure above would know whether it's really allowed to modify its
parameter.
--
Rob
Are you saying the Id Software didn't know what it was doing when it
designed Quake 2? I doubt it. Software projects like that involve
months, possibly years, of planning. There are code reviews and design
meetings. Features are vetted, their costs considered before being
added. Things are not added without considering the effect they'll have
on the rest of the program.
As much as you hate C, you sure say a lot of good things about Quake's
source code.
--
Rob
Oh shut up lol... like you know anybody from that team hehehehe.
>
> As much as you hate C, you sure say a lot of good things about Quake's
> source code.
Dude get real... it's not about C at all... it's about the concepts behind
the source code.
>
> --
> Rob
I wanted you to look at how few parameters are passed.
Have you seen it now ?
Have you seen how much is global ? :)
I don't know if C allows loop control variables do be global ?
Does it ?
> statements are in the same global scope, they are local in scope to
> each other .
> >
> >Alternatively
> >
> >1. Buy Delphi's VCL source code or Download any VCL Component.
> >
> Have it.
> >2. Wipe the shit out of your eyes
> >
> >3. Take a longgggg harrrddd look at the component's source code.
> >
> >4. Notice how properties change the component behaviour without using
> >parameters in component's usage code.
> >
> >5. Kiss my pinky :D
> >
> Properties are used to maintain state information which is needed for
> the lifetime of the object. Loop control variables do not maintain any
> object state information nor are they needed for the lifetime of the
> object.
>
> What you want to do is write procedural, hope-I-don't-step-on-my-dick,
> spaghetti code using an OO tool. It can be done but you will spend a
> lot of time complaining about all the "OO" bugs you've discovered.
Funny but bullshit. =D
Bye,
Skybuck.
YOU ARE TRYING TO FIND PROBLEMS WITH MY IDEA !
THAT IN ITSELF IS FAIR !
I AM SAYING TO YOU ALL AND EVERY PROBLEM YOU THINK OF CAN BE SOLVED ! =D
>
> > BORLAND/DELPHI/COMPILER SHOULD STILL ALLOW THE LOOP CONTROL
> > VARIABLE TO BE PASSED EVEN TO VAR PARAMETERS !
> >
> > SO THAT THE LOOP CONTROL VARIABLE CAN BE USED INSIDE THE PROCEDURE.
> >
> > IT IS PERFECTLY SAFE TO DO SO, SINCE THE VAR PARAMETER CAN NOT BE
CHANGED
>
> Read that sentence again. Do you realize what you're saying? You're
> asking for a var parameter that isn't really a var parameter. And you've
> said that such a thing would make code *easier* to understand.
>
> Read-only var parameters. Sounds like the bastard sibling of writable
> consts.
>
> > I RECOMMEND THAT THE COMPILER GIVE A WARNING WHEN THE PROGRAMMER DOES
> > TRY TO CHANGE THE LOOP CONTROL VARIABLE !
> >
> > **** SO MY BIG POINT IS ***
> >
> > *** IT SHOULD STILL BE ALLOWED ***
> >
> > *** DON'T DISALLOW IT SINCE THAT IS RETARDED !!! ***
>
> But in one of my other examples, you said the compiler should issue an
> error. Errors disallow compilation. Whatever shreds of an argument you
THATS BECAUSE YOU ARE PUTTING WORDS INTO MY MOUTH ! :D
YOU ASKED ME WHAT ONE SHOULD DO IN SUCH CASE.
I ANSWERED YOU, BIG DEAL.
THAT HOWEVER DOES NOT MEAN THAT THAT IS THE WAY I WANT IT TO BE SOLVED.
SINCE THAT IS NOT THE PROBLEM TO BEGIN WITH.
SOLVE THE CORE PROBLEM AND ALL OTHER PROBLEMS ARE SOLVED.
> once had are slipping right through your fingers.
>
> > FURTHER MORE MY ORIGINAL POINT WAS
> >
> > LOOP CONTROL VARIABLES SHOULD ALSO BE ALLOWED TO BE """GLOBAL"""
> >
> > *** DON'T DISALLOW IT SINCE THAT IS RETARDED !!! ***
> >
> > SAME THING:
> >
> > *** JUST GIVE A WARNING WHEN A LINE OF CODE TRIES TO CHANGE THE LOOP
CONTROL
> > VARIABLE
> >
> > WWWWWWHHHHILLLLLEEEEEEE IT'S BEING USED BY A LOOP !!!!!!! ***
>
> How does the compiler know when it's being used in a loop and when it
isn't?
ANSWER: USE A LOCK !
>
> A procedure that takes a var parameter may be called within a loop, and
> it may be called at other times. Its parameter may or may not be a
> reference to a loop variable.
Ohhhhhhhhhhhhhhh I am scared such a big problem ?! NOT !
The compiler can easily add some data to tell the compiler that the variable
is currently being used in a loop.
Use your imagination and be creative... gjeeee
<your frustrated example cut :D>
Give the idea a chance before slaughtering it :P
I had to go somewhere... otherwise I might have posted some pseudo code how
to do it all...
Though it's not my job to invent algorithms for compilers :D
I just request them... and then it's borland's job to make it happen
:P******* >D
> > THERE IS YOUR SOLUTION RIGHT THERE !
> >
> > THE COMPILER/RUNTIME ENVIRONMENT CAN SIMPLY ADD A BOOLEAN INDICATING IF
THE
> > LOOP CONTROL
> > VARIABLE IS BEING USED BY A LOOP !
>
> Would that Boolean be something in the compiler's internal data
> structures, or would it be something that got checked at run time? I
> think it would need to be available at run time so that the IncrementVar
> procedure above would know whether it's really allowed to modify its
> parameter.
Both.
I am exhausted from a trip... a nice trip... but still I will post and try
to create the idea in pseudo form... to see if any problems remain.
Now I create a simple var example because you have been nagging about var
parameters non stop ! =D
Procedure Test( Var RobIsNagging : integer );
begin
RobIsNagging := 0; // shut up =D
end;
Var
vIndex : integer;
IndexIsLoopControlVariable : boolean; // <- goes with vIndex ;)
Procedure DoSomethingWithvIndex;
begin
if not IndexIsLoopControlVariable then
begin
vIndex := 1; // not allowed
end else
begin
ShowMessage('error blablabla see below ;)');
end;
end;
// main
Begin
// compiler stuff:
CheckIfIndexIsALoopVariable
if IndexIsLoopControlVariable then
begin
ShowMessage('error index is being used as a loop control variable,
index may not be modified');
end else
begin
vIndex := 5; // allowed
end;
//
IndexIsLoopControlVariable := true;
for vIndex := 0 to 7 do
begin
if IndexIsLoopControlVariable then
begin
ShowMessage('error blablabla');
end else
begin
Test( vIndex ); // not allowed
end;
end;
IndexIsLoopControlVariable := false;
// same check here
vIndex := 7; // allowed
End;
Now, was that so hard ?! NO
I DARE TO SAY: EASYYYYYYYYYYYYYYYYYYYYYYYYYY
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! >>>D
Bye,
Skybuck =D
I already proofed that it's not !
For the rest of your posting see one of my other postings which explains my
idea of locking the loop control variable.
Skybuck.
Meteors could fall on my head as well =D
>
> >It's about the readibility of the current code. :)
>
> I don't see any advantages to your construction, and there are plenty
> of disadvantages.
Oh boy... such a big statement for such a simple piece of code !
Get real !
Bye,
Skybuck :)
C's loops don't have control variables in the way Delphi's do. You
really can't compare the languages on that point.
--
Rob
Oh man, my response to that is going to be fucking simple:
a for loop is a for loop, conceptually ! :P
Bye,
Skybuck :D
No it is not
Next you'll be stating that an Integer is a Float - 'conceptually'
Then C's for loops are not for loops. They are while loops with
streamlined syntax.
for ([initializations]; [conditions]; [increments]) {
[actions];
}
That can easily be transformed into a normal while loop like this:
[initializations];
while ([conditions]) {
[actions];
[increments];
}
You might think that those code forms may be duplicated in Delphi, but
only with significant restrictions on the contents of the three
"arguments" to a C for loop.
In C, each of those "arguments" may be compound statements. You can
perform several initializations, and the don't all have to be to simple,
ordinal values. Delphi only performs one initialization. In C, you can
perform complex conditional checks. Those checks may have side effects,
and those side effects will be applied before every iteration of the
loop. The checks needn't have any relation to the variables set in the
initialization. Delphi only evaluates the condition once, and the
condition is required to be a value of the same type as the loop-control
variable. In C, the [increments] section can really be anything,
including code with side effects beyond simply incrementing a single
variable. Delphi doesn't allow the programmer to specify anything to be
changed; the single loop-control variable will always be advanced by
exactly one value toward the loop-terminating value.
The similarities between C's and Delphi's for loops are superficial.
--
Rob
But at what expense?
Is it really worth solving? There are already alternatives to everything
you've lamented about. Alternatives that everyone else seems to be able
to get along with just fine.
Which other potential features are you willing to sacrifice in order for
Borland to have the resources to implement and test arbitrary
loop-control variables? Code refactoring? Generics?
>>> BORLAND/DELPHI/COMPILER SHOULD STILL ALLOW THE LOOP CONTROL
>>> VARIABLE TO BE PASSED EVEN TO VAR PARAMETERS !
>>>
>>> SO THAT THE LOOP CONTROL VARIABLE CAN BE USED INSIDE THE PROCEDURE.
>>>
>>> IT IS PERFECTLY SAFE TO DO SO, SINCE THE VAR PARAMETER CAN NOT BE
>>> CHANGED
The above is a quote from your previous message. In the next message,
you provided this code example:
> for vIndex := 0 to 7 do
> begin
>
> if IndexIsLoopControlVariable then
> begin
> ShowMessage('error blablabla');
> end else
> begin
> Test( vIndex ); // not allowed
> end;
>
> end;
So is it allowed or not? You can't have it both ways. (And that's even
after I decided that the "not allowed" bit in the commented line must be
a mistake.)
> YOU ASKED ME WHAT ONE SHOULD DO IN SUCH CASE.
>
> I ANSWERED YOU, BIG DEAL.
>
> THAT HOWEVER DOES NOT MEAN THAT THAT IS THE WAY I WANT IT TO BE SOLVED.
If I ask questions with premises you disagree with, you need to say so.
If you don't make your objections known, I'm left to conclude that you
accepted my assumptions when you answered the questions.
> SINCE THAT IS NOT THE PROBLEM TO BEGIN WITH.
>
> SOLVE THE CORE PROBLEM AND ALL OTHER PROBLEMS ARE SOLVED.
The core problem is that loops become unstable when the loop-control
variable is subject to changes outside the influence of the loop. That
problem has already been solved. It wasn't solved the way you would like
it to have been solved, and you're just going to have to learn to live
with that.
> Though it's not my job to invent algorithms for compilers :D
>
> I just request them... and then it's borland's job to make it happen
Speaking of which, have a look at the following link, in which Danny
Thorpe, the Delphi compiler architect, describes *exactly* how you
should go about getting Borland to do your bidding.
http://homepages.borland.com/dthorpe/blog/delphi/2004_04_01_archive.php#108175802940991038
Take special note that whining in Usenet newsgroups is not on the list.
Some of the items, however, might be interpretted as allowing whining on
Borland newsgroups.
Thank you, by the way, for switching back to mixed-case sentences.
They're much easier to read than the all-caps stuff you started out with.
> Now I create a simple var example because you have been nagging about var
> parameters non stop ! =D
I offered to drop that subject, but then you said that var parameters
were exactly your point, so I figured they were fair game.
> if not IndexIsLoopControlVariable then
> begin
> vIndex := 1; // not allowed
> end else
> begin
> ShowMessage('error blablabla see below ;)');
> end;
Realize that you're proposing adding an additional run-time check to
every assignment of a global variable or field in the entire program.
The rationale you initially cited for wanting something like this was
"for speed reasons."
--
Rob
FOR means to go forward, to set off for town.
To take steps.
FOR an hour, or we walked FOR miles.
FOR doesn't mean WHILE :)
Get it ? :)
Skybuck.
Absolutely, the alternatives suck balls :)
>
> Which other potential features are you willing to sacrifice in order for
> Borland to have the resources to implement and test arbitrary
> loop-control variables? Code refactoring? Generics?
Focus on basics first :P =D
>
> >>> BORLAND/DELPHI/COMPILER SHOULD STILL ALLOW THE LOOP CONTROL
> >>> VARIABLE TO BE PASSED EVEN TO VAR PARAMETERS !
> >>>
> >>> SO THAT THE LOOP CONTROL VARIABLE CAN BE USED INSIDE THE PROCEDURE.
> >>>
> >>> IT IS PERFECTLY SAFE TO DO SO, SINCE THE VAR PARAMETER CAN NOT BE
> >>> CHANGED
>
> The above is a quote from your previous message. In the next message,
> you provided this code example:
>
> > for vIndex := 0 to 7 do
> > begin
> >
> > if IndexIsLoopControlVariable then
> > begin
> > ShowMessage('error blablabla');
> > end else
> > begin
> > Test( vIndex ); // not allowed
> > end;
> >
> > end;
>
> So is it allowed or not? You can't have it both ways. (And that's even
> after I decided that the "not allowed" bit in the commented line must be
> a mistake.)
Oh come on I already explained to you.
If the loop control variable is locked it is not allowed.
If the loop control variables is not locked it is allowed.
In the last situation calling Test( vIndex ); will be allowed and work just
fine.
SO YES, I CAN HAVE BOTH WAYS !
>
> > YOU ASKED ME WHAT ONE SHOULD DO IN SUCH CASE.
> >
> > I ANSWERED YOU, BIG DEAL.
> >
> > THAT HOWEVER DOES NOT MEAN THAT THAT IS THE WAY I WANT IT TO BE SOLVED.
>
> If I ask questions with premises you disagree with, you need to say so.
> If you don't make your objections known, I'm left to conclude that you
> accepted my assumptions when you answered the questions.
BLABLABLA
YOU ARE TO XOR LIKE :)
Well who's to say for sure what can't and can be done by the compiler.
Still if it's true then it can be done during debugging and later disabled
for speed reasons =D
Skybuck.
It is:
Publish your development successes, challenges, and interests online
You don't have to obtain an exclusive audience with a Borlander to make your
interests known to us. You don't even have to email. Through the magic of
the Internet, if you publish a document mentioning Borland product names
we'll probably hear about it within a week or two, depending on how quickly
Google scans your site. If you publish a link to this blog, I'll know about
within the hour in many cases.
:)
>That's why Delphi is a better language and C plain bullshit.
>
>FOR means to go forward, to set off for town.
>
>To take steps.
>
>FOR an hour, or we walked FOR miles.
>
>FOR doesn't mean WHILE :)
Find out what 'For' really means in 'C'
- personally I appreciate the OP definition
Oh look it's Mister "I dont know what a double linked list it"
So I'll just disregard your bullshit :P
Next you will be saying:
Nooooooooooo-ooohhhhhh
A for loop is a while loop conceptually.
Bye, bye,
Skybuck :P***
Oh how totally unexpected of you... :P
> FOR means to go forward, to set off for town.
Even in Delphi For doesn't necessarily mean "go forward". (It can mean "go
backwards".) What it means is "for each n do".
Pascal derivatives have a For Do loop. C derivatives, like some ALGOL
derivatives, have a For While Do. In both cases the loop is a variant of
"for each n do". The difference is in the terminating condition. Pascal
allows only one terminating condition. C and ALGOL allow multiple
conditions.
> FOR an hour, or we walked FOR miles.
>
> FOR doesn't mean WHILE :)
>
> Get it ? :)
I do. For is not a verb. Do and While are. "For an hour" is meaningless
without a context. "For miles" means nothing without the verb Walked.
The problem, IMNO, with C is that the designers had an almost pathological
dislike of typing and thus avoided multi-character language tokens whenever
possible (although they might argue that it was space restrictions that
prompted this). Its a big mistake, IMO, to assume that the generally
accepted definition of words bears any relation to their operation in C. Its
an even bigger mistake to assume that just because statements in two
languages seem similar they have a common meaning. This holds true in both
formal and natural languages. You know the old saying about assume?
If Delphi can optimize;
1. Short for loops.
2. A bit longer for loops with calls to procedures
3. A bit longer loop with many instructions.
4. Even longer loops with if statements in them.
and it makes a significant speed difference... then I would say keep the
shit...
Otherwise get rid off the shit... and make the global shit possible =D
So if speed gain is minimal... screw it :P
Bye,
Skybuck.
This ain't your site.
--
Rob
You write things so eloquently. Your mother must be proud!
>> So is it allowed or not? You can't have it both ways. (And that's
>> even after I decided that the "not allowed" bit in the commented
>> line must be a mistake.)
>
> Oh come on I already explained to you.
Yes, but you explain it a different way every time.
> If the loop control variable is locked it is not allowed.
>
> If the loop control variables is not locked it is allowed.
>
> In the last situation calling Test( vIndex ); will be allowed and
> work just fine.
Why would that be allowed? It's inside the loop.
--
Rob
No in this last case I ment it was outside the loop
begin
Test(vIndex);
end;
Are you done yet ?
Skybuck.