Tuples are like Lambdas - yes really!
But not in the way one might think. They are not semantically like lambdas but they are the same when one is answering the question "why bother?". It is far too easy to keep adding features to a language. I strongly believe in keeping languages simple. OK, I accept that, paradoxically, I like C++; but then I am human and so inconsistent. Coming back to the question, the answer for both tuples and lambdas is locality.
Lambdas can be replaced by functions or objects; tuples can be replaced by structures, lists or objects. However, their replacements require dispersing the meaning of the code. A lambda is defined exactly where is it used. A tuple has similar locality; it is defined and used at the same place. At least, an implementation of tuples which does not have this feature is pretty much pointless! As a result, code which uses tuples can be much easier read and a lot easier to maintain.
Tuple/List Duality
Even old languages like COBOL and C have a way of creating arrays on the fly. For them arrays are a fundamental type rather than lists. The difference between the two has eroded over the years however. Many languages will process lists and arrays in similar ways and many more simply do not bother with arrays and only have lists.
For an example of arrays on the fly there is the {} syntax in C, C++, Java etc.
int z[]={1,2,3,4,5,6};
However, this is not that useful for passing the stuff around, especially for return types:
int *z=myFunction();
printf("Length %d Width %d \r\n",z[0],z[1]);
This code works because I know, via comments or convention, that the function returns an array the first element of which is the length and the second the width. However, the code is doing nothing to help document its self; I know from personal experience that code like this is prone to errors on writing and more so on maintenance.
We could define a struct for Width and Length, but then that definition is not local to the code using it and produces a lot of boilerplate code to maintane. What we want is something like:
int (length,width)=myFunction();
I could follow this line of thought for a long time - I have here. I am now going to start to think a bit more about dynamic languages and the duality of lists and tuples in them.
Moving This To Dynamic Languages
Crossing the great divide (or just the Thames in this case)
to dynamic languages - Copyright Dr Alexander J Turner all rights reserved
OK - if you have read my blog before you might have noticed that I am not always a big fan of dynamic languages. However, for specific purposes, especially as DSLs, I think they are just the ticket. They are quick to work with and easy to use for development. It is their very flexibility which causes all the trouble when they are used for large project general purpose development. So, it is in this light that I continue the discussion of tuples.
Dynamic languages do not need to worry about compile time type resolution. Great! This makes the mapping of lists to tuples very much easier. I realised from working with Magik that one does not really need a separate tuple type at all to get the benefits of tuples; they can be syntactic sugar around lists (or vectors as Magik calls them). In Magik there is the _scatter key word which takes a list and maps the elements in order into variables in parenthesis. This looks just like a tuple - but is actually just list processing.
So, I took this idea and simplified it right down to work in SFPL. SFPL, Sonic Field Patch Layout, is derived from my experimental/research language VSPL or Very Simple Programming Language. Actually, I think SFPL is simpler now due to the aggressive simplifications I have performed on it. But, back to tuples. Does this look like a tuple?
(1,2,3)
Well - it does, but in SFPL it is also a list generator. The parenthesis here look like they enclose the tokens to humans but to the parser and runtime then are just tokens and operators them selves. The above breaks down to this:
- C -> Create a new accumulator list and push it onto the accumulator stack
- 1 -> Forward the number 1
- , -> Add what ever is forward to the accumulator
- 2 -> Forward the number 2
- , -> Add what ever is forward to the accumulator
- 1 -> Forward the number 3
- , -> Add what ever is forward to the accumulator
- ) -> Pop the accumulator stack and forward the popped list
This list processing it key to just about everything in SFPL:
(1000,440)SinWave
The above passes a list of two numbers into the sin wave generator for example. How can we make these lists work like tuples without having to add new syntax to the SPFL? Well, I did not quite manage. SFPL has some special syntax for handling the storage and retrieval of values, which mimics the way variables work in more complex languages:
- !xyz -> store the forwarded value under the name xyz and forward what was forwarded to this operator
- ?xyz -> retrieve the forwarded value which is stored under the name xyz
- >xyz -> same as ?xyz but erase the storage cell afterwards
Working with tuple like semantics requires the addition of only one new special syntactical feature:
- ^xyz -> store the first element of the passed list under the name xyz and forward the rest of the list.
This means that:
(1,2,3,4) ^a ^b ^c ^d
Will place the values 1,2,3,4 in a,b,c,d storage cells respectively. This addition was required to make granular synthesis easy to work with. Here sound signals and their timing information need to be passed around and processed together; tuple handling makes this much easier. However, the approach is great for all sorts of things from passing arguments to processing complex structures.