Kotlin lambda syntax confusion
Asked Answered
E

2

13

I'm confused by Kotlin lambda syntax.

At first, I have

.subscribe(
          { println(it) }
          , { println(it.message) }
          , { println("completed") }
      )

which works fine.

Then I moved the onNext to another class called GroupRecyclerViewAdapter which implements Action1<ArrayList<Group>>.

.subscribe(
          view.adapter as GroupRecyclerViewAdapter
          , { println(it.message) }
          , { println("completed") }
      )

However, I got the error:

error

Error:(42, 17) Type mismatch: inferred type is () -> ??? but rx.functions.Action1<kotlin.Throwable!>! was expected
Error:(42, 27) Unresolved reference: it
Error:(43, 17) Type mismatch: inferred type is () -> kotlin.Unit but rx.functions.Action0! was expected

I can fix the error by changing to:

.subscribe(
          view.adapter as GroupRecyclerViewAdapter
          , Action1<kotlin.Throwable> { println(it.message) }
          , Action0 { println("completed") }
      )

Is there a way to write the lambda without specifying a type? (Action1<kotlin.Throwable>, Action0)

Note: subscribe is RxJava method

Edit 1

class GroupRecyclerViewAdapter(private val groups: MutableList<Group>,
                           private val listener: OnListFragmentInteractionListener?) :
RecyclerView.Adapter<GroupRecyclerViewAdapter.ViewHolder>(), Action1<ArrayList<Group>> {
Enteric answered 23/1, 2016 at 18:14 Comment(3)
looks like a type reference errorPhysic
its nice if you can include the error message as text, will help others find this post. You can compile, to get the same error you saw in the editor. Then cut-n-pasteHypoderma
@JaysonMinard added. thanksEnteric
P
12

view.adapter as GroupRecyclerViewAdapter part should be lambda func, not Action, since onError and onComplete also lambdas

so, to fix this try:

.subscribe(
          { (view.adapter as GroupRecyclerViewAdapter).call(it) }
          , { println(it.message) }
          , { println("completed") }
      )

with your names (replace Unit with your type)

class GroupRecyclerViewAdapter : Action1<Unit> {
    override fun call(t: Unit?) {
        print ("onNext")
    }
}

with lambdas

val ga = GroupRecyclerViewAdapter()
...subscribe(
    { result -> ga.call(result) },
    { error -> print ("error $error") },
    { print ("completed") })

with actions

...subscribe(
    ga,
    Action1{ error -> print ("error $error") },
    Action0{ print ("completed") })

pick one

Phidias answered 24/1, 2016 at 2:6 Comment(22)
Nope, doesn't work. if it's the case, why my last snippet works then?Enteric
because in last example they all Actions. give me a sec i'll tryPhidias
please provide view.adapter signature at least. is it really Action1? if it is in my example it should be (view.adapter as GroupRecyclerViewAdapter).call(it), sorryPhidias
Sure. added it. it's Action1Enteric
in (view.adapter as GroupRecyclerViewAdapter).call(it) take a note on it partPhidias
what error are you getting after applying my comment?Phidias
call per se returns Unit, but { (view.adapter as GroupRecyclerViewAdapter).call(it) } is a lambdaPhidias
isn't compiled says nothingPhidias
But my GroupRecyclerViewAdapter works fine. I'm sorry but the thing is I'm trying to pass some value in call (onNext). I don't think your edit really answers my question.Enteric
because your question makes no sense. you are not specifying type of lambda, but type of arguments you passing to .subscribe(). Since you are confused with lambda syntax I'm correcting you that you cannot pass Action and lamba as arguments, you must choose one.Phidias
Hey guys, did it work or didn't? And where the rule of not using SAM with lambdas has come from? Never heard of that.Physic
@Physic not aware if there is an explicit rule for that. but provided code in snippets works. and mixing Actions with lambdas gives syntax error.Phidias
@EntryLevelDev based on the conversation, this is a bug of the compiler. Please fill an issue at youtrack.jetbrains.com/issues/KTPhysic
@Physic I am not sure I understand this enough to file the issue. I still don't quite understand how Kotlin compiler infer type in this case. i'll do some research and might file an issue later.Enteric
@EntryLevelDev information in your question is more than enough for a bug ticket. Note: it is better for an issue to be filed by the one who found the problem because developers may need some additional info about your project, environment, etc.Physic
@EntryLevelDev please provide link to created issue, I'll vote it up. experiencing same behaviour. or if you are don't mind I can create one.Phidias
@AndreyElizarov actually, please go ahead creating the issue if you'd like.Enteric
@AndreyElizarov do you mind elaborate more why extending adapter with Action is poor design choice? I'm following github.com/JakeWharton/u2020 and I think it's a pretty good idea.Enteric
@Physic just to be clear, bug here is that one cannot mix SAMs with lambdas in arguments of function which expects only SAMS?Phidias
@EntryLevelDev could you point out specific files where did you get idea from? (@AndreyElizarov - me, forgot to change nick)Phidias
@Phidias github.com/JakeWharton/u2020/blob/… I think making the Adapter as a "sink" and letting it auto update a view when data changes is pretty neat. that's the point of using Rx, right?Enteric
Let us continue this discussion in chat.Enteric
D
2

You have two versions of the subscribe method to choose from:

  • The first (the real one) has the signature subscribe(Action1<ArrayList<Group>>, Action1<Throwable>, Action0).
  • The second version is generated by the Kotlin compiler and has the signature subscribe((ArrayList<Group>>) -> Unit, (Throwable) -> Unit, () -> Unit)

In your code, however, you pass the following parameter types:

subscribe(
    view.adapter as GroupRecyclerViewAdapter, // Action1<Throwable>
    { println(it.message) },  // (Throwable) -> Unit
    { println("completed") } // () -> Unit
)

As you can see, these parameter types satisfy none of the available signatures. The other answer gives you some solutions to your problem. In addition, you can make GroupRecyclerViewAdapter implement the functional type Function1<ArrayList<Group>, Unit> (they're interfaces, too) instead of Action1<ArrayList<Group>>.

Doti answered 25/1, 2016 at 12:34 Comment(1)
Would be nice to mix and match though!Mathews

© 2022 - 2024 — McMap. All rights reserved.