4 ms·
OK, this seems like a major fail on behalf of the Kotlin developer team: var value : Int? = null fun F() : Int { if ( value != null ) return 0
by SomeCallMeTim 10y ago
OK, this seems like a major fail on behalf of the Kotlin developer team:
var value : Int? = null
fun F() : Int {
if ( value != null ) return 0
return value // error
}
Tracing value types through a function is a solved problem. Look at TypeScript: Almost the exact function above will work flawlessly. [1]
Sure something in a JVM could be changed by another thread. But that would really be a bug no matter how you slice it. Doing type analysis like this seems like a minimal requirement for a modern language.
[1] http://imgur.com/nxdN9vc http://imgur.com/nxdN9vc -- you can see that TypeScript can identify the remaining type. It works for optional null as well when strictNullChecks is enabled.
- pdpi 10y agoLook at the code carefully. The only way you can reach "return value" is if `value == null`, so the compiler complains with "Required Int, found Int?", because it (quite rightly!) can't prove that value is definitely not null Let's change it to var value : Int? = null fun F() : Int { if ( value == null ) return 0 return value // error } Now the compiler still complains, with a different error: "Smartcast to Int is impossible because value is a mutable property that could have been changed by this time". Right you are. val value : Int? = null fun F() : Int { if ( value == null ) return 0 return value } This version compiles fine because `value` is a constant (though I think the compiler should've complained about dead code. You can never reach `return value`.) fun F(value : Int? ) : Int { if ( value == null ) return 0 return value } This version also works fine.
- akkartik 10y agoI'm staring at your examples but I don't see the difference between the first and second?
- pdpi 10y agoLike taco_emoji commented: "I believe you intended to use `val` in your second example...". Fixed the example now.
- taco_emoji 10y agoI believe you intended to use `val` in your second example...
- pdpi 10y agooops thanks.
- SomeCallMeTim 10y agoOK, you're right that he wrote the example incorrectly (mine was a copy-and-paste from his). The point still stands though. > "Smartcast to Int is impossible because value is a mutable property that could have been changed by this time". Right you are. I disagree. It cannot have been changed by that time, not unless it was changed in another thread, and it would be really, really nice for a language to have built-in threading intelligence to prevent that from being necessary to check. That's what I'm saying. TypeScript is single-threaded, so it can be certain that another thread hasn't changed it. Go is multithreaded, but except for genuine globals (which need to be protected by a mutex, but shouldn't be used for just about anything) you're piping information from one state to another, which again doesn't have a synchronization problem. If you have to manually mark a variable as "safe" every time you use it, you're just going to need to do that constantly for lots of variables. And you still are stuck getting the thread safety right: The above code isn't safe if something from another thread can change value. Which I guess is the point of the exclamation points, but ... somehow I prefer the Rust approach of "Mark this block of code as unsafe." Not that I've used either language. The fact that it works correctly as a parameter, though -- that does hit the 80% case, at least.
- pdpi 10y ago> If you have to manually mark a variable as "safe" every time you use it, you're just going to need to do that constantly for lots of variables. > ... > The fact that it works correctly as a parameter, though -- that does hit the 80% case, at least. That's the thing, it's not "80% of the cases". It actually hits just about all of them. For this whole situation to be a problem, rather than the compiler preventing bugs, you need all of the following: — You need a `var`, rather than a `val` (constant). — The `var` needs to be nullable. — The var is either a module global, or a class field. — Your code doesn't touch anything multithreaded. This includes not using NIO, or having any callbacks at all to libraries that might use threading internally. If any of those requirements is missing, the compilation error is either legitimate, or gone. In my experience, eliminating the multithreaded part eliminates all the reasonable use cases for Kotlin-as-a-Java-replacement: Android, web development, desktop applications. Not all languages need to be good at everything. For my purposes, I welcome a language that makes working in heavily-multithreaded environments a bit easier, and I won't begrudge languages targeting other people's use cases either.
- SureshG 10y ago> Tracing value types through a function is a solved problem. Sure, i think that(type inference/flow typing) is solved in kotlin too. Sorry, i don't get the issue here. The last return value is throwing a compile time error because it breaks the function contract, which expects a non null value.