Is top-level file scope analogous to class scope?

#1

I’m a long-time Java dev who is learning Kotlin.

Kotlin appears to be making a push for using top-level properties and functions, so I’m trying to get a feel for them. After some frustration, I have an insight that helps me think about top-level scope. I thought I’d share that insight – or at least present it for correction.

It seems that the top level scope is analogous to class scope. That is, I can expect visibility within the file to behave as if the contents of the file were wrapped in its own class.

Am I correct in this thinking? I’m trying to figure out how to think about files and top-level members so that I can properly design for them.

My frustration started with trying to create top-level factory methods for classes that should not be instantiated outside of the file. After all, I was supposed to be using top-level methods instead of static methods in Kotlin, where possible, right? I tried to make the class constructors private or protected and yet use them in the top-level methods. But that doesn’t work. I had to create a companion object for the factory methods instead.

How should I think about file scope in general? Thanks for your help!

~joe

#2

Private top level functions are only accessible from within that file. Public once are accessible everywhere and they are scoped within the package.

package foo.bar
fun test() = TODO()

// different file
foo.bar.test() 

So in that way I don’t think the class analogy fits for public functions perfectly. For private functions it’s spot on.
Also if you look at the generated bytecode, kotlin creates a class for each file putting all top level functions and properties into that class as statics. So looking at it that way you analogy is perfect :wink:

I normally think of top-level functions as if they belong to the package, as that is the scope from which they are accessed in kotlin. That said, I put top level functions normally in the file with the classes they work with or if they are grouped differently (like a collection of maths functions) into their own file.
File scope on the other hand isn’t that important to me. I use it a lot, but since it’s only relevant for private utility functions I don’t really think about it. Same way you don’t think about the scope of any other private function you create just to structure your code.
Also I try to never use private top level properties with backing fields. Well ok, I try to not use any global variables if not 100% necessary, which is quite rare.
As for factories I tend to use companion objects. That is one of the ways they are intended to be used (if I remember correctly).

1 Like
#3

It’s more like if all file-level functions and properties are wrapped in a separate class, while file-level classes aren’t. In fact, they’re visible in Java exactly like that: the class is called FileNameKt. Even if your code is 100% Kotlin, you still use that fact when you specify the main class if your main() is file-level (which it usually is).