ceylon/ceylon-spec — Issue #120: Record Types
Author: RossTate
Created: 2011-12-24 01:53:06+00:00
State: open

In the discussion for Tuples (#81), @luxspes brought up the issue of record types, a variant of tuples which are particularly important to databases and relational algebra.

One database given was:

```
RELATION {
TUPLE {SourceUserName 'Joseph', TargetUserName 'Peter', RelationshipName 'Friend'},
TUPLE {SourceUserName 'Jane', TargetUserName 'Alfred', RelationshipName 'Enemy'}
} where SourceUserName = 'Joseph'
```

resulting in `RELATION { TUPLE {SourceUserName 'Joseph', TargetUserName 'Peter', RelationshipName 'Friend'} }`.

If we use the syntax `{SourceUserName:String,TargetUserName:String,RelationshipName:String}` to denote a record type in Ceylon, and the syntax `{SourceUserName="Joseph", TargetUserName="Peter", RelationshipName="Friend"}` to denote a record instance in Ceylon, then we can encode that example using comprehensions (#82):

```
value rel
= {for rec in {{SourceUserName="Joseph", TargetUserName="Peter", RelationshipName="Friend"},
{SourceUserName="Jane", TargetUserName="Alfred", RelationshipName="Enemy"}}
if rec.SourceUserName == "Joseph"
rec};
```

and `rel` would have inferred type `{SourceUserName:String,TargetUserName:String,RelationshipName:String}*` and essentially have value `{{SourceUserName="Joseph", TargetUserName="Peter", RelationshipName="Friend"}}`.

Another example was, rather than

```
SELECT DISTINCT a as X,c,d,e,f,g,h,i, g+h as z from someTable
```

where you have to list all the fields you're not even messing with, we should be able to do

```
someTable RENAME (a AS X) REMOVE (b) ADD (g+h z)
```

So, if we extend the syntax for records with

* `rec.+field=value` to take a record `rec` and make a new record with extra field `field` with value `value`
* `rec.-field` to take a record `rec` and make a new record that's the same except without field `field`

then we can do this in Ceylon with the following:

```
{for row in someTable (row.+X=row.a).-a.-b.+z=row.g+row.h}
```

The syntax is a bit wordier than the database example, but that's because the database example is extremely context sensitive with a lot of implicit capturing. For example, if there were some previously defined variable g, then it's not clear whether the g+h expression should reference the previously defined g or the column g.

These thoughts open up a number of issues:

1. Do we want record types?
2. How should subtyping for record types work?
3. How should polymorphism (generics) for record types work?
4. How do we handle database joins?
5. How do we optimize comprehensions into database queries?