% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/hybrid-then.R
\name{hybrid_then}
\alias{hybrid_then}
\title{Asynchronous or synchronous \code{then()}}
\usage{
hybrid_then(expr, on_success = NULL, on_failure = NULL, ..., tee = FALSE)
}
\arguments{
\item{expr}{An expression that evaluates to either a promise or a non-promise
value.}

\item{on_success}{A function to be called when no error occurs synchronously
or asynchronously. When invoked, the function will be called with a single
argument: the resolved value. Optionally, the function can take a second
parameter \code{.visible} if you care whether the promise was resolved with a
visible or invisible value. Can return a value or a promise.}

\item{on_failure}{A function to be called if an error occurs synchronously or
asynchronously. Takes one argument: the error object. Can return a value or
a promise to recover from the error, or throw a new error. If \code{on_failure}
is provided and doesn't throw an error (or return a promise that fails)
then this is the async equivalent of catching an error.}

\item{...}{Reserved for future use. Currently must be empty.}

\item{tee}{If \code{TRUE}, ignore the return value of the callback, and use the
original value of \code{expr} as the result. For \code{on_failure} with \code{tee = TRUE},
the callback executes but the original error is re-thrown afterward.}
}
\value{
\itemize{
\item If \code{expr} evaluates to a promise, a promise with a single followup
promise to handle the \code{on_success} or \code{on_failure} callbacks.
\item If \code{expr} evaluates to a non-promise value, the result of the synchronous
operation after being processed by \code{on_success} or \code{on_failure}.
\item If a callback returns a promise, the result is always a promise.
}
}
\description{
This is a helper function that behaves like \code{then}, however if
\code{is.promising()} returns \code{FALSE} then the handlers will be executed
immediately.
}
\details{
Execution paths:
\itemize{
\item If \code{expr} evaluates to a promise (\code{p}), it will call \code{p |> then(on_success, on_failure)}.
\item If \code{expr} evaluates to a non-promise value (\code{x}), it will call
\code{on_success(x)}.
\item If \code{expr} throws an error (\code{e}) during calculation, it will call
\code{on_failure(e)}.
}

In all cases, the \code{on_success} and \code{on_failure} callbacks are executed (when
provided).
}
\section{Utility}{


This function is useful for writing functions that need to execute followup
behavior \emph{now} or within a promise. This is different behavior than \code{then()}
where \emph{everything} is made into a promise.

\code{hybrid_then()} allows authors to keep synchronous execution on the same
\emph{tick} without requiring the use of a followup promise. This is particularly
appealing for situations where the author does not control the execution flow
for items that may be either synchronous or asynchronous, such as within
\code{{plumber2}}.
}

\section{Error Handling}{


If no \code{on_failure} callback is provided and an error occurs, the error is
re-thrown immediately (for synchronous errors) or propagated through the
returned promise (for asynchronous errors).

If an \code{on_failure} callback is provided but it throws an error, that new
error replaces the original error. With \code{tee = TRUE}, even if \code{on_failure}
executes successfully, the original error is still re-thrown.
}

\section{Callback Return Values}{


Callbacks can return any value, including promises. If a callback returns a
promise, the entire \code{hybrid_then()} call will return a promise, even if the
input was synchronous. This allows seamless transitions between synchronous
and asynchronous execution.
}

\examples{
# Basic usage - works with both sync and async values
add_to <- function(x, k) {
  hybrid_then(
    x,
    on_success = function(value) {
      value + k
    },
    on_failure = function(err) {
      message("Error: ", err$message)
      NA_real_
    }
  )
}

# Synchronous
42 |> add_to(100)
#> [1] 142

# Synchronous error
add_to({stop("Bad input!")}, 8)
#> Error: Bad input!
#> [1] NA

\dontrun{
# Asynchronous
promise_resolve(42) |>
  add_to(8) |>
  then(print)
# When resolved...
#> [1] 50

# Error handling - asynchronous
promise_resolve(stop("Bad async input!")) |>
  add_to(8) |>
  then(print)
# When resolved...
#> Error: Bad async input!
#> [1] NA

# Chaining multiple operations
# (Move the `promise_resolve()` around to see sync vs async behavior)
1 |>
  hybrid_then(on_success = \(x) x + 1) |>
  hybrid_then(on_success = \(x) promise_resolve(x * 2)) |>
  hybrid_then(on_success = \(x) x - 1) |>
  hybrid_then(print)
# When resolved...
#> [1] 3
}
}
\seealso{
\code{\link[=then]{then()}}, \code{\link[=is.promising]{is.promising()}}, \code{\link[=promise_resolve]{promise_resolve()}}
}
