4 ms·
Look 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
by pdpi 10y ago
Look 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.
- SomeCallMeTim 10y agoModule global variables, I think we can agree, are less than ideal. But I was thinking of class fields. I don't really want my compiler to hold my hand with respect to "nullable", if I know for a fact that, by the time the code gets there, it can't possibly be null. Think of it this way: It's not a compile error to access an int from multiple threads, right? It doesn't require that !! syntax if you're just accessing a mutable class field or variable? So if I test an int for a value and then do something that assumes the value is still the same, I'm writing something that could crash just as easily as the null reference -- and array out-of-bounds, or a flag that says it's OK to do something but that flag changes after I check it, because I didn't grab a mutex. So why does it add an error condition if you're accessing a mutable variable that's available in multiple threads just because it's nullable? Seems like extra busy work for no clear benefit for what is, as you say, a rather rare situation. If we're going to share data across threads, I'd rather the language not present a false sense of security as a result of the !! operator.