Skip to content

Conversation

johnyob
Copy link

@johnyob johnyob commented Sep 26, 2025

Rendered version

TL;DR: Adds labeled and (0-indexed) unlabeled tuple projections:

# let x = (~tuple:42, ~proj:1337, "is", 'c', 00, 1);;
val x : (tuple: int * proj:int * string * char * int * int) = 
  (~tuple:42, ~proj:1337, "is", 'c', 0, 1)
# x.tuple;; 
- : int = 42
# x.3;;
- : char = 'c'

let y = x.tuple_label_a in
ignore (x : (tuple_label_a:int * string * bool));
(y, x.2)
Error: The value `x` has type `foo` but an expression was expected of type
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean discombulating_record instead of foo ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in latest version

Unlabeled tuple projections can naturally (and efficiently) be typed using row polymorphism, in
the same way object fields are typed today:
```ocaml
# let snd x = x.2;;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we might want to have the same semantic as with

let get_y t =
  let ~y, .. = t in
  y

which is rejected if I remember correctly.

We would also need to check that the back-end supports such polymorphism (I remember talking about a usefull feature similar to this one for modules with @lthls)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is rejected currently since the expected type of the pattern (i.e. the type of t) is not known

Check to see whether the expected type is known (principally known, if in `-principal` mode).
Then:
* If the type is not known: raise an error stating that the projection is ambiguous.
* If the type is known to be `(?l0:ty0 * ... * tyj * ... * ?ln:tyn)`: type the projection as `tyj`
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens in the case :

let x = ~a:1, ~b:2 in x.1

Is the example rejected because only x.a and x.b are accepted and not x.0/x.1 ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be rejected, as you correctly surmise, the only well-typed projections for x would be x.a, x.b.

This is consistent with the current pattern matching semantics i.e. the following is ill-typed:

# let x = ~a:1, ~b:2 in 
  let _, x1 = x in 
  x1;;
Error: The value x has type a:int * b:int
       but an expression was expected of type 'a * 'b
       The first tuple element is labeled a,
       but an unlabeled element was expected

@samsa1
Copy link

samsa1 commented Sep 30, 2025

As a whole I'm strongly in favor of this feature because I consider that it would increase the quality of life when handling tuples.

I also find the part about row-polymorphic tuples to be extremely interesting as it actually increases the expressiveness of OCaml's polymorphism. However I suspect this would require tweaking a few things in the back-end but hopefully not much.

@johnyob johnyob force-pushed the tuple-projections branch from 68585b9 to 0443ca7 Compare October 6, 2025 09:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants