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.andClassFamilydonā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