RFE: Class implements / extends in front of constructor params

Hi. I suggest to add an alternative place to declare the implemented interfaces and extended classes.
Why?

Because a lot of classes have a long list of properties, which pushes the more important information too below:

class Foo (
val name: String,
val surname: String,

val phone: String?) : Bar, Baz { … }

This has several negatives:

  1. Hardly readable - need to skim to find the line with implements /extends
  2. The default formatter in IDEA puts the information at the same line as last property, making it even less readable
  3. Not too useful when searching for the interface name by text - the line that comes out does not contain the implementing class (or sub) name

Someone might object with the logic that we are kind of writing the constructor that returns the type of the interface, but that’s not true… it’s returning the new class of course.

Simply put: This syntax would be way more readable, searchable and even more concise:

class Foo : Bar, Baz (
val name: String,
val surname: String,

val phone: String?
) { … }

It’s a bit late for such change, but perhaps both could be accepted? Or it could be an optional feature? I think it’s worth the negatives.
Also, I am aware that I can specify constructor explicitly, but that’s on the other hand more verbose for shorter classes (typically, data classes).

Thanks for considering.

1 Like

Also, IMHO, it would be more readable to have the extends and implements keywords.

I am not sure why it replaced it with : anyway. Maybe to make the syntax shorter, but then why the ternary operator would be replaced with if/else? …

I agree on your points, though there’s at least a catch, what happens if your super classes take parameters? Do you pass them before even declaring them?

class Foo: Baz(name[0] + "q") (
   ....
   val name: String,
   ....
)
1 Like

Yes, I see no problem passing the parameter before declared. It is also the case for instance for annotations and constants.

Personally I don’t see the reason for syntax that requires passing parameters before declared, after all instead of:

class PhonablePerson: Person(name)
    constructor(name: String, val phoneNumber: PhoneNumber) { }

the syntax could also look like:

class PhonablePerson: Person
    constructor(name: String, val phoneNumber: PhoneNumber) : super(name) { }

I would argue that the latter is way more readable, but that may come from C# influence.

I would not put this as a question of parsing something “before”. Parsing things before declared is very common. For instance, enum’s constructor is parsed before the enum instances, but those come first. Very commonly, you use a function before it’s declared. Very commonly, companion object is at the end. Etc etc. The order where declarations appear should not be an argument for decisions about how to structure the code; readability should be
.

I agree both with your arguments why this should be different and about the fact that the useabilty of the language should always come before the difficulty of implementing a compiler (within reason).

The one problem with your version is this

class Foo: Bar, Baz () { 
    ...
}

Looking at this code there is no way to tell whether Baz is a super class or an interface and the paranthesis are the parameterless constructor. Sure you can figure it out from the imports but I’d argue that this is still a problem.

1 Like