-
Notifications
You must be signed in to change notification settings - Fork 363
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Bound callable references #5
Comments
Just to clarify:
But this would still work, right?
I'd rather go for API for getting an unbound reference from a bound reference (and vice versa).
Of course there would be a way to check if it's bound/unbound, right? |
Currently this is not planned, but it's a valid option.
This is exactly what that open question is about. It's not clear at this point whether such API is needed and what declarations would be available there. I'll elaborate on this in the proposal. |
I noticed that re-introducing type inference for an empty LHS isn't listed as a "possible future advancement". Has this been considered? i.e.: val foo = listOf<String>()
foo.filter(::isEmpty) // String::isEmpty is inferred for arguments of type String.() -> Boolean or (String) -> Boolean It's not specifically related to bound references, but as I recall, it was removed to reserve the syntax for an implicit I wouldn't mind having to be explicit to resolve ambiguities with |
Hmm, I think this would be really limiting and lead to unnecessary tricks (to get the non-nullable reference) in many normally valid scenarios. Like instead of being able to do this: |
It would be really nice if we could create something like delegates in C#. It requires bound references to be comparable. I don’t think it’s possible to make bound references for the same member of a single instance equal by reference in general case. But it should be possible to override |
Why can't they be comparable? Just tested this:
and got:
so everything works as expected. |
If you mean comparable by references then I don't see a way ho you can cache an instance of |
No, I mean structural equality, because that's all what's needed: https://kotlinlang.org/docs/reference/equality.html#structural-equality |
That's what my question is about. I would like the bound reference to have |
Maybe add support for partial application? Something like Of course this could also be separate from this issue. |
@TheRaspPie Partial application is available from funKTionale https://github.com/MarioAriasC/funKTionale/wiki/Partial-application |
@MichaelRocks could you clarify: what is the use case you have in mind? |
I think the use cause would be like this one, but with a bound reference instead of a lambda: |
@abreslav Sure. Let's say we have a class that allows us to add/remove and notify observers. class Event<T> {
private val observers = ArrayList<(T) -> Unit>()
operator fun plusAssign(observer: (T) -> Unit) {
observers += observer
}
operator fun minusAssign(observer: (T) -> Unit) {
observers -= observer
}
operator fun invoke(value: T) {
observers.forEach { it(value) }
}
} And also we have a class which method must be invoked when an event occurs. class Listener {
fun onEvent(string: String) {
// Do something.
}
} The natural syntax for adding, invoking, and removing an observer would be something like that. val event = Event<String>()
val listener = Listener()
event += listener::onEvent
event("Test")
event -= listener::onEvent Unfortunately, removing the observer will not work if equals for a bound reference is not implemented properly. So I suggest overriding the |
@udalov please correct me if I'm wrong, but I think that |
Regarding the @MichaelRocks comment, I think it's worth to mention that the following use case should be supported as well: interface Foo {
fun foo(): CharSequence
}
class Bar : Foo {
override fun foo(): String = ""
}
val bar: Bar = Bar()
val foo: Foo = bar
require(foo::foo == bar::foo)
|
As @damianw said, there should be support for inferring the instance if it is not specified. Being forced to do |
You probably mean
This is a valid option, although it'll only allow to pass a reference to a function, not to a property. Still, we're investigating this possibility. |
Yes, sorry for confusion. I am talking about eta expansion of a method into a function, to avoid this::someMethod |
Will inlining be supported for bound callable references? Example: Will it be possible to reference extension methods that are instance methods? Currently, this doesn't work: class Bar
class Foo {
fun Bar.doStuff() {}
fun baz(bar: Bar) {
bar.apply(Bar::doStuff) //doesn't work
}
} What about referencing And what about partially bound references. Can I bind only |
@udalov is there a timeframe for this feature (a rough one at least), do you plan to do some other things first, etc. I'd (and hopefully I'm not the only one) just like to know how long it's going to take. |
The prototype is being worked on currently and the larger parts are mostly done. Once everything is implemented according to the proposal, we'll start an early access preview for this feature as a part of Kotlin 1.1. There's no date set for the 1.1 release; it will be out when this and other planned features are fully implemented. The first EAP is coming soon (the main development branch is already 1.1). |
@cypressious I'm not sure if we have taken care of it already, but I believe we should. It's an important use case. // cc @udalov |
Maybe bound reference should be of some subtype of |
Sorry for the long delay. Re your comment,
If by Overall, we've discussed this and decided that unless there are obvious reasons why it should be supported immediately, it can be postponed. Fun fact, to support it in the future without breaking source compatibility we must reserve the |
Yes, they do have different effect. I took a shortcut with my example, with the But I'm not sure how is this going to work with nullable references without the |
No, it won't be possible, see the end of the Resolution section:
So the only possible way would be the one you proposed or, if the operator ignores nulls, |
Thanks. This could be implemented, but with some care not to break source compatibility. I'll explain in the proposal. |
Is there something we can do about type mismatch because This makes it hard to use builder-style methods or something like |
Please vote for KT-11723 and share your use case there. Thanks! |
Has there been some progress on instance extension methods? It seems counterintuitive, that you can do class Foo {
fun doStuff(bar: Bar) {
}
} but can't with class Foo {
fun Bar.doStuff() {
}
} even though they are virtually the same. |
@udalov Sorry for the delay.
The idea is that The result of differentiating between function and anonymous function is that you need to write To answer your question: This topic is only relevant indirectly to this proposal, because it applies to the overall concept of method references which this issue is a part of. The argument that you want the same notation as in Java is a valid, although inconsistent argument. Then you'd also need the same syntax for constructors, variable declaration etc. |
References to operators are generally unnecessary because you can always use the desugared methods but the comparison operators Use case: listOfFoos.all(fooProvider.computeFoo()::==)
listOfMeasurements.any(THRESHOLD::<) |
@cypressious why callable references should be used here? Doesn't plain lambdas fit this case more? |
One argument is that the lhs of the bound callable reference is cached but more arguments were discussed in this thread.
I was thinking about this question and one possibility I see is to provide |
Reword the whole algorithm, to (hopefully) improve readability
Reword callable reference and class literal resolution algorithm, explain some corner cases (#5)
I've reworded the part about resolution of left-hand side in the proposal and added some corner case examples and their solutions, everyone is welcome to review. |
What about reference to constructors?
|
@punksta |
Update type checking rules of bound class literals (#5)
Why would it be indistinguisheable? Currently Kotlin allows propertiy and function with the same name: val i: Int = 2
fun i(): Int {
return 2
}
print(i)
print(i()) Diallowing this (I cannot imgae when this will be useful) so we can just refer a function with its name. |
@weakish That would break backward compatibility and is out of the question. |
@cypressious I think few code are written with same name property and function. Besides, current Kotlin cannot resolve it correctly with class KK() {
val i = 1
fun i(): Int { return 1 }
}
fun hkk(kk: KK, f: (KK) -> Int) {
println(f(kk))
}
fun main(args: Array<String>) {
hkk(KK(), KK::i)
} Compiled with
So:
|
The feature has been released in Kotlin 1.1, thus I'm closing the KEEP. Do not hesitate to open a YouTrack issue for any additional suggestions |
Discussions about the Bound callable references proposal will be held here.
@udalov is the shepherd for this proposal.
Short description
Bound callable references are expression like
foo::bar
wherefoo
is itself an expression, not a class. A type offoo::toString
would be() -> String
for anyfoo
.See full proposal for more details
The text was updated successfully, but these errors were encountered: