[fpc-devel] for-in-index loop

Sven Barth pascaldragon at googlemail.com
Sat Jan 26 13:22:02 CET 2013


Rereading your mail now with what I wrote about tuples in mind:

On 25.01.2013 22:44, Alexander Klenin wrote:
> 2) Indeed, introducing tuples to Pascal might be an alternative
> solution. Below is a proposal:
> 2.1) Tuple definition. Tuple is an anonymous list of values, possibly
> of different types. It is impossible to explicitly declare tuple type,
> or store a tuple in a variable.

As Michael said Pascal is a declarative language (though this has been 
forgotten some times) so I'd allow the declaration of tuple types using 
something like "tuple of (type1, type2, etc.)"

> 2.2) Tuple construction: Tuple may be constructed by listing its
> elements in as a semicolon-separated list in parenthesis:
>    (a; b; c). Also, any value of record or array type can be converted
> to a tuple by using built-in pseudo-function Tuple
>    (or other some name, perhaps even a special character like ~ or @@).
>    Semicolon is chosen to underline similarity with the record
> constants -- but perhaps comma is better.
>    Alternatively, a square brackets may be used since they already
> represent similar semantics for "array of const" parameters.

As I said in my other mail I'm still not sure whether "(...)" is a good 
idea, because there can be code like "i := (42)" (it's not forbidden and 
thus it needs to be allowed with such an extension as well). 
Nevertheless I'd prefer "," as a seperator.

Also I'd definitely prefer NOT to use special characters. Instead I'd 
prefer the use of an instrinsic like "Tuple" (though - together with my 
declaration proposal - one needs to pay special attention to the 
difference of "Tuple(...)" and "tuple of (...)" in the parser)

> 2.3) Tuple assignment. Tuple may be assigned to a record, provided
> field types match. Most important, tuples may be used in
> deconstructing assignment by listing variables in the same syntax on
> the left side of assignment:
>    (a; b) := (x; y);
> If the left side contains less variables then the tuple has values,
> extra values are ignored.
> If the right side contains more variables, it is an error.

I don't know whether we should use this "value ignoring". Maybe always 
an error if the count differs is better... (and in the case of a Tuple 
returned by the Tuple intrinsic we'd also need a new RunError and 
Exception type)

> 2.4) Tuples as procedure arguments. Tuple may be passed to a procedure
> or function.
> In this case, deconstructing assignment is performed from the tuple to
> the actual arguments,
> as if they were listed on the left side of assignment in the previous point.
> Also, a tuple may be present inside square brackets representing
> "array of const" argument.
> In this case, it works as if tuple elements were listed instead.
>

Together with my "declaration" proposal this is a bad idea. So no 
deconstructive assignments on procedure calls. Things like this can be 
allowed though:

=== code begin ===

type
   TTestTuple = (Integer, String);

procedure Test(aArg1: String; aArg2: TTestTuple; aArg3: Integer);

// somewhere else
Test('Foobar', (42, s), i);

=== code end ===

> 2.5) for-in loop accepts a list of variables after "for" keyword. In
> this case, it tries to convert the Current value to a tuple and
> perform tuple assignment.

It should not only be a list of variables, but a "tuple deconstructor":

=== code begin ===

for (key, data) in SomeContainer do
   ...

=== code end ===

The enumerator then of course needs to return a fitting tuple type.

This way one can keep the current enumerators (maybe except build in 
ones): they just don't return a tuple type, but a "scalar" and thus 
you'd continue to write

=== code begin ===

for data in SomeContainer do
   ...

=== code end ===

>
> With this proposal, following benefits are gained:
>
> 1) Group assignment:
> (x; y; z) := (0; 0; 0);
> (a; b) := (b; a);
> (first; second) := Tuple(SomeFunctionReturningArray());
>

Agreed.

> 2) Record literals without constructor functions:
>    ARectangle.TopLeft := (100; 200);
>

I don't know whether this should be possible without an approbiate 
intrinsic (the inverse of "Tuple"), but I'm open here...

> 3) Formatting complex values:
>    s := Format('%d-%d', [Tuple(CenterPoint(ARectangle))]);

Format would need to be adjusted to support Tuple types, but ok...

>
> 4) Collecting default values for procedures:
> In some library:
> procedure WithManyParams(A, B, C, D, E, F: Integer);
> In user code:
> var
>    p: record A, B, C, D, E, F: Integer; end;
>
> p := (default; values; for; params);
> ...
> p.E := 5;
> WithManyParams(Tuple(p));

As said above this is a no in my opinion.

>
> 5) Finally, for-in:
> for (v; i) in a do ...
> Compiler code for built-in types mostly the same as for-in-index --
> syntax difference only.
> User-defined iterators may return records with fields (value, key).
> In the case of
> for v in a
> v may now be either a record or just a value, depending on the type.

Basically agreed.

Regards,
Sven



More information about the fpc-devel mailing list