Why is the following a warning, and not a compilat...
# language-proposals
a
Why is the following a warning, and not a compilation error?
Copy code
private fun String.hashCode() = 42
e
https://kotlinlang.org/docs/extensions.html#extensions-are-resolved-statically
If a class has a member function, and an extension function is defined which has the same receiver type, the same name, and is applicable to given arguments, the member always wins.
a
Yes, exactly, but what is the rationale for allowing a definition of an uncallable function?
e
it's not uncallable, just not by that name
for example, if you give it a different name while importing, it is callable
a
Notice that it is private
e
if it were disallowed, then API-compatible ABI-compatible changes to the original class could break compilation of downstream code
☝️ 1
s
☝️ The public API of a class can vary independently of the extension functions. Not exactly relevant with String, but in general with a public API, I could define an extension function and then the owner of the API could later define a member with the same name.
a
Yes, that is exactly my concern. I would like to know when my code becomes overriden by the API owner.
e
changes to the original class can result in downstream behavior changes on recompile due to selection of overload, but Kotlin generally considers that to be permissible
s
But like… when? When you recompile? Or just… some kind of abstract push notification? 😄
a
Concrete example: We had a "private fun String.strip(): String" function in our project. When using compile SDK 33 on Android, suddenly a wild String.strip() function appears and overrides our code, but the project compiles anyway, and we get a production bug.
Would have preferred if it didn't compile there, seems odd to me that random parts of my code get overridden
To make matters even more interesting it was in a KMM module so the behaviour was unchanged in iOS
e
in this particular case, Lint should have prevented you from using
String.strip()
unless you have
minSdk=33
a
Disagree, I defined String.strip() myself
e
but in general, this is intentional and is how Kotlin itself evolves its API
let me rephrase my prior statement: for this specific case, if Android Lint did not break your build due to calling a SDK 33+ only method (
java.lang.String#strip
), that's either a configuration issue or a Lint issue
a
Kind of going of on a tangent here but why would lint block me from calling my own extension functions?
e
it should block you from calling an unavailable method, which is what happens if your own extension is not being resolved
so I don't see how this could cause a production bug for you
a
The function is available though, since I defined it myself. It just happens to have the same name as a function that was added in Java 11
(and signature)
e
and it's used, due to Kotlin's long-standing overload resolution rules. given that, how do you possibly have a production bug? this will be a build error through Lint, even though it's not through Kotlin
a
I wish i know what I could tell you. I just got the behaviour in a production build and it surprised me to see these rules for extension functions.
e
in general though, yes there are API evolution concerns whether you pick extensions over members or members over extensions. Kotlin chose the latter and it is well documented.
a
Yeah, it would just be interesting to understand why
I know these things know and I will adjust my expectations going forward and be more careful with this. But I still think it's wrong!
Thanks for your input.
e
I suppose it's possible you're running builds without running android lint. … I would hope that you are blocking production builds on a clean lint run though, right?
a
Lint doesn't capture this.
e
oh hmm. I gave it a shot in my project; it shows up as an error in the IDE but not in the command line lint tool
a
Yeah same here, in my reproducible example I get the IDE warning (which wouldnt have helped us anyway), but I didn't get it in my real project for whatever reason
only thing to save me here would have been
Copy code
kotlinOptions.allWarningsAsErrors = true
e
I see red sqiggle in the IDE on calling
"".strip()
, regardless of whether there is an extension function or not. it seems like a bug that the same is not reported in the lint tool.
a
Yes, there is a warning about it being an unstable api or some such in kotlin.
That was also not there in my real project, not sure whats causing it to miss it
the underlying .strip() isnt defined in kotlin so its a call to the java method
But in any case, thats should be a kotlin compiler concern, not android-lint concern
e
it is not a compiler concern - Kotlin has always preferred members over extensions. the designers could have made the choice in either direction, with different issues; this is the way they went with, and it can't be changed without breaking existing codebases