Skip to content
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

Design Meeting Notes, 12/8/2021 #47073

Closed
DanielRosenwasser opened this issue Dec 8, 2021 · 12 comments
Closed

Design Meeting Notes, 12/8/2021 #47073

DanielRosenwasser opened this issue Dec 8, 2021 · 12 comments
Labels
Design Notes Notes from our design meetings

Comments

@DanielRosenwasser
Copy link
Member

DanielRosenwasser commented Dec 8, 2021

Casing Operators on string

#47050

// this DOES NOT get uppercased
type A = Uppercase<`a${string}`>;
  • Clearly we should switch that to something at least like `A${string}`.
  • If these operators are going to operate the templates, it feels like there should also be a corresponding representation for Uppercase<string> too.
  • So now we will map over the templates and distribute over type interpolations/holes (e.g. replacing the string with Uppercase<string> in the above example).
  • When we built these intrinsics, we really didn't want the compiler to "deeply" understand them.
  • Now we will have to also have to be able to ask "is this intrinsic operator generic?"
  • Uppercase<Uppercase<T>> simplifies to just Uppercase<T>.
  • Uppercase<Lowercase<T>> does not?
    • These don't round trip.
    • What?
    • German S, Turkish i
    • 😫
  • Conclusion: in favor of this, just need a code review.

Records and Tuples

tc39/proposal-record-tuple#9
https://gist.github.com/rbuckton/bac946eda028cd898e7b09498e6f12e8

  • Getting feedback from type systems on Records/Tuples.

  • Can't use ReadonlyArray to represent tuples.

  • Records and Tuples can only contain primitive values (e.g. string, number, symbol, boolean, etc.).

  • Primitive tuple and primitive record types as constraints like object.

  • Idea would be Record and Tuple prototypes for apparent types.

  • Possibly provide ReadonlyRecord and ReadonlyTuple types.

    • This avoids conflicting with the built-in Record type.
  • Can also create record/tuple syntax.

    type T = #[number, string];
    
    // equivalent to
    
    type T = tuple & {
        readonly 0: number;
        readonly 1: string;
        readonly length: 2;
    };
  • Also a box type. Box is still a name that's being bikeshed-ed. Could imagine box<T> - first primitive that's generic. Could also make a box type operator.

  • Could we use a type alias for Box?

    • Box has a prototype, has primitive semantics.
  • Copying the syntax for creating primitives from array tuples and object literals.

  • Other projects might already use tuple and record, but maybe not a blocker.

  • A key type of records/tuples is that they're deeply immutable; but property access syntax is the same.

    • To support writing code like that, we don't let readonlyness affect assignability today.
    • Do we need to tighten the behavior somehow?
  • More concerns with just that - also the fact that a lot of places don't expect object-like things that are not objects.

  • Trying to decide if this provides enough value for the complexity.

  • How do you explain to users which "types of objects" they should be using?

  • Fair amount of overlap with "blittable" types - feels odd that these types with value semantics are not leveraged that way at all.

    • Explicitly not TypedArrays or blittable types.
  • What's the biggest use-case? Composite keys?

    • Referential transparency.
    • No persistence, right?
      • You already have persistent data structures with object types.
  • Seeing syntax for # in front of objects - why not tagged objects?

  • We'd also need some way to refer to "array-based tuple or immutable tuple".

  • Big concern over cognitive overhead - which do you use, why can't I define my own custom records, etc.

  • A lot of this is nice - makes sense. Some on the team feels like box is actually good.

  • Then complexity with the type system itself is also very high. How do you avoid bifurcating the world?

    • The minute you push strict readonliness, you split the world into mutable/immutable.
    • Nobody says readonliness by default.
  • Also, freshness rules - do properties get the as const semantics? If so, you can't reassign.

    • Use the same mutability binding rules as today - a let means widen the recursive properties, const means don't.
    • Really uninuitive! let/const always signaled just top-level mutability. Now they impact the properties of the value.
  • Also have a community PR from @Jack-Works (feat: support parser of record and tuple #45546).

    • Scope is rather large and a lot of decisions we're still unclear about. We don't want to move too quickly on an implementation, and when the time comes it may be better to iterate on it from within the team.
@DanielRosenwasser DanielRosenwasser added the Design Notes Notes from our design meetings label Dec 8, 2021
@Jack-Works
Copy link
Contributor

Also have a community PR from @Jack-Works (feat: support parser of record and tuple #45546).

Scope is rather large and a lot of decisions we're still unclear about. We don't want to move too quickly on an implementation, and when the time comes it may be better to iterate on it from within the team.

If I only work on the parser & AST part and do not touch the type checking part, is that OK?

@DanielRosenwasser
Copy link
Member Author

I think so! If we end up using those parser changes, we'll be sure to credit your work there.

@MartinJohns
Copy link
Contributor

The minute you push strict readonliness, you split the world into mutable/immutable.

IMO a similar is already the case since strictNullChecks (TypeScript 2.0), with many new projects created today with strictness turned off.

@AlCalzone
Copy link
Contributor

AlCalzone commented Dec 9, 2021

German S

Not sure what is meant by this. If it means the "eszett", that has an uppercase form since 2017, although used very rarely.

Uppercase: ẞ
Lowercase: ß

@weswigham
Copy link
Member

"ß".toUpperCase().toLowerCase()

@treybrisbane
Copy link

@DanielRosenwasser Not sure if this is the best place to ask this, but is there any appetite within the team for adding more of these intrinsic types?

I have a couple ideas for some new ones, but I'm unsure whether I should propose them, as the intended scope of intrinsic types isn't totally clear to me. 😅

@DanielRosenwasser
Copy link
Member Author

DanielRosenwasser commented Dec 14, 2021

Every feature starts at -100 points, but if you can prove out the use-cases or demonstrate genuine demand, we will consider it.

@DanielRosenwasser
Copy link
Member Author

I understand a lot of disappointment can come with the issue getting turned down - but I would hope nobody tries to make you feel bad for suggesting something that falls within our design goals. If you feel like there are worthwhile things to discuss, I would encourage you to file a suggestion!

@DanielRosenwasser
Copy link
Member Author

I'm sorry, @RyanCavanaugh noticed that my comment (#47073 (comment)) should probably be updated given how old the linked post is.

@acutmore
Copy link
Contributor

acutmore commented Jan 5, 2022

Note that Box has since been removed from the R/T proposal: tc39/proposal-record-tuple#277 in favour of pursuing https://github.com/tc39/proposal-symbols-as-weakmap-keys

One open issue with that proposal is if registered-symbols can be used in weak collections (though they won’t be collected) or if they should throw.
tc39/proposal-symbols-as-weakmap-keys#21

If registered symbols throw I’m not sure if TypeScript would want to statically track this or not - similar to how empty arrays are not tracked for detecting empty.reduce(f).

@Jack-Works
Copy link
Contributor

If registered symbols throw I’m not sure if TypeScript would want to statically track this or not

Of course not

@hax
Copy link

hax commented Jan 14, 2022

I think TS could statically track registered symbols (just like unique symbol subtype), registered symbols already behave differently, their identity are based on strings so Symbol.for(stringLiteral) would be easily be tracked by utilizing current string literal type.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Design Notes Notes from our design meetings
Projects
None yet
Development

No branches or pull requests

8 participants