Why parentheses after nullary gradual types?

Hi!

I’m excited about everything that’s going on re. gradual typing and am really pleased to see that Jose and the team seem to be thinking everything through extremely well.

I realise that it’s still all WIP and the $ syntax may never even make it in but I have one small thing that’s half question, half suggestion that I thought I’d raise…

All the literature I’ve seen up till now has parentheses after all the types, e.g.
binary(), integer(), float(), MyStruct.t(), etc.

Why is this?

I realise some types may have arguments, e.g. dynamic({:ok, term}), (would list(integer) be a thing?), but for the ones that don’t, would there be any harm of having the convention to leave out the parentheses?

I know it’s a small thing but personally I would find seeing code like

$ %{ user: User.t, age: integer } -> result

SO much easier to mentally parse than

$ %{ user: User.t(), age: integer() } -> result()

especially when there are other parentheses involved and as the statement gets more complex.

I don’t see why there would be any ambiguity because in the context of a $ statement I assume there are no variables as such?

I’m sure there’ll be a good reason but interested to know - thanks!

7 Likes

The one benefit that I can think of for always using parentheses after type names (other than just consistency) is that it makes it easy to distinguish between types and type variables.

2 Likes

Yes that’s a good point.
I’d hope that it would still be obvious what’s a type and what’s a type variable but it may not always be the case.
I guess it’s debatable which is more important out of consistency and readability and that may depend a lot on how complex the typical typespec is.

Typescript (which is also in some ways set-theoretic) doesn’t bother distinguishing between types and type variables, e.g.

type Blah = { /* */ }

type Blah<Var> = { /* */ }

though I’ve often seen/used the convention that type variables begin with a T, i.e.

type Blah<TVar> = { /* */ }

I like the suggestion to omit parens. I think most types in other languages don’t have parens unless they are parametrized.

It’s easier to read and write and we want the friction for writing types to be as low as possible :slight_smile:

Plus there is already precedent in the Elixir language: macros that allow omitting parens to reduce noise.

1 Like