# Empty result handling

Transducible processes such as foldl try to do the right thing even when init is not given, if the given binary operation step is supported by InitialValues.jl (for example, +, *, &, and | are supported). However, those functions throw an exception if the given collection is empty or filtered out by the transducers:

using Transducers

foldl(*, Map(add1), [])
ERROR: EmptyResultError: Reducing function * is never called.
The input collection is empty or the items are all filtered out by some transducer(s). It is recommended to specify init to avoid this kind of errors.

To write robust code, it is recommended to use init if there is a reasonable default. However, it may be useful to postpone "materializing" the result. In such case, Init can be used as a placeholder.

result = foldl(*, Map(add1), [], init=Init)

init=Init is a short-hand notation of init=Init(*) (so that * does not have to be repeated):

@assert result === foldl(*, Map(add1), [], init=Init(*))

Note also that transduce can be used for passing init as a positional argument:

@assert result === transduce(Map(add1), Completing(*), Init, [])

Since the input collection [] is empty, result is Init(*) (which is an InitialValues.InitialValue):

using InitialValues: InitialValue
@assert result::InitialValue === Init(*)

Init(*) is the left identity of *. Multiplying it with any x from right returns x as-is. This property may be useful, e.g., if result is known to be a scalar that is multiplied by a matrix just after the foldl:

result * ones(2, 2)
2×2 Matrix{Float64}:
1.0  1.0
1.0  1.0

The identities Init(*) and Init(+) can be converted to numbers:

convert(Int, Init(*))
1

Init(*) can also be converted to a String:

convert(String, Init(*))
""

This means that no special code is required if the result is going to be stored into, e.g., an Array or a struct:

xs = [true, true]
xs = Init(+)
xs
2-element Vector{Bool}:
0
1

They can be converted into numbers also by using Integer:

Integer(Init(+))
0

or float:

float(Init(*))
1.0