Inside an extension function, how can I call anoth...
# announcements
j
Inside an extension function, how can I call another function without an implicit
this
being used? In my IntelliJ Plugin have this:
Copy code
fun Project.foo {
   ...
   service<SomeApplicationService>().bar()
}
The
com.intellij.openapi.components.service.kt
file has two
service
functions:
Copy code
inline fun <reified T : Any> service(): T = ApplicationManager.getApplication().getService(T::class.java)
inline fun <reified T : Any> Project.service(): T = getService(T::class.java)
Because I'm inside a
Project
extension function, it is implicitly calling
this.service<SomeApplicationService>().work()
and thus the
Project.service()
extension function rather than
service()
. I was able to workaround by creating a separate
applicationService()
convenience function. But I have to imagine this is not an unheard of situation and was wondering if there is some syntax to say not to use the implicit
this
. It's a top-level function, to I'm not aware of any
this@
syntax for this case.
v
Iirc this is not possible yet if they have the same name and signature
Maybe if you alias the other method
d
Can you not say
this@functionName
?
a
Can you not say this@functionName ?
How would that refer to top-level function blob thinking upside down
v
But what would that bee?
this@foo
? That would be the same as the implicit
this
d
I’m probably thinking of top level extension functions
j
this@service
shows as invalid syntax. Thanks Björn (@Vampire)
Maybe if you alias the other method
Hmmm... I'll try that. I also thought of just using a wrapper function but just rewrote it with a different name since its a simple function. I had a suspicion that it was not directly possible (other than using a wrapper function) as it is a bit of a corner case. But sometimes it turns out that the Kotlin designers thought of the corner cases. So I figured I'd check.
Aliasing did not work, it still resolves the the extension function.
v
Did you actually use the alias? 🙂
☝️ 1
Or are both functions in the same package?
Then of course it still uses the extension function
a
Maybe use a custom singleton, or just aliases as suggested. I don't know what its syntax would be even if implemented maybe something like
::func
(c++) but that's reserved for function reference blob thinking upside down.
j
Did you actually use the alias?
Yes.
Copy code
import com.intellij.openapi.components.service as appService

