Jordan Terrell
08/24/2023, 4:20 PMJordan Terrell
08/24/2023, 4:21 PMJordan Terrell
08/24/2023, 4:21 PMContract
is defined in a package named packageA
in a module named moduleA
.Jordan Terrell
08/24/2023, 4:22 PMJordan Terrell
08/24/2023, 4:24 PMClassFamily
and InterfaceFamily
attempt to directly inherit from the Contract
type, but the compiler indicates that you cannot inherit from a sealed type defined in a different package or module:Jordan Terrell
08/24/2023, 4:24 PMClassFamily
and InterfaceFamily
themselves are abstract - you cannot create instances of them.Jordan Terrell
08/24/2023, 4:26 PMClassFamily
and InterfaceFamily
?efemoney
08/24/2023, 4:26 PMJordan Terrell
08/24/2023, 4:30 PMJordan Terrell
08/24/2023, 4:30 PMefemoney
08/24/2023, 4:31 PMJordan Terrell
08/24/2023, 4:31 PMClassFamily
and InterfaceFamily
don't introduce any new variants of Contract
.Jordan Terrell
08/24/2023, 4:31 PMefemoney
08/24/2023, 4:31 PMFirst
& Second
) is allowed, those arenāt sealed. But your snippet is extending the actual sealed Contract interfaceJordan Terrell
08/24/2023, 4:33 PMFirst
and Second
types implement a variant from Contract
, so safe code wouldn't break.efemoney
08/24/2023, 4:34 PMButClassFamily itself is the introduced variant. Even though its sealed absolutely nothing stops you from adding a subclass of it that in fact does not extend First or Second. And just like that moduleA invariant (that contract is of type First or Second) is broken. Thats not āsafeā code.andClassFamily
donāt introduce any new variants ofInterfaceFamily
.Contract
Jordan Terrell
08/24/2023, 4:36 PMnothing stops you from adding a subclass of it that in fact does not extend First or Second
- unless the compiler enforces that you implement the First
or Second
variants of the Contract
interface, which you see in the example I did.Jordan Terrell
08/24/2023, 4:38 PMwhen
expression would still be exhaustive:
when(val c: Contract<A, B> = funcThatReturnsClassFamily()) {
is Contract.First -> println("first")
is Contract.Second -> println("second")
}
Jordan Terrell
08/24/2023, 4:39 PMwhen
expression and not match one of the arms.efemoney
08/24/2023, 4:42 PMJordan Terrell
08/24/2023, 4:43 PMabstract/sealed
types in packageB
should be able to inherit from sealed
types in packageA
, but that the compiler would require anything non-abstract
derived from the new types in packageB
must implement/inherit from one of the variants of the sealed
type in packageA
.efemoney
08/24/2023, 4:44 PMJordan Terrell
08/24/2023, 4:44 PMContract
variant types.efemoney
08/24/2023, 4:44 PMJordan Terrell
08/24/2023, 4:45 PMefemoney
08/24/2023, 4:47 PMJordan Terrell
08/24/2023, 4:48 PMpackageB
.efemoney
08/24/2023, 4:48 PMJordan Terrell
08/24/2023, 4:50 PMefemoney
08/24/2023, 4:51 PMJordan Terrell
08/24/2023, 5:11 PMJordan Terrell
08/24/2023, 5:12 PMJordan Terrell
08/24/2023, 5:13 PMJordan Terrell
08/24/2023, 5:13 PMJordan Terrell
08/24/2023, 5:14 PMHappy
implements Possible.Success
and Sad
implements Possible.Error
.Jordan Terrell
08/24/2023, 5:16 PMwhen
expression on the useLogic
function is exhaustive, if and only if the compiler was improved to note that DomainSpecificResult
inherits from Possible
and it verified that all `DomainSpecificResult`'s non-abstract variants implement one of `Possible`'s variants.Jordan Terrell
08/24/2023, 5:22 PMDomainSpecificResult
cannot inherit from Possible
(as @efemoney noted) because it's a sealed type in a different package/module, and it complains that the when
expression is not exhaustive.
I think this is unnecessarily restrictive and could be enhanced to support this. That said, I welcome someone pointing out reasons why this is not sound from a type system perspective or that there is some underlying implementation detail that prohibits this.Wout Werkman
08/25/2023, 10:03 AMgroostav
09/01/2023, 9:48 PMsealed
restrictions only apply to direct children and not grandchildren and further projeny on the type hierarchy.
In my head I associate sealed
with final
classes, in that way I think of them as a kind of "dont worry compiler you wont have to invokeVirtual", but that's not strictly necessary --and indeed on my codebase we have some places with sealed class hierarchies that are more complicated.
right now you can also write
sealed interface A
abstract class B: A
class First: B()
class Second: B()
val a: A = ....
when(a){
is First -> TODO()
is Second -> TODO()
}
but with this feature it would fail with which would fail with "what about other descendants of B?"Wout Werkman
09/02/2023, 7:10 PMyour suggestion is that@groostav This is not what he is suggesting. This proposal wouldn't change the existing contract of interfaces or sealed interfaces. It will only relax the existing restriction of defining abstract subtypes in other modules as long as all of their instantiable subtypes conform to the sealed requirement. Probably explained it worse than @Jordan Terrell, be sure to read his messages :)restrictions only apply to direct children and not grandchildren and further projeny on the type hierarchy.sealed
Jordan Terrell
09/02/2023, 7:35 PMwhen
expression would not be considered exhaustive, even with today's compiler, even if everything was in the same package/module. You would have to add a is B -> TODO()
branch for it to be considered exhaustive. If some type in a different package or module inherited from B
, then that new is B
when
branch would cover it.Jordan Terrell
09/02/2023, 7:43 PMJordan Terrell
09/02/2023, 7:44 PM