Operators
Unary plus (+)
Implemented; no recorded answers are attributed to this entry
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
| Position | Name | Meaning |
|---|---|---|
| 0 | A | The 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
Quirks
Result and edge cases
- Number operand. Both readings return the same number. The
BUG-FUNC-029fix 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
TRUEorFALSE. - Blank operand. The
BUG-FUNC-029record 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
+Athrough the shared unary-numeric path has chosen reading 1 by omission — which is exactly the shapeBUG-FUNC-029describes 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
NumToNumsignature; 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 GitHubCatalogueEntry::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
CatalogueEntry::operatorcatalogueoperandcoerce
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-Aand+Aand 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;+Adoes not, under either reading.- The
--Adouble-unary idiom usesFUNC.OP_NEGATEtwice, 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