Bug: JavaScript unary operators "+" and "-" do not function as documented for UnitValue objects
According to the Illustrator ExtendScript documentation, applying the unary operators "+" or "-" to a UnitValue object should respectively produce the numeric value or the negated numeric value of the UnitValue. However, they instead respectively produce the UnitValue unmodified or the UnitValue with its value negated.
Either the documentation or the behaviour should be updated to reflect the other.
I observed this behaviour in Illustrator 28.5 on Mac OS Sonoma.
The behaviour may be quickly tested with the following script:
var uv = new UnitValue(2, "px");
alert(
"Results:" +
"\nUnitValue unmodified: \"" + uv + "\" (" + (typeof uv) +
")\n+UnitValue: \"" + (+uv) + "\" (" + (typeof +uv) +
")\n-UnitValue: \"" + (-uv) + "\" (" + (typeof -uv) +
")\nNumber(UnitValue): \"" + (Number(uv)) + "\" (" + (typeof Number(uv)) + ")"
);

Nihiltres, UnitValue is an object with properties
baseUnit - type of UnitValue data type
type - type of String data type
value - type of Numeric data type.
When using unary operator on object, the underlying value property of the object is modified.
Example:
var uv = new UnitValue(2, "px");
"-uv" will result in uv.value modified from "2" to "-2" and stays as Numeric data type.
Any unary operator on object as whole will return the object itself.
Alternatively you can achieve the result you expected by directly manipulating the value instead of the object
var uv = new UnitValue(2, "px");
"-uv.value" this will return the Numeric data type with negating the value, in this case it will convert the number 2 to -2
I do see it is working as documented, I would like to hear your view with the above information.
Unary operators (~, !, +, -)¶
Operator Behaviour
+unitValue
Result is the numeric value.
-unitValue
Result is the negated numeric value.
This implementation is based on the Ecmascript standard - https://tc39.es/ecma262/multipage/ecmascript-language-expressions.html#sec-unary-plus-operator
-
Nihiltres, this documentation has to be updated in couple of places.
I created a PR with the changes here, will wait for review and then will merge - https://github.com/docsforadobe/javascript-tools-guide/pull/13
I am working on updating the PDF documentation and it may take some time, will post an update once it is done.
-
Nihiltres commented
Thank you; I know how to use operators. I am saying that the documentation is misleading. Specifically, I'm complaining about the table at https://extendscript.docsforadobe.dev/extendscript-tools-features/specifying-measurement-values/#unary-operators-
The entry in the linked table currently says for the ~ operator "The numeric value is converted to a 32-bit integer with inverted bits.", which implies that it returns a UnitValue object with a mutated value property. That's accurate enough. Similarly, the entry for the ! operator is accurate because the result is in fact a boolean value.
The entries for the + and - unary operators say "Result is the numeric value." and "Result is the negated numeric value." respectively, which is inaccurate: the result is not the (negated) numeric value but a UnitValue with no change or a negated value respectively.
If you want to base the implementation on the ECMAScript standard, then you should change the behaviour so that the + and - unary operators return Number values as specified by the standard. This would be desirable at minimum for the + unary operator, because as currently implemented, its *only* effect is to copy the original. The + unary operator is frequently used in JavaScript as shorthand for a conversion to Number type, and the current design does not work with that pattern.
However, since changing the effect of operators may break any extant scripts that rely on the current behaviour, it's likely undesirable to change the behaviour. That's why I suggested updating the documentation instead.
If I had the power to fix the documentation myself, I would change "Result is the numeric value." to "Result is a new UnitValue with the same type and value as the original" and change "Result is the negated numeric value." to "Result is a new UnitValue with the same type and negated value from the original". Those are clear, correct ways to describe the current behaviour. I would also change the entry for the ~ operator to read instead something like "Result is a new UnitValue with the same type, but value converted to a 32-bit integer and inverted bitwise."
Even if it's possible to *interpret* the current wording in a way that reflects the behaviour, my complaint is itself evidence that some people are mislead by that wording. Therefore, it would be an improvement to change the wording. :)
-
Nihiltres commented
The issue is important not so much because it is a bad bug to work around but because it is directly misleading. I spent needless time debugging my script because I eliminated other possibilities before testing whether the built-in features functioned as described.
As a minor addendum: the "~" unary operator also produces a modified-UnitValue result instead of a numerical result, and it should have either its behaviour or documentation updated too.
-
Sergey Osokin commented
I agree that the text in the official reference is misleading. Although it's not a problem to convert the object type to a number using Number() or the .as() > new UnitValue(2, "px").as("px") method and then change the sign of the number