What's the difference between fromCallable and defer?
Asked Answered
S

2

20

fromCallable and defer have different implementation. I heard some say that defer helps with recursion but i can't produce any code that shows the difference between them.

i tried with infinite number implementation:

private Observable<Integer> numbers(int start) {
         return Observable.just(start)
                .concatWith(Observable.defer(() -> numbers(start + 1)));
    }

but i still get stack overflow exception when subscribing

Soutane answered 16/3, 2017 at 16:10 Comment(2)
artemzin.com/blog/…Wallow
fromCallable is kinda a convenient method for Observable.defer(() -> Observable.just(value))Gotthelf
M
17

fromCallable creates observable that emits single value, then completes.

defer postpones creation of actual observable until it is subscribed to. So you can create multi-value observable based on state at time of subscription. For example:

Observable<Integer> daysOfWeekLeft =
    Observable.defer(() -> 
        Observable.range(currentDayOfWeek(), 7 - currentDayOfWeek()));

Basically you can achieve the same with fromCallable like this:

Observable<Integer> daysOfWeekLeft =
    Observable.fromCallable(() -> currentDayOfWeek())
        .flatMap(day -> Observable.range(day, 7 - day));

PS. Your code for infinite stream of numbers results in infinite recursion. Might need to play with schedulers to avoid that.

Malversation answered 27/4, 2017 at 15:9 Comment(2)
why does defer emits multiple values?Unwise
@Dennis because author write this.Kellam
J
2

I was looking at it terms of Single, which is less complicated than Observable, because it can only have 1 value. (i.e. An observable with 1 emission). The following applies to the other types as well (Observable, Flowable, Completable)

Single.fromCallable

Single.fromCallable actually creates a new Single from the value inside the function it calls. This is why Aaron He said is comment:

fromCallable is kinda a convenient method for Observable.defer(() -> Observable.just(value))

It does that extra step of creating an Observable by using .just. If you call a function fromCallable which already creates a Single, you'll get a nested single.

// Not very useful to get a Single<Single<*>>
val fromCallable: Single<Single<String>> = Single.fromCallable {
    Single.just("Example")
}

// Better in these cases, where the function inside doesn't create a Single already:
 fun heavyFunction(): String { return "Heavy" }
val fromCallable2: Single<String> = Single.fromCallable {heavyFunction()}

Single.defer

Single.defer calls the function inside it, if it returns a Single, then you can use that Single later on. If it doesn't, it won't compile.

val defer: Single<String> = Single.defer {
    Single.just("Example")
}

// This line won't compile:
Single.defer {heavyFunction()}

// You need to wrap it in a Single:
val defer2: Single<String> = Single.defer {Single.just(heavyFunction())}

So, Single.fromCallable creates a Single from a callable, hence the name. This callable that doesn't have to create a Single, it can be anything.

Defer doesn't create a new Single, it just calls its body which should create a Single. That's why it doesn't have the from in its function name.

Janssen answered 16/2, 2021 at 21:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.