Skip to content

Add this and infer members to tuples #9

@kontheocharis

Description

@kontheocharis

Consider a tuple

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

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.

AsType <bool> ((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<T>, where Foo is a struct with a type parameter, can be used to write generics with trait bounds, where Foo represents a trait.

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

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

vec_iter_iterator := <T> => Iterator <VecIter<T>, 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 := <I where Iterator<I, Node>> => (nodes: I) -> NodeCollection => {
  ...
}


build_ast := () => {
  node_vec := vec()
  // .. build the ast
  
  nodes := collect_nodes(iter(node_vec)) 
  // desugared to: 
  nodes := collect_nodes<(VecIter<Node>, vec_iter_iterator<Node>)>(iter(node_vec))

  pass_to_next_stage(nodes)
}

Metadata

Metadata

Assignees

Labels

languageLanguage specification related issues

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions