unison icon indicating copy to clipboard operation
unison copied to clipboard

update docs to reflect that unique types are the default

Open ceedubs opened this issue 1 year ago • 9 comments

This may be controversial, but I'm bringing it up because I think that there are lots of good reasons for it, and particularly because it is such a stumbling block for newcomers.

Background

See #2251 and #2352 for background.

In the early days of Unison, types were structural by default and you had to add a unique keyword to make them non-structural. At some point people realized that unique types were almost always what you want, and there was a proposal to instead make unique the default. At the time of #2251 and #2352 the thought was that swapping the default was an abrupt change in behavior that might have negative consequences, so instead a structural keyword was added the default was removed. So for the 2 years since #2352 was merged users have been explicitly specifying structural vs unique when defining a type. I think that this is enough of a transition period to switch the default to switch the default to uniqueand elideunique` in the pretty-printer.

Why I think unique is a good default

Most types should be unique, not structural.

type UserId = UserId Nat and type EpochMillis = EpochMillis Nat are definitely not intended to be treated as the same type, and the same follows for most types that appear in application code.

Structural types arguably have their place (Option, Either, {Abort}, {Stream a}, and {Throw a} come to mind), but I think that the types that are structural in nature tend to come up much more in core libraries like base than in user/app code. That is, end-users (especially newcomers) are more likely to be defining unique types than structural types. And I would anticipate that people who are working on core structural types are likely to be more comfortable with Unison and/or sophisticated type systems.

structural/unique is an obstacle for newcomers

Requiring (and pretty-printing) unique all over the place is an obstacle for newcomers. After seeing hello world in a language, one of the first things that you'll encounter is a data type. If that data type looks like:

unique type User = {
  name : Text,
  age : Year
}

then everything else will be intuitive, but that unique is going to jump out as something that you don't understand and need to learn. It's true that you will still encounter structural when you view Optional, Either, etc, but maybe that comes a little bit later and I think that it's still a win to avoid the non-obvious keyword for 90% of types.

It's too easy to define a structural type that doesn't make sense

I've encountered quite a few structural types that don't really make sense as structural types. #3615 mentions a category or two of these that the compiler doesn't help you identify.

Also it's really common to see newcomer posts in Slack that define structural types with Text/Nat/Float fields which conceptually are unique. I'm not sure why these tend to be structural as opposed to unique, but if I were to speculate, the thought process is something like "I don't know what unique means, but this type isn't special; it just defines the structure of a user struct".

Unique type churn is a resolved issue

I used to define types as structural while I was developing them just to avoid unique type churn. But this problem was resolved a while ago (yesssssss! 🎉), which removes the biggest footgun with unique types.

Reduction in noise

Most of the time you want unique, so why the extra noise of writing or pretty-printing it?

ceedubs avatar Dec 21 '23 20:12 ceedubs

Sgtm

runarorama avatar Dec 21 '23 20:12 runarorama

I almost forgot to mention the most important reason: @alvaroc1 has advocated for this to lower the barrier to his child learning Unison.

ceedubs avatar Dec 21 '23 20:12 ceedubs

Sounds good to me too! It's time.

pchiusano avatar Dec 21 '23 22:12 pchiusano

From the perspective of an end user, I agree with this. I woudln't say I struggled with it, but it was another thing to learn early on with Unison, like in TypeScript deciding between an interface or type, which for historical reasons existed in parallel, but nowadays are almost exactly the same.

If there were an easy, TypeScript-like way to instantiate records, then maybe it might be nice to have an explicit structural/unique decision when someone designs the type, but there isn't, right?

Like, structural and duck typing makes so much sense if you can do something like

type Foo = { id: String, name: String }

and later just

x = { id: "123123", name: "Rizzmaster 4000" }

but having to create records through x = Foo "123123" "Rizzmaster 4000" structural typing sort of loses its utility for me since I'm passing it all through a nominal type system for instantiation. And something like Foo.default |> id "123123" |> name "Rizzmaster 4000" doesn't get one any closer to the utility of record types.

Most types are valuable because they represent some more concrete thing, while structural types seem to be more useful when the shape matters (I suppose that's why it's deemed "structural"!). I.e., things more closely aligned with category theory or other "core operations" like how @ceedubs mentions in the ticket body itself, things in base.

kylegoetz avatar Dec 21 '23 22:12 kylegoetz

Subtasks:

  • [ ] update code
  • [ ] update docs

aryairani avatar Dec 22 '23 18:12 aryairani

Hey! This sounds like something I'd like to do!

Just one detail, do you want to keep the unique keyword (just make it optional) or does it have to go? And does this also apply to abilities?

unorsk avatar Jan 02 '24 10:01 unorsk

@unorsk wonderful thank you! 🎉

do you want to keep the unique keyword (just make it optional) or does it have to go?

My inclination would be to keep it as a keyword. But like you said it would be optional, and the pretty-printer would never use it.

does this also apply to abilities?

Yes.

ceedubs avatar Jan 02 '24 13:01 ceedubs

Merged!

ChrisPenner avatar Jan 09 '24 22:01 ChrisPenner

@ChrisPenner just one thing left – updating the docs. I haven't had time yet to look into that, but from what I understand it's just a couple of pages (starting here) that have to be updated on unison share.

unorsk avatar Jan 10 '24 11:01 unorsk

@rlmark Do you know if this can be considered done?

aryairani avatar May 28 '24 18:05 aryairani