skip to content

Semicolons, Idioms & File-Level Visibility

Semicolons are inferred from line breaks, trailing commas are allowed, and top-level declarations are public by default with internal and private as the alternatives. The point interviewers probe is that internal means module-wide and Kotlin has no package-private equivalent.

part ofKotlinoverview, primer and where to startread it →
on this pageshow

questions

6

What is the default visibility of a top-level declaration in Kotlin, and how does that compare to Java?

level: juniorimportance: must knowfreq 60%

answer

  1. Kotlin default = public
  2. Java default = package-private
  3. Kotlin has NO package-private
  4. Four modifiers: public/internal/protected/private
  5. internal ~ closest to package-private but module-wide

basics

~10 s

By default everything in Kotlin is public — visible everywhere. In Java, members with no modifier are package-private (visible only in the same package). Kotlin has no package-private at all.

solid answer

~30 s

Kotlin's default visibility is `public`: a top-level function, class, or property with no modifier is visible from any module that depends on the file. This contrasts with Java, where omitting a modifier gives **package-private** (default) access, visible only within the same package. Kotlin deliberately drops package-private; its four modifiers are `public`, `internal`, `protected`, and `private`. For top-level declarations only `public`, `internal`, and `private` apply (`protected` is for class members). So the Java habit of relying on "no modifier = package scope" doesn't translate — you must use `internal` (module scope) or `private` (file scope) to restrict a top-level declaration.

go deeper

for a junior

States that the default is public and that Java's default differs (package-private).

for a middle

Lists all four modifiers and notes Kotlin removed package-private, with internal as the rough analog.

for a senior

Explains the module boundary of internal vs Java's package boundary and the API-surface implications of a public default.

for a principal

Discusses library API governance: explicit-API mode, binary compatibility, and why a public default pushes responsibility onto authors to seal internals.

## Default is public In Kotlin, if you write no visibility modifier, the declaration is **`public`** — accessible from anywhere it can be imported, including other modules. This applies to top-level functions, classes, objects, and properties as well as class members. ```kotlin fun greet() = "hi" // public by default class Service // public by default val VERSION = "1.0" // public by default ``` ## Java contrast Java has **four** access levels: `public`, `protected`, *default (package-private)*, and `private`. The **default** (no keyword) is package-private: visible only inside the same package. Kotlin's default is the opposite end of the spectrum — `public`. ## No package-private in Kotlin Kotlin **removed package-private entirely**. Packages in Kotlin are organizational namespaces, not an access-control boundary. The four Kotlin modifiers are: - `public` (default) — everywhere - `internal` — same **module** (compilation unit) - `protected` — declaring class + subclasses (class members only) - `private` — top-level: same **file**; member: same class `internal` is Kotlin's nearest replacement for Java's package-private, but its boundary is a **module**, not a package, and it's coarser/broader. ## Why this matters in practice A Java developer porting code may expect "no modifier = hidden from other packages." In Kotlin the same declaration is fully public API. To hide it you must explicitly add `internal` or `private`. ```kotlin internal fun helper() {} // visible only inside this module private fun secret() {} // visible only inside this file ``` ## Library design note Because the default is `public`, library authors must be deliberate about what they expose — every unmarked declaration is part of the public API surface and subject to binary/source compatibility concerns.

  • What's the closest Kotlin equivalent to Java's package-private, and why isn't it exact?
    `internal` — but it scopes to the whole module, not a single package, so it's broader. There's no per-package access control in Kotlin.
  • Why might a public-by-default language be risky for library authors?
    Every unmarked declaration is exposed API; you can accidentally publish implementation details and then owe backward compatibility on them. Authors must mark internals explicitly.

Java's no-keyword is a 'staff only' door (your package); Kotlin's no-keyword is a wide-open front door (public).

saying these in an interview costs you the question

  • Saying the default is package-private (that's Java)
  • Claiming Kotlin has a package-private level
  • Thinking the default is `internal`
  • Confusing module scope with package scope for `internal`
  • Assuming Java access habits transfer unchanged

context

open as a page

Are semicolons required in Kotlin? When, if ever, do you actually need one?

level: juniorimportance: must knowfreq 55%

basics

~20 s

No. Kotlin ends statements at line breaks, so you almost never write a semicolon. You only need one to put two statements on the same line, like val a = 1; val b = 2.

open as a page

Compare `internal` and `private` for top-level declarations. What exactly is the scope of each?

level: middleimportance: must knowfreq 50%

basics

~10 s

internal means visible to all code in the same module (your compiled unit). private on a top-level declaration means visible only inside the same file. Both hide the declaration from outside consumers.

open as a page

What are trailing commas in Kotlin, where are they allowed, and why are they useful?

level: middleimportance: should knowfreq 35%

basics

~20 s

A trailing comma is a comma after the last item in a list, like f(a, b,). Kotlin allows it in many comma-separated lists. It makes adding/removing/reordering lines easier and produces cleaner diffs in version control.

open as a page

How does the Kotlin compiler enforce `internal` visibility on the JVM, and what are the interop and reflection consequences?

level: seniorimportance: should knowfreq 25%

basics

~20 s

The JVM has no 'module' concept, so Kotlin renames internal functions in bytecode by adding a module suffix. Other modules can't call them by their normal name. But Java code or reflection can still reach them using the mangled name.

open as a page

You're authoring a Kotlin library where the default `public` visibility risks leaking implementation details. What language/tooling mechanisms help control the public API surface?

level: principalimportance: nice to knowfreq 18%

basics

~20 s

Turn on Kotlin's explicit-API mode so the compiler forces you to label every public declaration on purpose. Mark internals with internal or private, and use tools that track your public API so accidental changes are caught.

open as a page