Operators

Unary plus (+)

Implemented; no recorded answers are attributed to this entry

How we measure this · See the Rust code

No local names are recorded for this entry.

What it does

+number

+A returns its operand. The whole question on this page is how much of the operand it returns — the value alone, or the value together with its type.

There are two candidate readings, and they are not compatible:

Reading 2 — type-preserving identity. +A returns the operand unchanged, including its kind: text stays text, a logical stays a logical, a number stays that number. Under this reading +"2" is the text 2 and +TRUE is the logical TRUE.

For number operands the two readings agree, which is why the discrepancy survived: almost every real use of +A in a workbook has a numeric operand.

Arguments

PositionNameMeaning
0AThe operand. Required.

Arity is exactly 1; no optional arguments, no defaults.

The same + character in infix position is FUNC.OP_ADD, a two-argument function with a different operand doctrine. A leading + typed at the start of a formula (+A1*2, the habit inherited from Lotus 1-2-3 keyboards) is this operator applied to the rest of the expression — which is why the distinction is not academic: millions of formulas begin with it.

Try it

Input cells (optional)

Example: {"B2": 3, "B3": 4}. A1 holds the formula. Other cells need values before a formula can read them.

Enter a formula, then calculate.

Runs locally in your browser with OneCalc. Its answer may differ from Excel. Use English function names and commas between arguments.

Quirks

Result and edge cases

  • Number operand. Both readings return the same number. The BUG-FUNC-029 fix note additionally describes an underflow normalization on the number path; the Handbook has not characterized that behaviour and does not restate it as a rule here.
  • Text operand. The pivot case. Reading 1 coerces (and fails with #VALUE! on non-numeric text); reading 2 returns the text unchanged, so +"abc" would be "abc" rather than an error. These differ not only in value but in whether an error occurs at all.
  • Logical operand. Reading 1 gives 1 or 0; reading 2 gives TRUE or FALSE.
  • Blank operand. The BUG-FUNC-029 record describes blank/empty mapping to 0 among the operand semantics it measured before coding. Cited as an upstream observation, not as a Handbook claim.
  • Error operand. Propagates under both readings.
  • Arrays. Elementwise under both readings; under reading 2 the mapping preserves each element's own kind.

Errors

data/functions/FUNC.OP_UNARY_PLUS.json records no Microsoft documentation URL (docs is null). No Microsoft page is cited here for the type-preservation question, and the Handbook has not found one that settles it.

How to implement

Notes for implementers

  • Decide the reading explicitly and record it. An implementation that silently routes +A through the shared unary-numeric path has chosen reading 1 by omission — which is exactly the shape BUG-FUNC-029 describes as its root cause (a coercing surface reused for an identity operator).
  • If you implement reading 2, the operator is not a numeric kernel at all and does not belong behind a NumToNum signature; its array path must map kinds elementwise, not values.
  • Under either reading, error operands propagate and the operator is SafePure, Deterministic, NonVolatile.
  • Do not let the leading-+ typing habit reach a different code path from an inner +A. They are the same operator.

Rust code

Show the CalcFunc source of this function

Quoted from the public repository DnaCalc/DnaCalc, crates calc-func and calc-fml, at commit 9e1884369a67. Comments are the source's own. A kernel shared with other functions appears once, on its module page.

+ prefix · 1 lines · calc-func/src/catalogue/arithmetic.rs on GitHub
CatalogueEntry::operator(UNARY_PLUS, "+", Notation::Prefix, NUMBER, unary_plus)
unary_plus · 22 lines · calc-func/src/catalogue/arithmetic.rs on GitHub
/// `+x`: Excel's unary plus leaves its operand's value as it is, so text and a logical are the
/// result unchanged and an error is the result. A number is published by the number rule (a zero
/// is +0), and a blank operand is 0.
fn unary_plus(
    arguments: &[CalcValue],
    services: &mut EvalServices<'_>,
) -> Result<CalcValue, FunctionFault> {
    let site = Site::new(UNARY_PLUS, services);
    Site::finish(site.scalar_operands(arguments).and_then(|()| {
        let operand = &arguments[0];
        if operand.is_excel_overflow() {
            return Ok(operand.clone());
        }
        match operand.core_ref() {
            CoreRef::Number(n) => site.number(site.argument(0, coerce::operand(n))?),
            CoreRef::Empty | CoreRef::Missing => site.number(0.0),
            CoreRef::Text(_) | CoreRef::Logical(_) => Ok(operand.clone()),
            CoreRef::Error(code) => Err(Exit::Error(code)),
            CoreRef::Array(_) | CoreRef::Reference(_) => Err(site.not_modelled(Some(0))),
        }
    }))
}

Argument and result plumbing

No implementation has been published with a Handbook test suite for this function.

Version differences

No comparison between specific Excel builds is recorded here yet. This does not establish that all builds behave alike.

Alternatives

Relationships

  • FUNC.OP_NEGATE — the coercing unary sibling. The pair is the clean experiment: run identical operands through -A and +A and the coercion doctrine of each becomes visible in one screenshot.
  • FUNC.OP_ADD — same character, two operands.
  • N, VALUE, T — the explicit coercion functions. If a formula wants a number, one of these says so; +A does not, under either reading.
  • The --A double-unary idiom uses FUNC.OP_NEGATE twice, not this operator, and its coercing effect is well established — which is itself circumstantial support for reading 2, since nobody would need -- if + already coerced.

Named variants

No named variants are recorded yet.

Suggest a correction or contribute an implementation · For agents