-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Named tuples second implementation #19174
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
9d1f20d
2395ece
64a79c9
cb95265
6ae8252
1f79b87
b9899b7
27d6288
5dd48f9
bd9bb8a
e0a11cd
b9d86fe
0fbdb49
6f53dcd
b44f15d
02aa578
b7115e7
5c9bb5f
4758830
18f600d
5513ed6
fb1541a
cf09b19
4baa509
702dcd5
1e31d16
22e6c89
d0888f6
69964b0
a3409e0
111674c
1fd5962
c0b792f
611861b
640da16
67c0af2
2cd5d7e
d8b7595
e0eb247
4279a58
c0bd1e4
b997f3d
2206d88
ca19f1a
984fe62
21bcfef
92d22c9
1613ee1
a04d3a7
37b1bd2
3f8f6c6
9627c08
8a4162f
0ab9e7b
075b7d1
c58c8c2
57b17ac
f427ec9
94b7c1f
5df2120
40c6138
03509b8
9047ac3
579e14a
8d6fa37
1e29c4f
0c89c92
f80a8dd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
package scala | ||
import annotation.experimental | ||
import compiletime.ops.boolean.* | ||
|
||
@experimental | ||
object NamedTuple: | ||
|
||
opaque type AnyNamedTuple = Any | ||
odersky marked this conversation as resolved.
Show resolved
Hide resolved
|
||
opaque type NamedTuple[N <: Tuple, V <: Tuple] >: V <: AnyNamedTuple = V | ||
|
||
def apply[N <: Tuple, V <: Tuple](x: V) = x | ||
odersky marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
def unapply[N <: Tuple, V <: Tuple](x: NamedTuple[N, V]): Some[V] = Some(x) | ||
|
||
extension [V <: Tuple](x: V) | ||
inline def withNames[N <: Tuple]: NamedTuple[N, V] = x | ||
|
||
extension [N <: Tuple, V <: Tuple](x: NamedTuple[N, V]) | ||
|
||
inline def values: V = x | ||
|
||
inline def size: Tuple.Size[V] = values.size | ||
|
||
// This intentionally works for empty named tuples as well. I think NnEmptyTuple is a dead end | ||
odersky marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// and should be reverted, justy like NonEmptyList is also appealing at first, but a bad idea | ||
odersky marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// in the end. | ||
inline def apply(n: Int): Tuple.Elem[V, n.type] = | ||
inline values match | ||
case tup: NonEmptyTuple => tup(n).asInstanceOf[Tuple.Elem[V, n.type]] | ||
case tup => tup.productElement(n).asInstanceOf[Tuple.Elem[V, n.type]] | ||
|
||
inline def head: Tuple.Elem[V, 0] = apply(0) | ||
inline def tail: Tuple.Drop[V, 1] = values.drop(1) | ||
|
||
inline def last: Tuple.Last[V] = apply(size - 1).asInstanceOf[Tuple.Last[V]] | ||
inline def init: Tuple.Init[V] = values.take(size - 1).asInstanceOf[Tuple.Init[V]] | ||
|
||
inline def take(n: Int): NamedTuple[Tuple.Take[N, n.type], Tuple.Take[V, n.type]] = | ||
values.take(n) | ||
|
||
inline def drop(n: Int): NamedTuple[Tuple.Drop[N, n.type], Tuple.Drop[V, n.type]] = | ||
values.drop(n) | ||
|
||
inline def splitAt(n: Int): NamedTuple[Tuple.Split[N, n.type], Tuple.Split[V, n.type]] = | ||
values.splitAt(n) | ||
|
||
inline def ++ [N2 <: Tuple, V2 <: Tuple](that: NamedTuple[N2, V2])(using Tuple.Disjoint[N, N2] =:= true) | ||
: NamedTuple[Tuple.Concat[N, N2], Tuple.Concat[V, V2]] | ||
= values ++ that.values | ||
|
||
// inline def :* [L] (x: L): NamedTuple[Append[N, ???], Append[V, L] = ??? | ||
// inline def *: [H] (x: H): NamedTuple[??? *: N], H *: V] = ??? | ||
|
||
inline def map[F[_]](f: [t] => t => F[t]): NamedTuple[N, Tuple.Map[V, F]] = | ||
values.map(f).asInstanceOf[NamedTuple[N, Tuple.Map[V, F]]] | ||
|
||
inline def reverse: NamedTuple[Tuple.Reverse[N], Tuple.Reverse[V]] = | ||
values.reverse | ||
|
||
inline def zip[V2 <: Tuple](that: NamedTuple[N, V2]): NamedTuple[N, Tuple.Zip[V, V2]] = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. interesting point, do we care to always sugar the type in printing? here is the output from zipping two unrelated tuples: scala> (x = 3).zip((y = 4))
-- [E007] Type Mismatch Error: -------------------------------------------------
1 |(x = 3).zip((y = 4))
| ^^^^^^^
| Found: (y : Int)
| Required: NamedTuple.NamedTuple[Tuple1[("x" : String)], Tuple]
|
| longer explanation available when compiling with `-explain`
1 error found There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. how should this render anyway? e.g. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point, maybe make a separate issue? For now I think giving the full type is fine, since the encoding is fixed and publicly known. |
||
values.zip(that.values) | ||
|
||
inline def toList: List[Tuple.Union[V]] = values.toList.asInstanceOf[List[Tuple.Union[V]]] | ||
inline def toArray: Array[Object] = values.toArray | ||
inline def toIArray: IArray[Object] = values.toIArray | ||
|
||
end extension | ||
|
||
/** The names of the named tuple type `NT` */ | ||
type Names[NT <: AnyNamedTuple] <: Tuple = NT match | ||
case NamedTuple[n, _] => n | ||
|
||
/** The value types of the named tuple type `NT` */ | ||
type DropNames[NT <: AnyNamedTuple] <: Tuple = NT match | ||
case NamedTuple[_, x] => x | ||
|
||
type Size[X <: AnyNamedTuple] = Tuple.Size[DropNames[X]] | ||
|
||
type Elem[X <: AnyNamedTuple, N <: Int] = Tuple.Elem[DropNames[X], N] | ||
|
||
type Head[X <: AnyNamedTuple] = Elem[X, 0] | ||
|
||
type Last[X <: AnyNamedTuple] = Tuple.Last[DropNames[X]] | ||
|
||
type Init[X <: AnyNamedTuple] = | ||
NamedTuple[Tuple.Init[Names[X]], Tuple.Init[DropNames[X]]] | ||
|
||
type Tail[X <: AnyNamedTuple] = Drop[X, 1] | ||
|
||
type Take[X <: AnyNamedTuple, N <: Int] = | ||
NamedTuple[Tuple.Take[Names[X], N], Tuple.Take[DropNames[X], N]] | ||
|
||
type Drop[X <: AnyNamedTuple, N <: Int] = | ||
NamedTuple[Tuple.Drop[Names[X], N], Tuple.Drop[DropNames[X], N]] | ||
|
||
type Split[X <: AnyNamedTuple, N <: Int] = (Take[X, N], Drop[X, N]) | ||
|
||
type Concat[X <: AnyNamedTuple, Y <: AnyNamedTuple] = | ||
NamedTuple[Tuple.Concat[Names[X], Names[Y]], Tuple.Concat[DropNames[X], DropNames[Y]]] | ||
|
||
type Map[X <: AnyNamedTuple, F[_ <: Tuple.Union[DropNames[X]]]] = | ||
NamedTuple[Names[X], Tuple.Map[DropNames[X], F]] | ||
|
||
type Reverse[X <: AnyNamedTuple] = | ||
NamedTuple[Tuple.Reverse[Names[X]], Tuple.Reverse[DropNames[X]]] | ||
|
||
type Zip[X <: AnyNamedTuple, Y <: AnyNamedTuple] = | ||
Tuple.Conforms[Names[X], Names[Y]] match | ||
case true => | ||
NamedTuple[Names[X], Tuple.Zip[DropNames[X], DropNames[Y]]] | ||
|
||
end NamedTuple |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this separate definition is needed because
NamedTuple[?, ?]
is illegal, but this definition is very limiting compared to what can be done with a regularTuple
:None of these work on
x: AnyNamedTuple
because no extension methods are defined on it.I can't think of a better way to enable this than writing something like:
and hope that the more precise extension is picked when it is usable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If NamedTuple was covariant in both of its arguments we could maybe write:
But this breaks the reduction of all match types defined in NamedTuple.scala and upper-bounded by AnyNamedTuple for some reason.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you try
AnyNamedTuple = Tuple
? I think I tried that before and it did not work.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That doesn't seem to help, somehow all the variants I tried break reduction:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm. It works for me.