Edoardo Luppi
07/29/2024, 9:06 AMCLOVIS
07/29/2024, 9:25 AMEdoardo Luppi
07/29/2024, 9:26 AMEdoardo Luppi
07/29/2024, 9:26 AMCLOVIS
07/29/2024, 9:28 AMEdoardo Luppi
07/29/2024, 9:30 AMCLOVIS
07/29/2024, 9:32 AMArray<out IZoweTreeNode>
? That's the Kotlin equivalent of what you're doing, no?Edoardo Luppi
07/29/2024, 9:33 AMvar children: Array<IZoweTreeNode>?
Or on
var schema: IProfileSchema
override var schema: ICommandProfileSchema
CLOVIS
07/29/2024, 9:34 AMThe difference is in Kotlin working with external JS libraries is made much more obvious.No, it's not. Once a type has been converted into the Kotlin type system, you can do whatever you want with it. You can pass it to other functions, etc, and these have no way to know that this is an external type that doesn't really correspond to what the Kotlin type says. The only way for pure Kotlin code to be safe, is if all boundaries only let through data that has at least all capabilities of the equivalent Kotlin type. If it's unclear, the boundary should be safe and be restrictive.
Edoardo Luppi
07/29/2024, 9:36 AMCLOVIS
07/29/2024, 9:37 AMEdoardo Luppi
07/29/2024, 9:39 AMexternal interface IZoweTreeNode {
var children: Array<IZoweTreeNode>?
}
external interface IZoweJobTreeNode : IZoweTreeNode {
override var children: Array<IZoweJobTreeNode>?
}
With `var`s you can't increase the specificity of the type on the override.CLOVIS
07/29/2024, 9:49 AMvar
s. There is too much immutability here, I don't see how this example could ever be sound.
const job = new IZoweJobTreeNode();
job.children = [new IZoweTreeNode()];
Is this code allowed?
• If it's allowed, it's unsound (the type signature of IZoweJobTreeNode.children
is not respected)
• If it's not allowed, the language doesn't respect the LSP, so this isn't an inheritance relationship at allEdoardo Luppi
07/29/2024, 10:18 AMI don't see how this example could ever be sound.Even if it isn't, that's the JS library responsibility, I should be able to deal with the library anyway
Edoardo Luppi
07/29/2024, 10:20 AMchildren
and say it's a string
, the externals should reflect that.CLOVIS
07/29/2024, 12:24 PMEven if it isn't, that's the JS library responsibility, I should be able to deal with the library anywayThat's what
dynamic
is for.Edoardo Luppi
07/29/2024, 12:24 PMCLOVIS
07/29/2024, 12:24 PMCLOVIS
07/29/2024, 12:25 PMYes, but then you're losing type information, which you'd have on TS.That type information is incoherent and unsound. Nothing of value is lost.
Edoardo Luppi
07/29/2024, 12:25 PMThat type information is incoherent and unsound. Nothing of value is lost.I mean, you're losing library usability, which basically is everything you need when developing software
Edoardo Luppi
07/29/2024, 12:26 PMEdoardo Luppi
07/29/2024, 12:26 PMCLOVIS
07/29/2024, 12:27 PMunsafe
equivalent in Kotlin is dynamic
, not external
.CLOVIS
07/29/2024, 12:28 PMas
on a dynamic
value. The compiler is right to forbid dangerous code when the developer doesn't explicitly recognize the dangers.Edoardo Luppi
07/29/2024, 12:29 PMCLOVIS
07/29/2024, 12:31 PMCLOVIS
07/29/2024, 12:32 PMdynamic
. Everything else should be safe. In this example, you have to be unsound, because the library you want to interop with is unsound. So, use dynamic
.Edoardo Luppi
07/29/2024, 12:33 PMSo, useAnd then other n developers need to remember what the actual type is? Doesn't make much sensedynamic
CLOVIS
07/29/2024, 12:33 PMCLOVIS
07/29/2024, 12:34 PMunsafe
but doesn't expose it.Edoardo Luppi
07/29/2024, 12:34 PMEdoardo Luppi
07/29/2024, 12:35 PMEdoardo Luppi
07/29/2024, 12:37 PMCLOVIS
07/29/2024, 12:37 PMEdoardo Luppi
07/29/2024, 12:47 PMdynamic
on the override: loses type information
2. extension property which calls `js(...)`: can't use the same property name. + it's a mess when externals are auto-generated as you need to do that manually.
3. wrap the object into another object: impossible when the library is complex + it's a very bad idea anyway as the library itself is the abstractionEdoardo Luppi
07/29/2024, 12:51 PMCLOVIS
07/29/2024, 12:55 PMdynamic
.Edoardo Luppi
07/29/2024, 12:57 PMThis means making Kotlin as unsafe as the target languageBut obviously you're not making the language unsafe, you're making externals more flexible for K/JS. Type information is crucial for productivity. Otherwise how do a team of developers do anything useful on a dynamic property?
Edoardo Luppi
07/29/2024, 12:59 PMany
in TS, when you actually know what the underlying type is. You'd ask yourself why you're doing that.CLOVIS
07/29/2024, 1:02 PMBut obviously you're not making the language unsafe, you're making externals more flexible for K/JS.You are making the language unsafe. With your proposal, there is now a variable with the Kotlin type
Array<IZoweJobTreeNode>
that can sometimes contain an Array<IZoweTreeNode>
, which is an incompatible type. Because there are no runtime checks, this (false) type information can propagate to anywhere in the entire project.CLOVIS
07/29/2024, 1:03 PMdynamic
is exactly as unsafe. This is the exact same thing as in Rust: values of a Rust type cannot be unsafe. An unsafe
function must return a valid Rust type.CLOVIS
07/29/2024, 1:05 PMCLOVIS
07/29/2024, 1:06 PMdynamic
on JS, platform types on the JVM, unsafe
in Rust).Edoardo Luppi
07/29/2024, 1:06 PMBecause there are no runtime checks, this (false) type information can propagate to anywhere in the entire projectWe can say this about any JS external. You can type your property to
String
and have it be a number on the underlying code. So what is safe at this point?CLOVIS
07/29/2024, 1:07 PMEdoardo Luppi
07/29/2024, 1:08 PMit's 100% for sure wrongBut who says it's not handled correctly on the library side? Why would it be wrong?
CLOVIS
07/29/2024, 1:09 PMCLOVIS
07/29/2024, 1:10 PMCLOVIS
07/29/2024, 1:13 PM