I've been turning this around for a while: there's...
# general-advice
m
I've been turning this around for a while: there's no Kotlin equivalent to Java static factory functions, right?
Copy code
// How do I do this in Kotlin?
interface Shape {
  int area();

  class Square implements Shape {
    // private constructor here
    private Square() {}
    @Override public int area() {return 0;}
  }

  // more shapes...

  /**
   * static factory method
   * Doesn't work on a Kotlin companion function because the Square constructor is private
   */
  static Square square() {
    return new Square();
  }
}
Closest I found would be extracting a public interface with a file-private implementation but this has other issues
Or is there a way?
k
Have you tried pasting the above Java code into a Kotlin file in IntelliJ IDEA? -- Update: I see it turns the private constructor into internal.
m
Yea, here it kept it private but that fails to compile
Screenshot 2024-11-07 at 18.13.19.png
r
Untitled.kt
The above at least leaves the constructor private. Lot of boilerplate though, and of course a client can still call
Shape.Square.square()
rather than
Shape.square()
.
m
a client can still call
Shape.Square.square()
rather than
Shape.square()
Yup, ideally I'd like to avoid that but looks like that's just not an option
OptIn markers would work:
Copy code
**
 * Symbols annotated with [PrivateConstructor] are only public for technical reasons, but you shouldn't use them.
 */
@RequiresOptIn
annotation class PrivateConstructor

internal interface Shape {
  fun area(): Int

  class Square @PrivateConstructor constructor() : Shape {
    override fun area(): Int {
      return 0
    }
  }

  companion object {
    fun square(): Square {
      @OptIn(PrivateConstructor::class)
      return Square()
    }
  }
}
But still not as nice as Java
k
Do you need to have the type
Shape.Square
publicly exposed? One idiom is to have
Shape.square()
return a privately defined
Square
using a return type of
Shape
but with all the behaviour of a `Square`:
Copy code
interface Shape {
    fun area(): Int

    private class Square : Shape {
        override fun area(): Int {
            return 0
        }
    }

    companion object {
        fun square(): Shape {
            return Square()
        }
    }
}
This way it doesn't matter that the
Square
constructor is public, as your users can't construct a
Square
directly.
m
Do you need to have the type
Shape.Square
publicly exposed?
Yes, in my use case,
Shape
is actually a sealed interface and the user must be able to switch on the different cases
The sub types must be public, only I want to control how they are created
e
in Java < 11, the
private
constructor gets a package-private bridge so that it can be accessed from outside the class
in Java 11 they introduced nestmates which enables access to
private
without that bridge
m
I won't be holding my breath but thanks for the pointer!
🤣 1