Re: [css-values] Concrete proposal for unit algebra in calc()

On Thu, Apr 10, 2014 at 12:43 PM, Zack Weinberg <zackw@panix.com> wrote:
> I brought up the question of being able to divide two <length>s in
> calc() earlier this week, along with min/max expressions.  I'm
> convinced min/max are Too Hard for right now, but I think it's not too
> hard to specify enough unit algebra to make <length> ratios feasible.
> Here is a concrete proposal relative to the current ED.
>
> In section 8.1.1 (calc() syntax):
>
> -  product : unit [ S* [ "*" S* unit | "/" S* NUMBER ] ]*;
> +  product : unit [ S* [ "*" S* unit | "/" S* unit ] ]*;
>
> In section 8.1.2 (type checking), replace the second two bullet points
> in the list with the following:
>
>  * At '*', apply these rules in order:
>
>    1. If both sides are <integer>, resolve to <integer>.
>    2. If one side is <number> and the other is <number> or <integer>,
>       resolve to <number>.
>    3. If one side is <number> or <integer> and the other is a
>       _dimension_, resolve to the type of the _dimension_.
>    4. If one side is <time> and the other is <frequency>, resolve to
>       <number>.
>    5. If one side is <length> and the other is <resolution>, resolve
>       to <number>.
>    6. All other combinations of units are invalid.
>
>  * At '/', apply these rules in order:
>
>    1. If both sides have the same type, resolve to <number>.
>    2. If the left side is a <number> or <integer> and the right side is
>       also a <number> or <integer>, resolve to <number>.
>    3. If the left side is a _dimension_ and the right side is <number>
>       or <integer>, resolve to the type of the _dimension_.
>    4. If the left side is a <number> or <integer> and the right side
>       is a <length>, resolve to <resolution>.
>    5. If the left side is a <number> or <integer> and the right side
>       is a <time>, resolve to <frequency>.
>    6. All other combinations of units are invalid.

So this does require you to manually keep the units singular, right?
You're not allowed to write "calc(1px * 2px / 3px)", because due to
order-of-operations you'll first evaluate the multiplication and hit
clause 6.  You'd have to reorder to "calc(1px / 3px * 2px)" or add
parens to "calc(1px * (2px / 3px))" to produce a valid expression,
right?

I'm okay with this, as it keeps the implementation much simpler, just
making sure that's intended.

> Also, replace from "Also, division by zero is invalid" through the end
> of that paragraph with:
>
>    ... The expression is also invalid if it contains a division by
>    zero which can be detected at parse time.  For example,
>    `calc(10px/0)` and `calc(10px/(1em - 1em))` are both invalid.
>    However, `calc(10px/1em)` and `calc(10px/5%)` are *not* invalid,
>    even though `1em` might evaluate to zero when the value is
>    computed, and `5%` might evaluate to zero when the value is used.
>
> In section 8.1.3 (computed value), delete the note about the
> representation of a computed calc(), and perhaps also add some more
> examples.
>
> In section 8.1.4 (range checking), add immediately after "...to the
> range allowed in the target context":
>
>     If a (sub-)expression contains a division by zero which was not
>     detected at parse time, the value of that (sub-)expression is
>     infinite.  The result of any further computation on infinite
>     values is also infinite, except that dividing any finite value
>     by an infinite value produces zero.
>
>     If the value resulting from a complete `calc()` expression is
>     infinite, it is clamped and becomes the most positive value
>     allowed in the target context.
>
> | NOTE: This deliberately differs from the behavior specified in IEEE
> | 754 in order to avoid introducing NaNs and negative zero into CSS,
> | However, implementations using IEEE 754-conformant floating point
> | arithmetic internally can produce the above semantics by treating
> | -Inf, +Inf, and NaN as "infinite", and -0 as equivalent to +0.

This "most positive value" will be implementation-defined in most
cases, as very few value contexts actually have an upper cap.  Is that
acceptable?

~TJ

Received on Thursday, 10 April 2014 21:21:02 UTC