Wondering what others think about whether it shoul...
# language-proposals
s
Wondering what others think about whether it should be possible to implement a sealed interface that exists in a different package by delegation. It would still ensure that the implementation remains the same as one that exists within the same package as the sealed interface.
Motivation for our case is for producing these interfaces as proof of validation while limiting the ability to create instances to the validation methods with visibility of the sealed interfaces. Being able to delegate would allow us to construct new proofs that also carry any dependent/implied proofs, while keeping the construction of them limited to their associated (and package isolated) validation methods. e.g.
Copy code
package a
sealed interface OldEnough
private object OldEnoughInstance : OldEnough
Copy code
package b
sealed interface Employed
private data class EmployedInstance(private val proof: a.OldEnough)
  : Employed, a.OldEnough by proof
e
can't be allowed; code like
Copy code
fun f(x: OldEnough) = when (x) {
    is OldEnoughInstance -> {}
}
is allowed to assume that the only immediate subtypes of sealed
OldEnough
are defined in the same package+compilation unit, and would break on
f(EmployedInstance(...))
because it is not
you could drop
sealed
, or perhaps
Copy code
interface HasOldEnoughProof {
    val oldEnough: OldEnough
}
sealed interface OldEnough : HasOldEnoughProof {
    override val oldEnough: OldEnough
        get() = this
}

class EmployedInstance(override val oldEnough: OldEnough) : HasOldEnoughProof
but you haven't explained enough here to determine what is necessary
s
End goal is to be able to pass around types that can only be generated through validation functions/smart constructors, though can be combined together in some form while avoiding deep subclass hierarchies. e.g. Some of these validation functions require passing in other proofs of prior validation, so being able to compose these together such that functions that depend on a particular state can accept a single argument and declare which constraints are required.
Copy code
fun <A> foo(proof: A)
  where A : SomeConstraint,
        A : SomeOtherConstraint = ...
y
you can have a custom extendible class/interface in your hierarchy like this:
Copy code
package a
sealed interface OldEnough
private object OldEnoughInstance : OldEnough
class OldEnoughDependent(oldEnoughInstance: OldEnough): OldEnough by oldEnoughInstance

// Other module

package b
sealed interface Employed
private data class EmployedInstance(private val proof: a.OldEnough)
  : a.OldEnoughDependent(proof), Employed
Same thing can be done with an interface but I think you'll need to delegate each method manually, but AFAIK Intellij can auto-generate that