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

Primary constructor type parameter syntax #3172

Open
munificent opened this issue Jun 28, 2023 · 8 comments
Open

Primary constructor type parameter syntax #3172

munificent opened this issue Jun 28, 2023 · 8 comments
Labels
brevity A feature whose purpose is to enable concise syntax, typically expressible already in a longer form primary-constructors

Comments

@munificent
Copy link
Member

The proposed syntax for a generic class with a named primary constructor (#3023) is:

class D.named<T>(int x);

It feels to me like it should be:

class D<T>.named(int x);

The type parameters are a property of the class itself, not the constructor. The syntax for invoking a named constructor on a generic class is:

D<String>.named(123)

Also, if we ever want to support generic constructors, we may find ourselves wanting to allow:

class D<ClassTypeParam>.named<CtorTypeParam>(int x);
@lrhn
Copy link
Member

lrhn commented Jun 28, 2023

It should be class D<T>.named(int x);!

@Cat-sushi
Copy link

I feel current specification reasonable. because,

  • In case of class D(int x);, D is the name of constructor, but not that of the class.
  • In case of class D.named(int x);, D is a part of the name of the constructor, as well.
  • Type parameters of functions should be just after the name, but not in the middle of the parts of that.
  • Constructors doesn't have type parameters separated from those of the class.
  • Unnamed primary constructor couldn't have type parameters separated from those of the class, anyway.

@munificent
Copy link
Member Author

  • In case of class D(int x);, D is the name of constructor, but not that of the class.

It's the name of the class, at least according to how the spec reasons about this. The constructor doesn't have a name in this case. (If it were the name of the constructor, then D would be a constructor tear-off, but it isn't. It's a type literal for the class D.)

  • Type parameters of functions should be just after the name, but not in the middle of the parts of that.

But the type parameters are not on the function, they are on the class.

  • Constructors doesn't have type parameters separated from those of the class.

Not currently, but this a long-running feature request: #647.

  • Unnamed primary constructor couldn't have type parameters separated from those of the class, anyway.

They can. We anticipated that when adding constructor tear-offs by letting you write .new for the unnamed constructor. So if you wanted to have a generic unnamed constructor, you could define it like:

class C {
  C.new<T>() { ... }
}

@eernstg
Copy link
Member

eernstg commented Jun 29, 2023

This was a dilemma.

As proposed, the constructor name is shown (so it's readable and searchable). If the class is generic then the type parameter list needs to go somewhere, and I put it after the complete constructor name. Of course, this conflicts with the constructor invocation syntax, but it is arguably similar to the current constructor declaration syntax (for those, there is no type parameter list, so we never have anything between the class name and the other half of the name of a named constructor).

We could also simply make it a syntax error to have both a type parameter list and a named primary constructor at the same time.

This means that the primary constructor will also have to be the "nameless" one in a generic class. In return, we won't ever have this funny configuration where the constructor name has a (perhaps long) type parameter list in the middle.

Another possibility is to say that the type parameter list goes in the same position as in the constructor invocations, and we don't care that a constructor named C.name is shown as C<Lots, Of, Stuff>.name in the declaration.

I don't have a strong opinion here.

@munificent
Copy link
Member Author

Another possibility is to say that the type parameter list goes in the same position as in the constructor invocations, and we don't care that a constructor named C.name is shown as C<Lots, Of, Stuff>.name in the declaration.

This is what I prefer, definitely. Users are always apparently entirely comfortable reading code like List<SomeLongType>.filled(value), so I don't think there's anything wrong with the class declaration syntax being similar.

@Cat-sushi
Copy link

Ok, now I agree with @munificent ,

@lrhn
Copy link
Member

lrhn commented Jun 29, 2023

I'm strongly for Name<TypeArgs>.identifier(args), and strongly against Name.identifier<TypeArgs>(args).

There are pragmatic reasons too, like being prepared for generic constructors, but mainly the latter just looks like a mistake.
It doesn't match anything in the language, except the time we mistakenly allowed you to write List.filled<int>(...) as well as List<int>.filled(...). That was a parser bug, and we fixed it.

NUXI

@eernstg
Copy link
Member

eernstg commented Jun 30, 2023

Cool, let's do Name<TypeArgs>.identifier(args)!

@eernstg eernstg added the brevity A feature whose purpose is to enable concise syntax, typically expressible already in a longer form label Oct 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
brevity A feature whose purpose is to enable concise syntax, typically expressible already in a longer form primary-constructors
Projects
None yet
Development

No branches or pull requests

4 participants