0

I can't understand why the following code works: Sam Interface:

 fun interface WebResponseHandler { fun onWebResponseFinished(jsonObject:JSONObject) } 

and Implemnetaiton looks like:

 val onWebResponseHandler: VolleyHandler.WebResponseHandler = VolleyHandler.WebResponseHandler() { fun onWebResponseFinished(jsonObject: JSONObject) { Log.v("da", "dsa") } fun foo() { it.getString("name") } } 

How does foo function knows what is it? After all, foo function isn't part of the VolleyHandler.WebResponseHandler interface, and it works only when interface as only one method.Function Foo is being called without any arguments, so why is the meaning of it there?

In addition another problem occurs if I'm omitting the keyword fun from the interface declaration, when i'm trying to implement the interface:

val onWebResponseHandler: VolleyHandler.WebResponseHandler = VolleyHandler.WebResponseHandler() { fun onWebResponseFinished(jsonObject: JSONObject) { Log.v("da", "dsa") } fun foo() { Log.v("something", "something") } } 

I'm getting a compilation error saying

Interface WebResponseHandler does not have constructors

what is the different between both situation? If i remove the () i'm getting a lot of different errors like :

Function declaration must have a name

I hope someone can figure out what is wrong here

3
  • What's happening is very sutle and weird, but none of this code is doing what you think it is. What you need to actually do what you think you're doing is to write object : after the = sign: = object : VolleyHandler.WebResponseHandler() { ... } Commented Nov 11, 2020 at 20:41
  • @LouisWasserman, can i use the fact the it's a SAM interface? Do you have explanation to all the issues i have written in the post? it seems that Kotlin doesn't have explanation for all the mess Commented Nov 11, 2020 at 20:46
  • It seems that if i use () i must open the { at the same line. Really can't understand what is going here Commented Nov 11, 2020 at 20:52

2 Answers 2

2

It's not Kotlin that's a mess, it's that you're using the wrong syntax for what you want to do.

What fun interface lets you do is write

val onWebResponseHandler = VolleyHandler.WebResponseHandler { jsonObject: JSONObject -> Log.v("da", "dsa") } 

What you can do with a normal interface is write

val onWebResponseHandler = object : VolleyHandler.WebResponseHandler() { fun onWebResponseFinished(jsonObject: JSONObject) { Log.v("da", "dsa") } fun foo() { Log.v("something", "something") } } 

Your code does none of those things, and when compiled, doesn't do anything like what you mean it to. What you wrote is equivalent to

val onWebResponseHandler = VolleyHandler.WebResponseHandler() { unusedJsonObject: JSONObject -> fun aFunctionWhichIsDefinedAndNeverCalled(jsonObject: JSONObject) { Log.v("da", "dsa") } fun anotherFunctionWhichIsDefinedAndNeverCalled() { unusedJsonObject.getString("name") } // doesn't actually do anything at all when executed // just defines functions which aren't ever invoked } 

...which compiles because, since it's a fun interface, you can just pass a lambda to the constructor, but doesn't actually do anything resembling what you expect.

Sign up to request clarification or add additional context in comments.

10 Comments

Do functions declaration can be part of the lambda expression?
What will happen when i will write onWebResponseHandler.aFunctionWhichIsDefinedAndNeverCalled? also you said: you can just pass a lambda to the constructor but an interface doesn't have a constructor.
You are defining a local function, which can't be called from the outside. You can declare functions, as you have here, but they can only be called from within the lambda.
Additionally, defining a fun interface does create a constructor for the interface: one accepting a single lambda.
i have never seen such a lambda.. usually lambda has input parameters followed by -> and then the implementation inside curly braces. I can't understand this lambda :(
|
1

Here's a different way of explaining it that might help.

If you want to assign an implementation of an interface to a variable or property, you usually have to use an anonymous class syntax like this. Note the use of object: and override.

val onWebResponseHandler = object : VolleyHandler.WebResponseHandler { override fun onWebResponseFinished(jsonObject: JSONObject) { Log.v("da", jsonObject.toString()) } } 

You could also define other public functions in your anonymous class, but this is pointless because there is no way to access the unique members of an anonymous class, so you would not be able to call the function foo() in this example:

val onWebResponseHandler = object : VolleyHandler.WebResponseHandler { override fun onWebResponseFinished(jsonObject: JSONObject) { Log.v("da", jsonObject.toString()) } fun foo() { Log.v("something", "something") } } 

If you make your interface a fun interface, that enables the use of lambda syntax to define that single function like this. This is what SAM conversion is. It treats your lambda as an anonymous implementation of your interface.

val onWebResponseHandler = VolleyHandler.WebResponseHandler { jsonObject -> Log.v("da", jsonObject.toString()) } 

Furthermore, if a lambda has only one parameter, you can omit defining the parameter name, and simply call it it so this is equivalent to the above:

val onWebResponseHandler = VolleyHandler.WebResponseHandler { Log.v("da", it.toString()) } 

Also, be aware that you can define a function anywhere in your code, including right in the middle of another function. For example:

fun bar() { fun foo() { Log.i("foo", "foo") } foo() } 

is equivalent to

fun bar() { val foo: () -> Unit = { Log.i("foo", "foo") } foo() // or foo.invoke() } 

So in your original code, you combined these concepts to create a lambda function that has other functions defined in it that are never used. The confusion probably comes because it looks similar to my top block of code, where we are defining an anonymous class with the object: syntax. The big difference is that you omitted object: and override, so you are using the lambda syntax. Your code is equivalent to:

val onWebResponseHandler = VolleyHandler.WebResponseHandler { jsonObject -> val onWebResponseFinished: (JSONObject) -> Unit = { Log.v("da", "dsa") } val foo: () -> Unit = { jsonObject.getString("name") } } 

which without lambda syntax (SAM conversion) would look like

val onWebResponseHandler = object : VolleyHandler.WebResponseHandler { override fun onWebResponseFinished(jsonObject: JSONObject) { val onWebResponseFinished: (JSONObject) -> Unit = { Log.v("da", "dsa") } val foo: () -> Unit = { jsonObject.getString("name") } } } 

5 Comments

first of all thank you (like always). Secondly, can you tell me what is the role of the object in object : VolleyHandler.WebResponseHandler? Is it somehow related to companion? Because when i'm omitting the objecti'm getting the follwoing error: "Classifier 'WebResponseHandler' does not have a companion object, and thus must be initialized here"
object is a way of defining a singleton class, which is a class with no constructor and that is automatically instantiated the first time it is used, and there only exists one instance for the whole app. There are three ways to use it.
(1) A companion object is one that goes along with some other class and can be called by that class's name. (2) You can simply define your whole class as an object by using object instead of class. (3) You can use them like I did above to create an anonymous class, which means you are creating an object that implements an interface or is a subclass of something without even giving it a name. Same concept as an anonymous class in Java.
SAM conversion is where you can use lambda syntax to create an anonymous implementation of an interface that has a Single Abstract Method instead of using the object: syntax.
thanks a lot, i think i understood ALL my mistakes

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.