fun Project.foo() {
    appService<SomeApplicationService>().bar()
}
Or are both functions in the same package?
Not only same package, but same file.
a
If you have any better ideas, put them on https://kotl.in/issue or propose a keep, talk in #C0B9K7EP2
v
Yeah, then the alias approach cannot work of course. Then you need a forwarding function or a rename
j
Yeah, rename is not possible as it is in an external library/API. So yeah, I think a forwarding function (which I was calling a wrapping function) is the best solution.
v
Something like this:
Copy code
private inline fun <reified T : Any> appService() = service<T>()
fun Project.foo {
   ...
   appService<SomeApplicationService>().bar()
}
👍 2
j
@Animesh Sahu - I can open a open a request / make a suggestion, I want to make verify it was not possible first. Björn (@Vampire) Thanks for the assistance.
a
I'm not aware of any, and didn't found anything similar a few days ago when I was searching about this :{
👍 1
v
If you post the link here, you get at least two votes I guess 🙂
😛 1
👌 1
j
Will do. 🙂 (It'll be a little bit as I'm in some meetings that just started.)
n
in principle they could coopt syntax like
this@null
for this
the same why you can already do
this@T
for cases where you have multiple T possible as the receiver and want to select one
a
Why
this
?
I guess they were building sort of namespaces, in search of supporting multiple-receivers
Maybe namespaces in future may solve the problem blob thinking fast
j
I was wondering if a syntax of
Unit.funciton()
would work. Basically declaring no receiver.
blob thinking upside down 1
n
I don't think namespaces make sense as a solution to this problem; you shouldn't need the person writing the code to opt into the solution
(nor do I think they make too much sense generally)
😅 1
I just suggested
this
because we already have syntax to force lookup on a specific receiver type when there is ambiguity
and weird as it is, forcing lookup on "no" receiver kind of falls into that. It also avoids having any new keywords or syntax, just combines two existing things.
An alternative here would be to give the
import foo as
statement a little more power, it is a bit weird that if you have overloaded things you just get all of them imported with no control
you can imagine even in other contexts, people might define some overloads, and you want a way to just import one of them, to avoid mistakes in your code
a
there's also
label@ for(...) { break@label }
🤔
this@
does makes some sense, but like I like to have a different operator, this seems to refer to current scope...
maybe like
noreceiver@func
lel, but something short/more concise
n
🤷 it refers to which received is being used, which is what
this@
does. In this case, we want to force no receiver, but we are still choosing the receiver.
j
The other possibility would be having a way to turn off the implicit
this
in the function and thus you would have to declare
this
when you want it rather than having to declare in some strange way to not use
this
.
1
a
explicit@function
n
Eh, I'd definitely rather quality a single call to not use the receiver, then to blanket introduce it for the whole function
j
yeah... there is that
n
it's a lot more consistent with what's already present as well. there's no mechanism vaguely similar to that
i think kotlin in general has kind of shied away from things that affect the interpretation of code less locally. I was thinking the other day how kotlin even got away from access "labels"
🤔 1
you now stick private/public on every single attribute individually
a
What? blob thinking upside down (sorry I didn't understood properly)
n
I mean in Java or C++ you don't write
private void foo();
you write
private:
and then everything beneath that is private
until you hit another label
a
Java has that label 🤔
n
yes, Java does
Not sure how else to explain 🙂 In Java and C++, you have a label that starts a section that can contain many functions /variables
in kotlin you label each function/varaible individually
it's pretty similar to the discussion here; Mark suggests adding a declaration to the function that will potentially change lookup for the rest of the function. Compared to explicitly changing the lookup each time at the call site.
j
yeah, as I think about it, and given Nir's points, I think changing the convention for an entire function would be more confusing in the long run. Better to just say "this one call is different than convention"
a
Which version 🤔
Copy code
public class Main
{
   public:
    void test() { System.out.println("World"); }
	static void main(String[] args) {
		System.out.println("Hello ");
		test();
	}
}
This doesn't seem to compile on Java 8 🤔
n
yeah seems you're right, I haven't actually written Java in many, many, years, so maybe it used to be like that, or maybe I"m just misremembering
In C++ that is what it is
r
(Sorry if this has already been mentioned, I didn't read all the comments too closely.) Can you use the FQN?
Copy code
com.intillij.openapi.components.service.getService<SomeApplicationService>().bar()
✔️ 1
v
You are totally wrong, that's just a C-thing. Java never had "access labels". It also does not make too much sense imho. That way you are forced to sort by access modifier which makes the code less readable. Instead methods that belong together should be grouped together.
@Ruckus that wouldn't help, both functions are in the same package, and even in the same file
r
I know, but since you are spelling out the path in place of the receiver, it should work (unless I misunderstood the issue). I did that similar when I ran into something similar in the past.
a
I guess it could (can receivers be implicit over package name) 😮
v
Ah, interesting
r
It won't work if the functions are defined in the root package, but that's just bad code anyway, so...
j
Interesting. @Ruckus suggestion of fully qualifying in the call seems to work. At least in IDEA's resolution of the function. Going to run a test now.
n
@Vampire the real problem here isn't forcing to sort things, or grouping order. the real problem is that it's non-local. It leads much more easily to things like like merging two commits, which are individually correct, but together result in non-working code
the same would be true for a statement that turns off implicit
this
for the rest of the function
v
That's always the problem when merging code. You always should test after merging, even if there were no conflicts. 🙂
n
it's always a potential issue but like all engineering issues, it's a question of mitigating vs exacerbating
sometimes there are counter arguments vis a vis repetition but generally there's huge value for each line to be relatively standalone and not have hidden dependencies
it would be interesting to see the exact reasoning though for getting rid of that style from C++ (btw, it's not a "C" thing, C does not have access controls at all 🙂 )
(the historical reasoning I mean; I can't seem to find it with a google search)
v
I used C short for C++ in this case, as it of course does not apply to C 😉
Probably the reasons you mentioned? 🙂
j
I can confirm that fully qualifying in the method works:
Copy code
fun Project.foo {
   ...
   com.intellij.openapi.components.service<SomeApplicationService>().bar()
}
Thanks @Ruckus 👍 So I'm thinking maybe I should change the issue request to be on of documenting how to handle this corner case rather than adding new syntax.
👍 1
v
A new syntax might not hurt either 🙂
But you should mention it as kind of work-around for fellow readers 🙂
j
Yeah. Rucks posted it in the issue and I just commented as well.
n
Thanks for posting and including some of the syntactic suggestions even
👍 1