Extension Functions & Properties Quiz
KOTLIN › Types & Classes
open class Animal; class Dog: Animal(); fun Animal.sound()="generic"; fun Dog.sound()="woof". What does this print: val a: Animal = Dog(); println(a.sound())?
- woof
- generic
- Compile error: ambiguous call
- null
Answer: generic
Extensions resolve statically by the declared type. Since a is typed Animal, Animal.sound() is chosen regardless of the Dog runtime instance.
A class has fun greet() printing "member", and there is an extension fun TheClass.greet() printing "extension". What does instance.greet() print?
- member
- extension
- Both, in declaration order
- Compile error: duplicate declaration
Answer: member
Members take precedence over extensions of the same signature, so the member runs. The extension is silently never called (the IDE warns it is shadowed).
Which statement about extension properties is correct?
- They can store state in a backing field like regular properties
- They can be initialized with = when you declare them
- They need a custom getter and cannot have a backing field
- They replace existing properties declared in the class
Answer: They need a custom getter and cannot have a backing field
Extensions add no real members, so there is no backing field; you must supply a custom getter (and setter if mutable), and cannot use an initializer.
What is the main reason to declare an extension on a nullable receiver, e.g. fun String?.orEmpty()?
- It makes the receiver non-null inside the body automatically for you
- It forces every caller to pass only non-null arguments
- It enables virtual dispatch across all the null subtypes
- It lets the function be called on a null receiver without an NPE
Answer: It lets the function be called on a null receiver without an NPE
A nullable receiver type allows the call when the value is null; the body handles this == null itself, moving the null check inside the extension.
On the JVM, how is a top-level extension function fun String.shout() compiled?
- As a new instance method grafted directly onto java.lang.String
- As a static method taking the receiver as its first argument
- As a runtime-generated subclass extending String
- As a default method on a synthetic helper interface
Answer: As a static method taking the receiver as its first argument
The compiler emits a static helper whose first parameter is the receiver; the original class is untouched, which is precisely why dispatch is static.
Which of these is a genuine Android KTX extension that reduces boilerplate?
- sharedPreferences.edit { putBoolean("k", true) }
- Activity.super.onCreate() generated automatically
- viewModel = new MyViewModel()
- Context.systemServiceReflection()
Answer: sharedPreferences.edit { putBoolean("k", true) }
core-ktx adds the inline extension SharedPreferences.edit { } with a lambda-with-receiver and sensible defaults, replacing the manual edit()/put/apply chain.
A top-level extension fun User.isValid() is declared in another file. What can its body NOT do?
- Call User's public methods
- Use the receiver via the this keyword
- Read User's private fields directly
- Be imported into other packages
Answer: Read User's private fields directly
Because the extension compiles to a static method outside the class, it only sees the public/internal API and cannot touch private or protected members.
You want a List-like class you don't own to support the indexing syntax obj[i]. How can you add it without modifying the class?
- You cannot; indexing only works if you edit the original class
- Operators can never be extensions; they must be member functions
- Declare operator fun TheType.get(index: Int) as an extension
- Annotate the class with @Operator to generate indexing support
Answer: Declare operator fun TheType.get(index: Int) as an extension
Operator functions can be declared as extensions; an extension marked operator fun get(index: Int) wires up the obj[i] syntax for a type you don't own.
You want to call MyClass.fromJson(...) as if it were a static factory. Where must the extension be declared?
- As a top-level extension property on MyClass, not its companion object
- Inside a Java static initializer block, which Kotlin extensions do not use
- On MyClass directly; the companion object is not needed for this syntax
- On MyClass.Companion; MyClass must already declare a companion object
Answer: On MyClass.Companion; MyClass must already declare a companion object
Companion-object extensions give the MyClass.fromJson() call syntax, but you can only extend a companion that exists, so the class must declare one (even an empty companion object).
A top-level extension fun String.shout() lives in the file StringUtils.kt. How does Java code call it?
- "hi".shout(), because Kotlin adds the method to java.lang.String
- StringUtilsKt.shout("hi")
- new StringUtils().shout("hi")
- It is invisible to Java callers
Answer: StringUtilsKt.shout("hi")
The compiler emits a static method on the file's generated class (StringUtils.kt becomes StringUtilsKt) whose first parameter is the receiver, so Java calls StringUtilsKt.shout("hi").
In a Kotlin DSL builder, what does the type T.() -> Unit represent?
- A plain function taking a T argument and returning Unit
- An extension property declared on T, not a function type
- A function literal with receiver; T is the implicit this
- A suspending lambda bound to one T instance for its lifetime
Answer: A function literal with receiver; T is the implicit this
T.() -> Unit is a function type with receiver: inside the lambda the receiver of type T is the implicit this, which is exactly how lambda-with-receiver DSLs and apply-style builders work.
For a member extension function declared inside a class (extending some other type), which receiver is dispatched virtually at runtime?
- The extension receiver: the declared type being extended
- The dispatch receiver: the enclosing class instance
- Both receivers get dispatched virtually at runtime
- Neither; member extension functions are fully static
Answer: The dispatch receiver: the enclosing class instance
The dispatch receiver (the enclosing class instance) is resolved virtually like any normal member, while the extension receiver is still resolved statically by its declared type.
Inside fun String?.describe(), what is the compile-time type of this and what does it imply?
- String?, so this.length needs ?. or a null check first
- String, so this.length is available without any null check
- Any?, so you must cast it to String before member access
- Nothing, so the body can never actually be reached at runtime
Answer: String?, so this.length needs ?. or a null check first
A nullable receiver makes this of type String? inside the body, so the compiler forces you to handle null (this?.length or a this == null branch) before touching members.
The androidx delegate val vm by viewModels() in an Activity relies on which Kotlin feature combined with an extension function?
- Reflection on each access, checking the property at runtime
- A manually synchronized singleton field shared across the Activity
- Compile-time annotation processing that generates the property
- Property delegation with by, using a returned Lazy delegate
Answer: Property delegation with by, using a returned Lazy delegate
viewModels() is an extension function that returns a Lazy delegate, and the by keyword (property delegation) wires it up so the ViewModel is created lazily on first access.