Yup, I noticed that Kotlin has internal as the default modifier :)
So I think internal as the default is a bad idea. Looking at how the default of ‘package private’ for methods and fields has worked out in Java, I believe it has not worked out very well. Firstly ‘internal’ to the compilation unit is somewhat of a confusing concept for methods. Remember that the scope of a method is already limited by the scope of the class it is in. If the class is hidden, the public methods are also hidden. Thus the meaning of package private (or ‘internal’) for a method or property is really:
Even if you can see this class, then you can’t call this method, unless you happen to be in the same package/module as this class.
This is a very strange and unusual set of access requirements and is very rarely what people intended. Indeed because package private is so rarely used in Java, people in my workplace generally feel the need to specifically annotate it’s use. That is, on the rare occasion someone actually does want a package-private method they normally end up doing this:
/* package */ void myPackagePrivateMethod() { …
In other words, because the default of package private is confusing and unusual, people want to annotate their code with a keyword when they actually want to use it. To my mind this is a clear indication that the default is wrong.
I take your point on public APIs but in my opinion there are two possible solutions to this:
- Make classes be ‘module internal’ by default, but methods and properties be public by default. That way something is not going to be a part of their API unless the user specifically annotates their class to say that it should.
- Make the default be private by default for methods, properties and classes.
Personally I don’t think public by default is a big problem. While it is true that in theory someone might accidentally make a method a part of their public API, I’ve not seen that be a problem in practice in Scala code (which is public by default). I have also seen people make things public in Java when they didn’t mean to. Ultimately people need to think about what is public and what is private, having a default of internal doesn’t automatically solve this issue.
Your point is taken on having private as the default, private as default would force people working in small codebases to write access modifiers. But this might be a good idea anyway. Indeed, another of my concerns with internal as default is that it creates a strong distinction between a project that is a single module (leave off all the access modifiers) and a larger multi-module project (you need to have public access modifiers). Kotlins modules are pretty large units, many interesting programs may start life as a single module and later become multi-module … at which point you need to go back and add modifiers to every public method in every public class. It’s also really bad for training: that what you should do in the small is not the same as what you should do in the large.
The same training issue exists in Java as well with it’s package-privae, and as a result Java training religously teaches people to always put in their access modifiers, whatever the size of their code. I suspect a similar thing would happen for Kotlin as well, entirely negating the argument that private-as-default is bad for coding in the small.
So whilst I can see some arguments for a default of ‘internal’, I think it all comes at quite a high cost in my opinion. You end up having to put lots of ‘public’ and ‘private’ modifiers throughout your code, coding in the large is different from coding in the small, and worse still you end up with a default that is a very unusual case, so much so that when people actually do want that in Java they feel the need to annotate their intention …