﻿ Anonymous Struct Types Tutorial
 Cω - Samples

# Anonymous Struct Types Tutorial

This tutorial shows in a simple Cω program how to work with anonymous structs (Cω's tuple types).

#### Sample Files

To run a similar sample, you may use the following project and source files:

• Tuples.cwproj
• main.cw

These files are located in the \samples\Basics\Tuples subdirectory under the path where you installed Cω, which by default is C:\Program Files\Comega.

In Visual Studio, open the Cω project (.cwproj) file and then press F5 to compile and run the sample code.

#### Tutorial

The best way to think about anonymous structs is as implicitly defined C# structs with public fields. Thus the anonymous type `struct{ int x; int y; }` matches with the nominal type `Point` that has the same fields:

`  struct Point{ public int x; public int y; }`

The important correspondence between anonymous and named C# structs is that both have no referential identity. That means that the assignment of ``` q.x = 13``` in the example below has no effect on variable ``` p```

```  Point p = new Point(47,11);
Point q = p;
q.x = 13;```

In XSD terms, an anonymous struct corresponds to a `sequence` particle. The difference is that Cω does not impose complicated constraints on structs as there are in XSD. In particular anonymous structs can have unlabelled and/or duplicated fields. Hence the type ```struct{ int; bool b; struct{ Button b; int; }}``` is perfectly valid in Cω but a matching type cannot be defined using XSD Schema.

Struct members can be accessed by name or by type as we have seen before. In addition, members of an anonymous struct can also be accessed via their relative position.

```  struct{ int; bool b; struct{ Button b; int; }} x = new {47, b=false, new {b=null, 11}};
int a = x[0];
choice{bool; Button;}+ b = x.b;
int+ c = x.int::*;```

For anonymous structs, name and type-based access are just (convenient) sugar for positional access. In the above example `x.b` is a shorthand for the generator expression ```{ yield return x[1]; yield return x[2][0]; }``` that enumerates all fields labeled ``` b``` and `x.int::*` is a shorthand for the generator expression `{yield return x[0]; yield return x[2][1];}` that enumerates all fields of type `int`.

We can forget labels, nesting, and the exact static type (covariance, just like arrays and streams) when converting one anonymous struct to another. This means that we can assign our example struct `x` to another `y` of different type ```struct{ object; bool; object; int }``` where we have dropped the labels, forgotten the nesting, and implicitly converted type `Button` to ``` Control```:

`  struct{int; bool; Control; int } y = x;`

The implicit conversion from `x` to ``` y``` constructs a new struct of the appropriate shape by copying and possibly converting all the fields of `x` when creating ``` y```:

`  y = new{ x[0], x[1], (Control)x[2][0], x[2][1] };`

It is even possible to implicitly convert an anonymous struct to a stream by forgetting labels and the ordering of the fields. For our example, this means that we can convert struct `y` to a stream ``` z``` that contains items of type `int, bool` and ``` Control```:

`  choice{int;bool;Control;}* z = y;`

The implicit conversion from `y` to ``` z``` effectively generates the stream by enumerating all fields of ``` y```:

`  z = {yield return z[0]; yield return z[1]; yield return z[2]; yield return z[3];};`

Just like the rules for lifting member access over streams, we have to be a bit careful when defining the result type of converting anonymous structs to streams. It can happen that a struct itself is not `null`, but that the corresponding stream is empty because all the field in the struct are ``` null```.

```  struct{Button; Button;} bt = new{null, null};
Button* bs = bt; // bs is empty```

Only if we know that at least one of the fields in not null (for example because it is a value type, or a non-empty stream), we can safely assume that the corresponding stream is non-empty.

There is an implicit conversion from a singleton anonymous struct to its raw underlying field type. This avoids introducing a gratuitous stream type that we would then have to cast away.

`string msg = new{Email = "A lonely string"};`

Even though struct and stream types are closely related, there is an important difference between struct values and stream generators. Creating a stream by upcasting a struct is eager, which means that all the fields in the struct are evaluated before the stream is generated. On the other hand generators are lazy, and stream elements are created on demand.

```  int* xs = new{ 1, 2/0 };
int* zs = {yield return 1; yield return 2/0;}; ```

In this example, the first assignment will throw a `DivideByZeroException` exception immediately. The second assignment will succeed, and the exception is only thrown when and if the second element of the stream accessed.

#### Example

The following is a complete Cω program that demonstrates working with anonymous struct types.

```using System;
using System.Windows.Forms;

public class Test {

static void Main() {

struct{ int; bool b; struct { Button b; int;};} x = new{47, b=false, new{b=null, 11}};
int a = x[0];
choice{bool; Button;}+ b = x.b;
int+ c = x.int::*;

struct{ int; bool; struct{ Button; int;};} y = x;

choice{int ; bool ; Button;}* z = y;

struct{ Button; Button;} bt = new{ null, null };
Button* bs = bt; // bs is empty

string msg = new{ Email = "A lonely string" };

// throws immediately
int zero = 0;
try {
int* xs = new { 1, 2/zero };
} catch(DivideByZeroException e){
Console.WriteLine("Division by 0");
}

// prints 1 then throws
int* zs = {yield return 1; yield return 2/zero;};
try {
zs.{ Console.WriteLine("it = {0}",it); };
} catch(DivideByZeroException e){
Console.WriteLine("Division by 0");
}

```Division by 0