# Lazy and eager API design

**URL:** https://discourse.julialang.org/t/lazy-and-eager-api-design/22398
**Category:** Internals & Design
**Tags:** question, lazy-evaluation
**Created:** [March 27, 2019, 8:43am UTC](https://discourse.julialang.org/t/lazy-and-eager-api-design/22398 "2019-03-27T08:43:54Z")
**Posts on this page:** 7
**Page:** 1

<div class="post-metadata">

### Author: ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)
#### Post date: [March 27, 2019, 8:43am UTC](https://discourse.julialang.org/t/lazy-and-eager-api-design/22398/1 "2019-03-27T08:43:54Z")

</div>

This is a somewhat general API interface design question and I am still wondering about the idiomatic “Julian” way of formulating it, so I thought I would ask here.

Suppose I have a vocabulary of verbs `f`, `g`, `h`, which operate on some objects. These operations can either be lazy or eager (think eg `Base.filter` vs `Iterators.filter`). Both the lazy and the eager versions can be advantageous, and the user should feel free to decide when to actually instantiate intermediate objects (eg after benchmarking/profiling, suppose there is no good general answer because it depends on dimensions etc).

I can imagine various approaches:

1. using a wrapper type for the lazy version, use the capitalized type name for that, and the small letter version for the eager one. Eg `F` vs `f`. This can be neat, but exposes the implementation (perhaps the user should not care about the wrapper type).

2. put the lazy and eager versions in submodules, eg `ThatModule.f` and `ThatModule.Lazy.f`. This can be cumbersome and confusing, and precludes having both in the same namespace.

3. govern lazyness with a keyword, eg `f(x; lazy = true)`. This is not type stable (unless we rely on constant propagation).

What would you recommend?

---

<div class="post-metadata">

### Author: ![zgornel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/zgornel/32/217487_2.png) [@zgornel](https://discourse.julialang.org/u/zgornel)
#### Post date: [March 27, 2019, 9:53am UTC](https://discourse.julialang.org/t/lazy-and-eager-api-design/22398/2 "2019-03-27T09:53:19Z")

</div>

how about making `f(x)` lazy by default and add a `run(f(x))` for the eager one? (eagerness is explicit) It is a bit similar to the mutating functions approach that calls the mutating one on a internally copy of the input. I consider lazy the more ‘generic’ case as it has state.

I like 3. as well; for the lazy/eager dispatch you could create methods with different number of arguments or dispatch on some singleton…

---

<div class="post-metadata">

### Author: ![pfitzseb](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pfitzseb/32/45566_2.png) [@pfitzseb](https://discourse.julialang.org/u/pfitzseb)
#### Post date: [March 27, 2019, 10:12am UTC](https://discourse.julialang.org/t/lazy-and-eager-api-design/22398/3 "2019-03-27T10:12:41Z")

</div>

Lazy-as-default seems sane to me – if the user wants the eager computation then they can wrap the lazy function call in `Base.collect` or `YourModule.materialize` or something similar.

---

<div class="post-metadata">

### Author: ![piever](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/piever/32/1815_2.png) [@piever](https://discourse.julialang.org/u/piever)
#### Post date: [March 27, 2019, 11:01am UTC](https://discourse.julialang.org/t/lazy-and-eager-api-design/22398/4 "2019-03-27T11:01:45Z")

</div>

This is probably somewhere that could use some coordination across packages. In IndexedTables all operations are eager by default but lazy version are often also possible, just not exposed to the user and I’m curious what’d be a nice API. Lazy by default here would be very breaking unfortunately, even though it feels like the cleanest design (with some `collect` or `copy` to materialize it).

---

<div class="post-metadata">

### Author: ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)
#### Post date: [March 27, 2019, 11:18am UTC](https://discourse.julialang.org/t/lazy-and-eager-api-design/22398/5 "2019-03-27T11:18:12Z")

</div>

Many interfaces in Julia (incl `Base`, the standard libraries, and various packages) offer both lazy and eager versions (in some cases a package complementing an existing API).

I agree that coordinating some general syntax for this would be nice, so the solution would ideally be one which is free from type piracy (so keywords are out).

I am somewhat reluctant to take a general stand on whether being eager or lazy should be the default, as I think it depends on the problem. An ideal API would just have both.

---

<div class="post-metadata">

### Author: ![tkf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkf/32/17635_2.png) [@tkf](https://discourse.julialang.org/u/tkf)
#### Post date: [March 28, 2019, 3:59am UTC](https://discourse.julialang.org/t/lazy-and-eager-api-design/22398/6 "2019-03-28T03:59:27Z")

</div>

> [@Tamas\_Papp](#):
>
> I agree that coordinating some general syntax for this would be nice, so the solution would ideally be one which is free from type piracy (so keywords are out).

[LazyArrays.jl](https://github.com/JuliaArrays/LazyArrays.jl) now has `Applied` much like `Broadcasted` to represent generic call trees. There is [a PR](https://github.com/JuliaArrays/LazyArrays.jl/pull/21) (or rather [my suggestion](https://github.com/JuliaArrays/LazyArrays.jl/pull/21#issuecomment-462014552)) for creating non-`materialize`d `Broadcasted` and `Applied` object with a macro `@~`. You can get a lazy object from, e.g., `@~ f(g(h.(x) .+ y), z)`.

I think it would be nice to have a common syntax like `@~` macro and common representation like `Applied` for lazy API. You can then specialize `materialize` for `Applied{<:ApplyStyle, typeof(YOUR_FUNCTION)}` to evaluate the call tree. It may be nice to also have something equivalent to `Broadcast.instantiate` to turn `Applied{<:ApplyStyle, typeof(YOUR_FUNCTION)}` to the public lazy API of your package.

---

<div class="post-metadata">

### Author: ![rapus95](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rapus95/32/3773_2.png) [@rapus95](https://discourse.julialang.org/u/rapus95)
#### Post date: [October 10, 2019, 5:27am UTC](https://discourse.julialang.org/t/lazy-and-eager-api-design/22398/7 "2019-10-10T05:27:45Z")

</div>

Are there relevant iterators that cannot be lazy by design?

Either way, why didn’t we go for a lazy by default pattern to get people used to collecting/materializing? That way all functions that iterators in some kind, would only materialize where expected.  
Maybe even make iterators that can be lazy - if such exists - hiding the full result. And specializing collect for them to instantly return the full result.
