Skip to content

Instantly share code, notes, and snippets.

@ditn
Created June 23, 2017 10:03
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ditn/32ccf5e63e112c95eeff63871db79366 to your computer and use it in GitHub Desktop.
Save ditn/32ccf5e63e112c95eeff63871db79366 to your computer and use it in GitHub Desktop.
An example of a gotcha that I found whilst working with method references in RxJava/Kotlin
fun printString(string: String) = println(string)
/**
* Prints successfully
*/
Observable.just("Test string")
.doOnNext{ printString(it) }
.subscribe()
/**
* Prints successfully
*/
Observable.just("Test string")
.doOnNext(this::printString)
.subscribe()
/**
* Does not print
*/
Observable.just("Test string")
.doOnNext { this::printString }
.subscribe()
@ditn
Copy link
Author

ditn commented Jun 23, 2017

If someone smarter than me can explain why this doesn't work, please do comment!

@lmller
Copy link

lmller commented Jun 23, 2017

Compare the decompiled versions (I created a Test class and a test function to do decompile):

//works
 Observable.just("Test string").doOnNext((Action1)null.INSTANCE).subscribe();

//works
      Observable.just("Test reference").doOnNext((Action1)(new ExtensionsKt$sam$Action1$d2e50922((Function1)(new Function1(1, (Test)this) {
         // $FF: synthetic method
         // $FF: bridge method
         public Object invoke(Object var1) {
            this.invoke((String)var1);
            return Unit.INSTANCE;
         }

         public final void invoke(@NotNull String p1) {
            Intrinsics.checkParameterIsNotNull(p1, "p1");
            ((Test)this.receiver).printString(p1);
         }

         public final KDeclarationContainer getOwner() {
            return Reflection.getOrCreateKotlinClass(Test.class);
         }

         public final String getName() {
            return "printString";
         }

         public final String getSignature() {
            return "printString(Ljava/lang/String;)V";
         }
      })))).subscribe();

//doesn't work

      Observable.just("Test wrong ref").doOnNext((Action1)(new Action1() {
         // $FF: synthetic method
         // $FF: bridge method
         public void call(Object var1) {
            this.call((String)var1);
         }

         public final void call(String it) {
            // **here is the issue**: this function is created, but never invoked
            Function1 var10001 = new Function1(1, Test.this) {
               // $FF: synthetic method
               // $FF: bridge method
               public Object invoke(Object var1) {
                  this.invoke((String)var1);
                  return Unit.INSTANCE;
               }

               public final void invoke(@NotNull String p1) {
                  Intrinsics.checkParameterIsNotNull(p1, "p1");
                  ((Test)this.receiver).printString(p1);
               }

               public final KDeclarationContainer getOwner() {
                  return Reflection.getOrCreateKotlinClass(Test.class);
               }

               public final String getName() {
                  return "printString";
               }

               public final String getSignature() {
                  return "printString(Ljava/lang/String;)V";
               }
            };
         }
      })).subscribe();
   }

check the `call method of the "doesn't work" example - a function is created but never invoked

@ditn
Copy link
Author

ditn commented Jun 23, 2017

This is great, thank you. I was going to decompile the Kotlin to see what was going on, but you beat me to it 😄

Much appreciated!

@lmller
Copy link

lmller commented Jun 23, 2017

You're welcome! :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment