SRL Archive - Research & Development Lounge

Foreach for simba(first experience).


CynicRus

2012-06-19 15:39:42

Hello, everyone. I'm a novice on this forum, but I have some programming experience in C++, Object Pascal and C#.
I liked SIMBA: the idea, as well as the software, is really great . Unfortunately, I have not found foreach
operator in SIMBA, still, I enjoyed the experience of using it. I wanted to create one in SIMBA. Today I will tell you how I made a convenient analog of this operator for myself.
What you will need is:
1) Some imagination;
2) MSDN;

Well, let's begin-)

As stated in the MSDN:
“The foreach statement repeats a group of embedded statements for each element in an array or an object collection. The foreach statement is used to iterate through the collection to get the desired information, but should not be used to change the contents of the collection to avoid unpredictable side effects.”

In Delphi the analogue of the cycle (foreach) is "for in TList". However, in SIMBA we don't have "for in List" or foreach. How can we create it? The algorithm works as simple as that: we go through the collections doing something with each element or an element of a condition. Since we do not have collections, we use arrays. (I have not found an opportunity of overloading procedures, so I had to create two procedures with different names -( )

File foreach.simba:

//procedure foreach for arrays
procedure foreach(Arr: array of Variant;func:function(p: Variant):integer);
var
i: integer;
begin
i:=0;
for i := 0 to high(Arr) do
if func(Arr[i]) <> 0 then exit;
end;
//procedure foreach_p for tpoint array
procedure foreach_p(Arr: array of TPoint;func:function(p: TPoint):integer);
var
i: integer;
begin
i:=0;
for i := 0 to high(Arr) do
if func(Arr[i]) <> 0 then exit;
end;

The presented procedure of implementing the algorithm foreach is meant for three types of arrays: array of integer, array of string, array of Tpoint. The first argument is the array itself, the second argument &#8211; the procedure for any action with an element of the array.

Test script:

program foreach;
{$i srl/srl/misc/foreach.simba}
function Display(int: variant): integer;
begin
Writeln(ToStr(int));
if int=5 then result:=1 else result:=0;
end;

function Display1(point: TPoint): integer;
var
p: Tpoint;
begin
p.x:=162;
p.y:=244;
Writeln(ToStr(point));
if Point=p then result:=1 else result:=0;
end;

function Display2(s: variant): integer;
begin
Writeln(s);
result:=0;
end;

var
TestArray: array of variant;
PointArray: array of TPoint;
TestStrings: array of variant;
flag: integer;

begin
flag:=0;
TestArray:=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
PointArray:=[Point(24,39),Point(25,67),Point(162,244),Point(188,249)];
TestStrings:=['Metallica','Iron Maiden','MegaDeath'];
Writeln('INTEGER ARRAY');
foreach(TestArray,@Display);
Writeln('TPOINT ARRAY');
foreach_p(PointArray,@Display1);
Writeln('STRING ARRAY');
foreach(TestStrings,@Display2);

end.

Test output:

Compiled successfully in 16 ms.
INTEGER ARRAY
1
2
3
4
5
TPOINT ARRAY
(24, 39)
(25, 67)
(162, 244)
STRING ARRAY
'Metallica'
'Iron Maiden'
'MegaDeath'
Successfully executed.

In conclusion I would like to say that there is nothing complicated or innovative, just a story about a missing implementation of the algorithm. I hope this material will be useful for someone. Thank you for your attention.

UPDATE: loop exit added.

Brandon

2012-06-19 16:30:51

I definitely love the for_each loop but it isn't supposed to use for-iteration loops under the hood so this is just a wrapper but I still like it. Next is that instead of casting for each type, why not use a TVariant? or TVariantArray? (Note Variant types don't work for point arrays or points but work for everything else).

You should make a wrapper for the For-Range loop:


Procedure ForRange(I: Variant; T: TVariantArray; Proc: Procedure(A: Args));
begin
For I To High(T) Do
Proc(I);
end;

Now of course this isn't a real for-range. It's just a wrapper around the for-loop. BUT the thing about writing wrappers for loops and why it's bad is because you cannot break out of the loop when a condition is met as there is no way to pass a conditional statement as a parameter.

These would only be useful for looping entire arrays and calling functions multiple times but for real usage, well it isn't there and probably never will be.

So all in all, I support the "IDEA" but I cannot support this implementation. I wouldn't even support my own example because it's bad. But you do have some creative and good ideas so I hope I can see some more from you soon.

I know you cannot break out of for_each so this is an ok implementation but I prefer not to use wrappers for things that should be language implemented.

CynicRus

2012-06-19 17:49:24

So, i fixed my code. Loop exit is added-)
Foreach.simba

//procedure foreach for arrays
procedure foreach(Arr: array of Variant;func:function(p: Variant):integer);
var
i: integer;
begin
i:=0;
for i := 0 to high(Arr) do
if func(Arr[i]) <> 0 then exit;
end;
//procedure foreach_p for tpoint array
procedure foreach_p(Arr: array of TPoint;func:function(p: TPoint):integer);
var
i: integer;
begin
i:=0;
for i := 0 to high(Arr) do
if func(Arr[i]) <> 0 then exit;
end;

Test script:

program foreach;
{$i srl/srl/misc/foreach.simba}
function Display(int: variant): integer;
begin
Writeln(ToStr(int));
if int=5 then result:=1 else result:=0;
end;

function Display1(point: TPoint): integer;
var
p: Tpoint;
begin
p.x:=162;
p.y:=244;
Writeln(ToStr(point));
if Point=p then result:=1 else result:=0;
end;

function Display2(s: variant): integer;
begin
Writeln(s);
result:=0;
end;

var
TestArray: array of variant;
PointArray: array of TPoint;
TestStrings: array of variant;
flag: integer;

begin
flag:=0;
TestArray:=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
PointArray:=[Point(24,39),Point(25,67),Point(162,244),Point(188,249)];
TestStrings:=['Metallica','Iron Maiden','MegaDeath'];
Writeln('INTEGER ARRAY');
foreach(TestArray,@Display);
Writeln('TPOINT ARRAY');
foreach_p(PointArray,@Display1);
Writeln('STRING ARRAY');
foreach(TestStrings,@Display2);
end.

Test output:

INTEGER ARRAY
1
2
3
4
5
TPOINT ARRAY
(24, 39)
(25, 67)
(162, 244)
STRING ARRAY
'Metallica'
'Iron Maiden'
'MegaDeath'
Successfully executed.

CynicRus

2012-06-20 03:36:35

And another realisation foreach:

procedure foreach_ex(Arr: array of Variant;func:function(p: Variant):integer);
var
i: integer;
v: integer;
begin
i:=0;
repeat
v:=func(Arr[i]);
i:=i+1;
until v<>0;
end;

Test function:

function Display(int: variant): integer;
begin
Writeln(ToStr(int));
if int=5 then result:=1 else result:=0;
end;
****
//usage
****
var
TestArray: array of variant;

begin
TestArray:=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
foreach_ex(TestArray,@Display);
end.
Output:

ForEachEx
1
2
3
4
5