hash-org / hash-org/spec

Add `this` and `infer` members to tuples

Open
#9 9 comments 0 reactions 1 assignee Claimed by @kontheocharis View on GitHub
language
Dominant language
Python
Stars
1
Forks
0
PR merge metrics
No merged PRs in 30d

Description

Consider a tuple
```rs
bing : (foo: str, bar: i32)
```
Even though it contains a `str`, `bing` cannot be used as one without `.foo`.
However, it is sometimes desirable to allow a tuple to be used as one of its members, without having to add the explicit access.
This could be done with the addition of a new parameter modifier `this`. Initially this could be implemented as an attribute `#this` on parameters. When `this` is present on a parameter list `q : (this X, ...Y)`, it means that `q` can be used in place of something expecting `X`.

Additionally, a second modifier `infer` could be added which infers the requested parameter from context (or at least attempting to) when the tuple is created. Similarly this can be also done through an attribute `#infer`. In some ways, `infer` is the inverse of `this`: `this` is relevant for tuple destruction (on field access, ignoring the other fields), while `infer` is relevant for tuple construction (inferring the other fields). It is useful when you have a `x: X` and need to fulfil the type `(this X, infer Y)`: instead of providing `(x, get_y_somehow())` you could provide `x` and expect that due to the presence of `infer`, `get_y_somehow()` will be inferred. Of course, the inference is a best-effort, and if it fails the compiler will request the parameter to be added manually.

Why is any of this needed or useful? See the use cases below.

## Use cases

### Struct inheritance

```rs
Animal := struct (age: Age)

Cat := struct (this Animal, meow: Sound) // could also write (this animal: Animal, ..)
c := Cat(..)
c.meow : Sound
c.age : Age

alloc_animal := (a: Animal) => {..}

// Both valid
alloc_animal(c)
alloc_animal(c.0)
```

### Constraints

Consider an extension of the syntax where `P where Q` means `(this P, infer Q)`. This can be used to write constraints, with `Q` being inferred from context if possible.

```rs
AsType ((b) => type b ~ true)

arcsin : (x: f32) where { x in -1..1 } -> (r: f32) where { r in (-PI/2)..(PI/2) }
= (x) => { ... }

bing := (x: f32) => {
if x in -1..1 {
// implicitly exists: _p: {x in -1..1}

print(arcsin(x)) // desugared/inferred to print(arcsin((x, _p)))
}
}
```

### Traits

The expression `(T: Type) where Foo`, where `Foo` is a struct with a type parameter, can be used to write generics with trait bounds, where `Foo` represents a trait.

```rs

Iterator := struct (
next: &mut I -> Option
)

VecIter := struct (
data: &mut Vec,
current_index: usize
)

vec_iter_iterator := => Iterator , T> (
next = (v) => {
if v.current_index == len(v.data) {
None
} else {
result := v.data[v.current_index];
v.current_index += 1;
Some(result)
}
}
)

collect_nodes := > => (nodes: I) -> NodeCollection => {
...
}

build_ast := () => {
node_vec := vec()
// .. build the ast

nodes := collect_nodes(iter(node_vec))
// desugared to:
nodes := collect_nodes<(VecIter, vec_iter_iterator)>(iter(node_vec))

pass_to_next_stage(nodes)
}
```

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.