Metadata
Title
Tuple Examples
Category
general
UUID
bcb3e593859a4468a5c51a07c2f803a1
Source URL
https://cforall.uwaterloo.ca/features/tuple.shtml
Parent URL
https://cforall.uwaterloo.ca/features/
Crawl Time
2026-03-18T05:15:58+00:00
Rendered Raw Markdown
# Tuple Examples

**Source**: https://cforall.uwaterloo.ca/features/tuple.shtml
**Parent**: https://cforall.uwaterloo.ca/features/

- [Complex Resolution](#ComplexResolve)
- [Go Comparison](#GoCompare)
- [Variadic Tuples](#VariadicTuples)

---

### Complex Resolution

```
[ int, int ] foo1( int );			// overloaded foo functions
[ double ] foo2( int );
void bar( int, double, double );
bar( foo( 3 ), foo( 3 ) );
```

The type resolver only has the tuple return types to resolve the call to bar as the foo
parameters are identical, which involves unifying the possible foo functions with bar's
parameter list. No combination of foos is an exact match with bar's parameters; thus, the
resolver applies C conversions. The minimal cost
is bar(foo1(3),foo2(3)), giving (int,
int, double) to (int,
double, double) with one safe (widening)
conversion from int to double versus (double,
int, int) to (int,
double, double) with one unsafe
(narrowing) conversion from double to int and two safe conversions.

### Go Comparison

Comparison of C∀ and Go tuples.

| C∀ | Go |
| --- | --- |
| ``` #include <fstream.hfa>   [int, int ] f() {     return [3, 7]; } void g( int a, int b ) {     sout | a | b; } int main() {     sout | f();     g( f() );     int a, b, c;     [a, b] = f();     sout | a | b;     c = f().1;     sout | c;     c = f().0;     sout | c;     [10] int w = { a, b };     sout | nlOff;     for ( i; 10 ) sout | w[i];     sout | nlOn;     sout | nl; 	// Go does not have tuple variables     [int, int, int] t = [1, 2, 3];     sout | t;     [a, b] = [t.2, t.0]; // reorder and drop tuple elements     sout | a | b; } ``` | ``` package main import "fmt"  func f() (int, int) {     return 3, 7 } func g( a, b int ) {     fmt.Println( a, b ) } func main() {     fmt.Println( f() )     g( f() )  	a, b := f()     fmt.Println( a, b )     _, c := f()     fmt.Println(c)     c, _ = f()     fmt.Println(c)     w := [10]int{ a, b }   	fmt.Println(w)       } ``` |

### Variadic Tuples

Variadic functions are provides by the new kind of parameter type, ttype (tuple type).
Matching against a ttype parameter consumes all the remaining argument components and packages them into a tuple, binding to the resulting tuple of types.
There is at most one ttype parameter that occurs last, which matches normal variadic semantics, like CC11 variadic templates.
Unlike C variadic functions, it is unnecessary to hard code the number and expected types.

For example, a type-safe variadic print function to replace printf, which also supports user-defined types.
This mechanism is used to print tuples in the C∀ I/O library.

```
forall( T, ttype Params | { void print(T); void print(Params); } ) void print(T arg, Params rest) {
	print(arg);  print(rest); 	// recursive usage
}
void print( int x ) { printf( "%d", x ); }
void print( double x ) { printf( "%g", x ); }
void print( const char * x ) { printf( "%s", x ); }
// all other basic types
struct S { int x, y; };			// user type
void print( S s ) { print( "{ ", s.x, ",", s.y, " }" ); }
int main() {
	print( 5, " ", 3.5, " ", (S){ 1, 2 }, "\n" );
}
```

It is possible to use ttype polymorphism to provide arbitrary argument forwarding functions.
For example, it is possible to write new as a library function.

```
forall( T | sized(T), ttype Params | { void ?{}( T &, Params ); } ) T * new( Params p ) {
	return &(*malloc()){ p };					// run constructor
}
forall( R, S ) struct pair {
	R first;	S second;
}
forall( R, S ) void ?{}( pair(R, S) &, R, S );
pair( int, char ) * x = new( 42, '!' );
```

The new function combinations type-safe malloc with a C∀ constructor call, forcing construction of dynamically allocated objects.
This function provides the type safety of new in C++, without the need to specify the allocated type again, due to return-type inferencing.