[fpc-devel] RFC: Support for new type "tuple" v0.1

Sven Barth pascaldragon at googlemail.com
Sun Jan 27 12:16:52 CET 2013


On 27.01.2013 02:35, Hans-Peter Diettrich wrote:
> Sven Barth schrieb:
>
>> * Description
>>
>> What are tuples? Tuples are an accumulation of values of different or
>> same type where the order matters. Sounds familiar? They are in this
>> regard similar to records, but it's only the order of an element that
>> matters, not its name. So what does make them special? Unlike records
>> you can only query or set all the elements of a tuple at once. They
>> basically behave like multiple assignments. In effect they allow you
>> to return e.g. a multivalued result value without resorting to the
>> naming of record fields (you'll still need to declare a tuple type) or
>> the need for out parameters. This in turn allows you to use them for
>> example in "for-in" loops.
>
> The lack of element names results in bloated code and runtime overhead.
> See below.
>

I don't see why it should result in bloated code and runtime overhead.

>> * Declaration:
> [...]
>
>> The usage of constructors and destructors also allows a realisation of
>> group assignment:
>>
>> === code begin ===
>>
>> var
>>   a, b, e: Integer;
>>   c, d: String;
>> begin
>>   a := 42;
>>   c := 'Hello World';
>>   (b, d) := (a, c);
>>   a := 21;
>>   b := 84;
>
>>   (a, b) := (b, a); // the compiler needs to ensure the correct usage
>> of temps here!
>
> What will happen here?
>
> At compile time a tuple type (integer; integer) has to be defined, and
> an instance must be allocated for it. Initialization and finalization
> information/code must be added if required.
>
> At runtime the arguments are copied into that tuple instance, then
> copied into the target variables. All "copies" may be subject to type
> conversions and reference counting.

And here you are wrong. We have an assignment node with a tuple node on 
the left and a tuple node on the right. So the compiler can insert 
direct assignments between the corresponding elements on the left and 
right maybe with the need to insert a few temp vars to resolve cases 
like the above. And even then the optimizer can reduce the amount of 
temps. So the amount of temps is normally less or equal to the count of 
elements, but often it should be less than the count of elements.

If a tuple node is only on one side of the assignment and the other one 
is a load node for a tuple variable then construction/deconstruction 
(depending on the side) will take place.

>
> Consider memory usage and runtime when tuples are nested, or contain
> large data structures (records, static arrays...).
>

You'll have similar memory usage and runtime problems when you don't use 
tuples...

>>   a := 42;
>>   (a, e) := (a * 2, a); // (a, e) should be (84, 42), not (84, 84)
>
> Such code tends to become cryptic with larger tuples.
> High level (source code) debugging will be impossible :-(
>
>

You can also write cryptic code without tuples. Also why should 
debugging become impossible? It's "just" a matter of adding the correct 
debug information.

> [...]
>> * Possible extensions
>>
>> Note: This section is not completely thought through!
>>
>> An possible extension would be to allow the assignment of tuples to
>> records and/or arrays (and vice versa). [...]
>
> Without references to distinct tuple elements the coder has to provide
> local variables for *all* tuple elements, then decompose the *entire*
> tuple, before access to a single element will be possible. This may be
> accomplished with less source code when a tuple can be assigned to a
> record variable, but then it would be simpler to use records *instead*
> of tuples.

There is always Michael's idea of single element access (which can be 
extended by allowing ranges)...

>
> When a record type is modified, during development, all *compatible*
> tuples and tuple types must be updated accordingly.
>

If you modify code it's likely that you need to modify other parts anyway...

>> * Possible uses
>>
>> - use for group assignments which can make the code more readable
> ... or unreadable (see above).
>
>> - use for multivalues return values which can make the code more
>> readable (instead of using records or out parameters)
>
> This IMO makes sense only when such tuples are passed along many times,
> before references to their elements occur. Otherwise full tuple
> decomposition is required when e.g. only a succ/fail indicator in the
> result tuple has to be examined.
>
>> - use as result value for iterators (this way e.g. key and data of
>> containers can be queried)
>
> This reminds me of SQL "SELECT [fieldlist]", where *specified* record
> fields are copied. But I wonder how confusion can be eliminated in the
> order of the tuple elements. Will (k,v) or (v,k) be the right order for
> key and value? What are the proper types of key and value?

The order of key and value will depend on the corresponding 
implementation. You need to look this up like you need to look up other 
things as well. By implementing builtin enumerators and those of the FCL 
consistently we might be able to provide a guide for other developers...

And the types of key and value depend on what your key and your value 
is. You have the same problem currently as well when you want to find 
out what the value type of an enumerator is.

>
>
>> * Implementation notes
>>
>> Tuples need to pay attention to managed types (strings, interfaces,
>> etc.). Thus an Init RTTI will be required (which needs to be handled
>> by fpc_initalize/fpc_finalize accordingly).
>> It might be worthwhile to add a new node type for tuple
>> constructors/deconstructors (one node type should be sufficient) and
>> handle them in assignment nodes accordingly.
>
> I'd reuse the record type node for that purpose.

You can not reuse a node type that does not exist...

Regards,
Sven



More information about the fpc-devel mailing list