W3C home > Mailing lists > Public > public-houdini@w3.org > May 2017

[Houdini] Minutes Tokyo F2F 2017-04-18 Part II: Typed OM

From: Dael Jackson <daelcss@gmail.com>
Date: Mon, 15 May 2017 04:41:20 -0400
Message-ID: <CADhPm3sU98OLJVa5rX=sodarFeCD9meWOHKGACpKXkRg-a8D-Q@mail.gmail.com>
To: public-houdini@w3.org
Cc: www-style@w3.org
   These are the official Houdini Task Force
     minutes. Unless you're correcting the
      minutes, please respond by starting
 a new thread with an appropriate subject line.

Typed OM

  - TabAtkins proposed a new approach to numeric values:
  - RESOLVED: Adopt Tab & Shane's new proposal for value API as an
              improvement over the current proposal; issues around
              cases requiring an AST might, however, require further
              revision of the design. [Note: This resolution was
              overridden by the CSSMathValue one below.]
  - RESOLVED: Use iterable (option 2) for Array-like CSS interfaces,
              unless/until Proxies become more performant.
  - RESOLVED: inline style attribute map is also live
  - RESOLVED: Custom properties that have an initial value show up
              in computed style, warn authors about perf issues if
              they type everything all the time
  - RESOLVED: For inline style, should return the custom properties
              that are set on the inline style of the current node
  - RESOLVED: For specified style, should return the custom
              properties defined in the current rule
  - RESOLVED: For computed style, should return all defined custom
              properties on the current node (including inheritance)
  - RESOLVED: Be consistent about null vs throw in all three
              .parse() syntax error cases; follow TAG guidelines
              once they have them.
  - RESOLVED: Replace previously-resolved value API with
              CSSNumericValue tree.
              * CSSNumericValue has two subclasses: CSSMathValue and
              * CSSMathValue has two members:
                  - operator, a string representing a math op like *,
/, min, max, +
                  - operands, a list of CSSNumericValue.
              * CSSNumericValue has a method called toSum which
                  returns a map of units to numbers representing a
                  sum of those dimensions, as previously discussed
                  in Tab & Shane's proposal above. If the
                  CSSNumericValue cannot be so reduced, it either
                  returns null or throws, whatever the TAG decides.
  - RESOLVED: Using properties is moved to L2
  - RESOLVED: Name style maps accessed via element.attributeStyleMap
              and element.computedStyleMap, with attributeStyleMap
              maybe renamed later. Pseudo-element styles accessed
              through PseudoElement APIs.
  - RESOLVED: Update Typed OM draft on /TR with above edits.


Agenda: https://github.com/w3c/css-houdini-drafts/wiki/Tokyo-F2F-April-18-2017

Scribe: fanasai

Typed OM

Numeric Values Rethink

  <TabAtkins> https://docs.google.com/presentation/d/1s1LgVKntulttemMacBMbErOAc0UQzLbdol4rQbQf-aw/edit?usp=sharing
  TabAtkins: Why I changed everything about how we did numeric
  TabAtkins: Previous number type looked like this: attribute double
  TabAtkins: Previous simple length was similar, added readonly
             LengthType type;
  TabAtkins: calc() was a structlike structure with em, px, etc.
  TabAtkins: Angle values were similar to calc() but looked like a
             length. Automatically converts between units.
  TabAtkins: This is a problem.
  TabAtkins: We have 3 different unit things that have dramatically
             different representations.

  TabAtkins: Length version is very nice for setting up arbitrary
             units. Not bound to unit types we have exposed.
  TabAtkins: No updating needed to support new units.
  TabAtkins: calc() is nice because it supports sum of values.
  TabAtkins: And angle has great auto-conversion.
  TabAtkins: But the differences make the system weird.
  TabAtkins: ...
  TabAtkins: Even then, what we added wasn't good enough.
  TabAtkins: We're adding unit algebra into calc() soon.
  TabAtkins: px/em needs to remain as px/em, couldn't do that with
             old calc interface.
  TabAtkins: And also mixing number.
  TabAtkins: It also doesn't support custom units.
  TabAtkins: Could set that in unit type, but can't do it in calc()
  TabAtkins: Can't do that in angles, same problem.
  TabAtkins: Bad for various reasons.

  TabAtkins: So I rewrote everything into a new structure that
             replaces everything.
  TabAtkins: Replace it with two classes, plus superclass.
  TabAtkins: First one is for dimensions/percentages/numbers
  TabAtkins: Other is for calc.

            interface CSSUnitValue: CSSNumericValue {
                attribute double value;
                attribute DOMString unit;
                readonly attribute DOMSTring type;
  TabAtkins: This handles everything that is a dimension
  TabAtkins: it handles custom units, in future
  TabAtkins: also handles number and percent.
  TabAtkins: It becomes a problem if we create a unit named "number"
             or "percent", but that's unlikely.
  TabAtkins: Type is used internally to maintain length/angle/number
  TabAtkins: so that can throw if there's a type mismatch, etc.
  smfr: What about z-index?
  TabAtkins: Those are numbers.
  TabAtkins: Integer inputs will clamp numbers
  <TabAtkins> calc(5px + 2em) => {"px": 5, "em": 2}

  <astearns> https://www.irccloud.com/pastebin/Db0ATwfQ/
  TabAtkins: ^ represents calc
  TabAtkins: with input validation.
  TabAtkins: ...
  dbaron: How is this going to extend to calc(3px*2vw/2em)?
  TabAtkins: Each such expression can be turned into simple sum of
             complex units.
  TabAtkins: Those will just be strings.
  several people: :/
  <shane {"px*vw/em": 3}
  TabAtkins: I know of literally no better way to do it.

  plinss: How are you storing the operators?
  TabAtkins: Every calc can decompose into a sum of united values.
  dbaron: Not quite that obvious
  dbaron: if you have a sum in the denominator.
  dbaron: It's a logical piece of unit algebra
  dbaron: We already have a resolution to add unit algebra to L4.
  <dbaron> calc(4em / (2em + 2px))

  fantasai: What about handling min()/max()?
  shane: ...
  TabAtkins: Yeah, you can produce expressions that don't reduce
             well... would need to produce a tree.

  plinss: You're decomposing multiplication into addition?
  TabAtkins: No, you distribute
  TabAtkins: Unless you have a sum in the denominator, would work
  shane: min/max would need a different approach.

  shane: Advantage of this interface is that all calc expressions
         today, and majority in the future, can be represented here.
  shane: Very useful for interrogating through script.
  shane: Just says what units are expressed in the calc.
  shane: It's a compromise between map and string representations.
  shane: Shame we can't express every single calc expression, but
         this still captures most of them.
  TabAtkins: Will have to change some parts of sub-expressions as an
  <TabAtkins> calc(5px + 2em/(5% + 10px)) => {"px": 5}, + AST for
              the second half
  shane: It would be a tree representation.
  shane: A real pain to deal with in script.
  <iank> {type: 'div', numerator: {type: 'value', value: '4em'},
         dem: {type: 'plus', value: [{type: 'value', value: '5%'},
         {type: 'value', value: '10px'}]}}
  <iank> ^ a bad AST representation of dbaron example

  jack: So this will be able to represent all?
  jack: If some will be represented as complex strings, how is that
        better than now?
  TabAtkins: Every single calc you can express today is decomposable
             into sum of simple units
  TabAtkins: so simple units as keys.
  TabAtkins: Only get arithmetic in the units if doing unit math.
  shane: ...
  shane: These are like channels, each unit is a channel.
  shane: Complex units, except those with sums in the denominator,
         are the same concept.

  till: What would be representation for 100% - 50px
  <TabAtkins> calc(100% - 50px) => {"percent": 100, "px": -50}
  shane: percent: 100; px: -50
  shane: This works nicely if you add, -25% + 50% you end up with

  SimonSapin: So the way to output is to make a sum?
  SimonSapin: That's not obvious, maybe put sum in the name? e.g.
  TabAtkins: Not sure that's necessary
  fantasai: Seems reasonable to me. We might in future want to
            represent calc as the tree that it was.
  fantasai: Since this represents a simplification of the calc,
            reasonable to express that in the type name.
  shane: I'm okay with that.
  shane: I also think that we can extend this to represent the
         remaining cases that haven't been specced yet by having an
         AST member in this that represents the full tree.

  fantasai: That sounds great, but my concern is how are we dealing
            with min & max?
  fantasai: Want to see how that fits into this interface.
  TabAtkins: Didn't draw that up yet.
  shane: Let's sit down at lunch and figure that out
  TabAtkins: Just want to point out that old proposal didn't deal
             with this either, this is an improvement in any case.

  till: How do vars figure into this?
  TabAtkins: It's represented as an unparsed value instead.
  shane: That's only for non-computed style uses.

  <dbaron> [moved on to slide 10]
  TabAtkins: Once the var substitutes, you'll get a proper whatever.
  TabAtkins: Superclass has stuff that all values should be able to
             interface CSSNumericValue : CSSStyleValue {
                 CSSNumericValue add(CSSNumericValue value);
                 CSSNumericValue subtract(CSSNumericValue value);
                 CSSNumericValue multiply(double value);
                 CSSNumericValue divide(double value);
                 bool equals(CSSNumericValue value);
                 CSSNumericValue to(DOMString unit);
                 static CSSNumericValue parse(DOMString cssText);
  TabAtkins: Math is awkward, let's do it for you
  TabAtkins: When necessary will pop out a calc value, but in simple
             cases won't.
  TabAtkins: e.g. adding two px values results in a px value.
  TabAtkins: adding px plus percent gets you a calc().

  TabAtkins: This is very strict at the moment.
  TabAtkins: Will tell you that 5px and 5px are equal.
  TabAtkins: Will not tell you that 96px and 1in are equal.
  TabAtkins: Also won't tell you that a unit value of 5px and calc
             value of 5px are equal.
  ChrisL: Why?
  TabAtkins: Question is why you would want to compare things.
  TabAtkins: Examples we could tell, probably didn't want to do a
             loose equality.
  TabAtkins: That said, okay with adding.
  ChrisL: Was wondering why. Doesn't seem hard.
  TabAtkins: Not hard, but didn't seem to fit with uses.
  fantasai: Seems to me you would want to have the ability to do
            equivalence matching.
  TabAtkins: Wanted to match with what would happen with JS value
  fantasai: That's fine. I think you just probably want both.

  TabAtkins: If there's even remotely realistic case, would add
             interface that'll do conversion equality.
  TabAtkins: We might not need to add that except as a convenience,
  TabAtkins: because to() function will convert from one type to
             another, so long as it's possible.
  TabAtkins: Throws if it can't, e.g. not enough info.
  TabAtkins: Loose equality would just be a convenience function,
             could otherwise convert both things to the same unit.

  leaverou: ????
  TabAtkins: If you're dealing with computed values, already
             resolved away. If dealing with specified values, keep
             them as the types that you're looking at and they'll
             resolve later on.
  shane: Should to() let you cast to combinations of units as well?
  TabAtkins: Send it to em+px? Would produce a calc for that?
  TabAtkins: That's not the worst idea. Open an issue for me?

  TabAtkins: Last function is parse()
  TabAtkins: Will turn it into a CSSNumericValue.
  leaverou: calc(1px + 2px)?
  TabAtkins: You get calc value of 3px. calc(3px)
  TabAtkins: Use the math functions if you want ...
  leaverou: If calc(3px) is equivalent to 3px, should output 3px.
  TabAtkins: Also logical to maintain the calc() that was your
             source input.
  shane: Calc expression at one end and the other, animating between.
  shane: Just because one of them hits zero at some point in the
         middle, don't want the calc() wrapper to suddenly disappear.
  Rossen: Also want to be able to round-trip it for tooling.

  SimonSapin: parse() function takes CSS syntax?
  TabAtkins: Yes. Invokes Syntax module algorithm.
  SimonSapin: Is there a way to create without parsing?
  TabAtkins: Yes, they all have constructors.
  TabAtkins: CSSCalcValue has two constructors. Takes a dictionary.
  TabAtkins: Other one also should take a map iterator, but
             specifying that in WebIDL is really messy right now.
  TabAtkins: So put an issue that when WebIDL makes that better,
             let's add it.

  till: So if calc() is always for sums, why not call it CSSSumValue?
  till: Then can have a CSSProductValue.
  TabAtkins: Don't think we have a CSSProductValue.
  TabAtkins: Also like that it matches up to the functional notation

  iank: With the to() function, converting 1em to px, that would
  iank: At some point could add a dictionary to have the conversions
  iank: So you could specify what an em is.
  fantasai: You would want to have the layout engine and the JS use
            different conversion factors?
  TabAtkins: You would pass an element, or an element and property,
             for reference on how to convert the units.
  shane: We have a typed-om-2 label in the issue tracker, so file
  SimonSapin: You mentioned resolving value of an element against a
              property, including percentages, does that include
              percentages resolved during layout?
  TabAtkins: Theoretically?
  TabAtkins: Definitely L2, can work out details later.
  SimonSapin: If you do that probably want it to be asynchronous.
  iank: Could provide utility methods for resolving e.g. inline size.
  iank: Because we don't want ppl to go through writing modes.
  iank: ????

  TabAtkins: We put it into the ED, if anyone objects, will take it
             out :)
  TabAtkins: Meade from Chrome is working on it.
  astearns: Anyone from Gecko?
  dbaron: No idea.
  <till> dbaron: based on https://bugzilla.mozilla.org/show_bug.cgi?id=1278697,
         I don't think anybody's working on typed OM
  TabAtkins: This has been in the spec for ~2months
  <astearns> it wouldn't be the worst idea to have a resolution
  fantasai: I'm happy to resolve on this, so long as we note that
            the max/min investigation might result in further

  SimonSapin: Cases not supported by maplike calc, do we have a plan
              for another API?
  TabAtkins: Gonna discuss with shane over lunch
  TabAtkins: Those parts can hang off in the AST
  SimonSapin: So some parts of the calc will be represented in the
              sums, but not all?
  TabAtkins: Yeah
  <shane> I think everything would end up in the maplike, it's just
          some of the bits wouldn't map to numbers.
  fantasai: That seems really bad.
  TabAtkins: Previous approach was worse
  fantasai: happy to replace previous approach with this one, but
            this one still has issues with calc that we need to fix
  shane: could have a key for the extra bits
  Rossen: objections?

  RESOLVED: Adopt Tab & Shane's new proposal for value API

  Rossen: Please file those key issues mentioned so the draft
          doesn't progress without them addressed.

Array-like Frustrations

  <TabAtkins> GitHub Topic: https://github.com/w3c/css-houdini-drafts/issues/239
  <TabAtkins> https://docs.google.com/presentation/d/1pXoJ4vqRfjww7xJ8DYTYk8LBu0kGyGyg0yZm88w8xBw/edit?usp=sharing
  TabAtkins: Couple interfaces in typed OM, e.g. CSSUnparsedValue,
             CSSTransformValue, that are just sequences of other
             values. They have other extra data, e.g. transform has
             an equivalent matrix.
  TabAtkins: But at their core, they are sequences of values. So
             they really want to be arrays.
  TabAtkins: Really want to use array notations.
  TabAtkins: But making something array-like, only way is to use
             Proxies, which are slow and not desired by implementers.
  TabAtkins: Annoying because maps and sets are easily faked.
  TabAtkins: WebIDL is also broken, can't even do iterables without
             invoking Proxies.
  TabAtkins: WebIDL is doing something very stupid for bad reasons. (
             I'm gonna be really judgmental here.)
  TabAtkins: Wanted to go over these issues.
  SimonSapin: Can we fix WebIDL?

  TabAtkins: First option is suck it up, use LegacyArrayClass.
             Invokes Proxy. Not great.
  TabAtkins: It also means that any Array methods that return an
             array, return a real array, not an instance of our
  till: That shouldn't be true anymore with species.
  TabAtkins: That's option 3 :)
  TabAtkins: I don't want to do Option 1, but it is a possibility.

  TabAtkins: Option 2 is Use iterable
  <shane> Not an array, but can be turned into one: let arr =
  <shane> As written today, would still invoke Proxy; it’s written
          to require indexed properties. Totally fixable, just
          hasn’t been fixed yet in WebIDL.
  <shane> (kv-iterator doesn’t act badly like this. It can be fixed!)
  <shane> Probably good enough, at least as a first step.
  TabAtkins: This lets you iterate in a for loop, or to cast things
             into an array.
  TabAtkins: It's okay as a first step.
  TabAtkins: Fairly easy to get to.
  TabAtkins: Problem is WebIDL value iterators, which is what we'd
             use here, still requires Proxy.
  TabAtkins: ....
  TabAtkins: So WebIDL needs to be fixed.
  TabAtkins: This would be okay.
  TabAtkins: Could also hack around key-value iterator. Doesn't have
             the problems. But it's a hack.
  TabAtkins: This is a possible solution, particularly in ES6
             casting is easy.

  TabAtkins: Option 3 is desirable one which is ES spec now has
             proper subclassable arrays.
  TabAtkins: Similar to previous step, but it's a real Array.
  TabAtkins: Will also return the correct subclass from Array
  ChrisL: Which version of ES spec did that come from, and can you
          compile this down to ES6?
  till: It's ES6 and it is implemented in all engines.
  TabAtkins: Not fixed in WebIDL yet.

  TabAtkins: Only problem with this is that you still can't
             intercept a set operation, like you can with maps.
  TabAtkins: So people can put random crap in your interface
  TabAtkins: e.g. CSSUnparsedArray is suppoed to only have strings
             and ??
  TabAtkins: Not sure what to do with that, do we throw when you add
             something that's invalid?
  TabAtkins: Most of the time you can sanitize at ...
  leaverou: If the issue is that people can mess with your types,
            that's just how JS works.
  TabAtkins: In maplike, in calc(), because it has an impl of set
             method, can do type checking and tell you if you're
             doing something wrong right away.
  TabAtkins: If you're setting an arbitrary object to px key, will
             throw, because not a number.
  TabAtkins: Doesn't look correct, and then later when you're
             setting into a property map, break down.
  leaverou: That's their own fault.
  TabAtkins: But we still have to handle correctness.
  TabAtkins: And we'd have to handle it via checking every set,
             iterating over it, even in cases where you haven't done
             anything wrong, which is more computation than is
  TabAtkins: If you're strict at the start, then we don't have to do
             such extra checks.
  till: I think you fundamentally want Proxies to implement that.
  <TabAtkins> AWB had a proposal to let you hook the [] syntax, but
              that's never gone anywhere. :(

  shane: At least with proposal 2 the only time we need to check
         correctness is on construction, and that is very ...
  shane: We wouldn't be in a situation where every time we need to
         use contents we typecheck them.
  TabAtkins: So I think we should go with option 2 for now, and then
             in future, go into Array subclassing.
  Rossen: What would prevent us from going to Array subclassing in
          the future?
  TabAtkins: Only if you're doing exotic checks on whether it's an
             array or not.
  TabAtkins: If just iterating over it, won't notice the difference.

  till: The performance on Proxies might not be that much of a
        problem going forward.
  till: Engines are doing pretty good optimizations nowadays
  till: If all you have is a set hook, then should be optimization.
  TabAtkins: I was told that's not the case.
  iank: I was told we're not going to be able to make Proxies fast
        anytime soon.
  till: in the general case, that's true, but this isn't the general
  TabAtkins: If good news comes out, ok to change, but for now would
             go with option 2.
  Rossen: So you're proposing to go with option 2.
  Rossen: Any objections?
  Rossen: Anyone for option 3 at this point?

  RESOLVED: Option 2- Use iterable

Remaining Typed OM Issues

  <shane> Issues list:
  shane: 7 issues that need discussion
  shane: #239 and #359 just discussed

Issue 149: Describe that StylePropertyMaps are not live objects
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  <shane> Topic: https://github.com/w3c/css-houdini-drafts/issues/149
  shane: We resolved in September of last year that the specified
         and computed style maps were live.
  shane: So if you made changes not through typed OM, would see
         those changes reflected in the map.
  shane: We did not discuss inline style map.
  shane: I assume that would be live as well, anyone disagree?
  dbaron: I consider that one case of the specified style.
  shane: Same as specified style in the sense that represents
         specified style, but has different backing model.
  Rossen: If we're making specified style live, inline is just

  RESOLVED: inline style attribute map is also live (Issue 149)

StylePropertyMaps wrt custom properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  <shane> Topic: https://github.com/w3c/css-houdini-drafts/issues/276
  TabAtkins: We need to clarify how style map works with custom
  TabAtkins: Suggestion from shane is that for style attributes,
             custom properties set in style attr should be included.
  TabAtkins: For style rule, include those custom properties in that
             style rule.
  <shane> For inline style, should return the custom properties that
          are set on the inline style of the current node
  <shane> For specified style, should return the custom properties
          defined in the current rule
  <shane> For computed style, should return all defined custom
          properties on the current node (including inheritance)
  TabAtkins: [reads what shane posted]

  iank: If you register a custom property, it won't show up
  TabAtkins: No.
  shane: What if you registered it with an initial value?
  iank: That's what I meant.
  TabAtkins: That's a good question.
  iank: ...
  dbaron: That has a computed value then, so it should show up.
  shane: Just in computed value then, not in specified/inline.
  shane: I wonder if we want to allow having an invalid initial
  TabAtkins: You can, have an unregistered property with grammar of *
  SimonSapin: What happens in old style CSSOM?
  TabAtkins: Undefined, but hopefully consistent.
  iank: It would make sense that all registered properties appear in
        computed style maps.
  TabAtkins: [...]

  shane: One pattern we've seen with untyped custom properties is
         that people use them like macros.
  shane: They put a lot of them at the root node
  shane: to represent colors that might be used on the page, etc.
  shane: Not uncommon to see pages with one or more custom
         properties defined.
  shane: Relatively easy to keep performant if not referenced much
  shane: But could be an issue for typed properties if the same
         pattern used, because significantly increases size of
         computed value map.
  shane: It would be bad if people typed their untyped custom
  shane: At the very least, should provide suggestion that ppl don't
         do that.
  shane: But might want to look into CSS API for that.
  TabAtkins: Currently only JS api for registering, so most of these
             cases likely won't do that...
  shane: So, should typed custom properties show up in computed

  RESOLVED: custom properties that have an initial value show up in
            computed style, warn authors about perf issues if they
            type everything all the time
  RESOLVED: For inline style, should return the custom properties
            that are set on the inline style of the current node
  RESOLVED: For specified style, should return the custom properties
            defined in the current rule
  RESOLVED: For computed style, should return all defined custom
            properties on the current node (including inheritance)

  iank: We also may come back later with impl experience to say this
        was a terrible idea, but we'll see.

SSStyleValue.parse(): throw vs return null?
- - - - - - - - - - - - - - - - - - - - - -

  <shane> Topic: https://github.com/w3c/css-houdini-drafts/issues/305
  TabAtkins: When you call CSSStyleValue.parse()
  TabAtkins: parses arbitrary string into typed OM value.
  TabAtkins: Takes a property name and a value.
  TabAtkins: Several ways to do something wrong, not sure whether to
             throw or return null.

  TabAtkins: 1st case is, property is not even an identifier.
  SimonSapin: If property is a separate arg, not parsed out from
  SimonSapin: Then do you even need to parse it?
  SimonSapin: For CSS.supports(), we have API with 2 variations.
  SimonSapin: One with colon syntax, uses CSS syntax.
  SimonSapin: Other one passes prop and value separately
  SimonSapin: In that case you don't parse it,
  TabAtkins: ...
  SimonSapin: Just assume it's an ident,

  TabAtkins: Yes, that avoids the issue entirely.
  iank: Might want to throw on the empty string.
  iank: We throw a SyntaxError on that.
  SimonSapin: Empty string is not valid property name.
  iank: It's not a valid function name.
  SimonSapin: Are we talking about property names.
  iank: First argument in custom paint is an ident, same issue.
  shane: What does supports() do with empty string?
  SimonSapin: Supports method, you can give it custom property, in
              which case name starts with --

  shane: There are 3 different error conditions.
  shane: 1st, not a valid property name. If that's just empty
         string, still.
  shane: 2nd, valid property name, but doesn't exist. Can only
         happen for non-custom properties.
  SimonSapin: Could treat those the same.
  shane: 3rd, valid property name, but value's grammar doesn't match.

  shane: I thought 2 & 3 were the same, but both of them could be
         that you're simply running on a browser that hasn't built
         support for that syntax yet.
  TabAtkins: Taking the property name makes it not an error.
  shane: Could treat them all the same, and throw.
  Rossen: It would be easier to handle null from user side.
  Rossen: Rather than wrapping everything in try for parsing all
          over the place.
  Rossen: 1 & 2 are more of an error than 3.
  Rossen: 3 is you're parsing a value that you can't parse.
  shane: But both 2 & 3 could be that you're trying to parse a
         feature that the browser doesn't yet support.

  dbaron: It does feel like the more CSS-ish thing to do, not to
          throw for unsupported values or properties.
  dbaron: In normal CSS, they get silently dropped
  dbaron: so null seems more sensible.
  shane: Note that we throw if you set a value that doesn't parse
         according to your type already.
  dbaron: If mistyped things throw, then unknown things should
          throw. I would agree with that.

  philipwalton: My intuition is, you don't want to both try-catch
                and check for null when you're writing code.
  philipwalton: I think there are many cases you want try-catch, so
                throwing an error is probably best.

  <astearns> what about not throwing, but returning a value that
             throws an error when you try to read it? Could that be
             the worst idea?
  <TabAtkins> Worst idea, yes.
  <TabAtkins> Value that can validly be used, but represents a
              random property/value.

  shane: Rossen, you were leaning towards null before. What do you
         think now?
  Rossen: Not gonna object, but not gonna love it.
  iank: What's your hesitation?
  Rossen: More of a philosophical discussion.
  Rossen: I'm very biased to the APIs we work on on the Windows
  Rossen: We have strict principles on what is an error, how to deal
          with errors, how to make API that is ergonomic for
  Rossen: Don't want to sprinkle try-catch all over, half is
          error-handling, half is business logic.
  Rossen: We have strict rules to guide our APIs. Not gonna impose
          those here.
  fantasai: Might be worth having that philosophical discussion
  fantasai: and codify some principles for our APIs, whether same or
            different from Windows API principles

  shane: Inconsistent to return null here.
  shane: You then set this value, want to throw an error here
         [missed exactly the nuance there]
  <dbaron> I think Shane was saying that it's not as inconsistent as
           he thought it was before.
  <shane> yup. When we set values we need to throw an exception on
          error because there's no return value
  <dbaron> because the other case was setting an object and getting
           a type mismatch, whereas this is parsing a string.
  <shane> but here we're getting the result as the return value so
          we can use null to signal an error

  iank: Does TAG have any guidance?
  plinss: We have a document discussing principles for designing
          APIs, but don't have anything on this topic.
  Rossen [offers to review that? send feedback? something?]

  Rossen: So going back.
  Rossen: Are you reverting your opinion about throwing vs null?
  shane: Yeah.
  shane: I'm going back from saying we should throw to not having a
         strong opinion.
  Rossen: Does anyone have a strong opinion?
  philipwalton: Likely to do this in environment where you don't
                know what you're getting
  philipwalton: so maybe throw.
  Rossen: Think about it from a mid-layer library, start exposing
          some of those.
  Rossen: First they're going to write their own wrapper that does a
  Rossen: are going to call that so they don't have to deal with
          throw/catch all over.
  Rossen: If that's the principle we design around, okay.
  Rossen: ...

  fantasai: Sounds like we should table discussion and have your
            philosophical discussion about throw vs null?
  plinss: To me, throwing is semantically different than returning
          an error.
  plinss: If you pass in a property that isn't an ident, e.g.
          numbers, can't possibly be a property name. Could see an
  plinss: But if passing a name that's unknown to the engine, then
          return null.
  plinss: Not recommending that's what we do, but there's a
          distinction between throwing errors and returning null,
          and it's useful to make that distinction.
  TabAtkins: If you do construct a value that doesn't make any
             sense, and you return null. Whatever you do with that
             will throw an error.
  TabAtkins: All you can do is check for null.
  plinss: Throwing is for exceptional circumstances like out of
  plinss: I've tried using it for everything, and that way lies
  plinss: For a certain class of things, throw exceptions, and be
          consistent about it.
  plinss: We need some guidance on that, and we don't have it.

  iank: I was just looking through a few of the Web apis, like
  iank: Dae.parse() does not ... seems like more things throw than
        silently fail.
  iank: HTML throws if not well-formed.
  iank: Could file an issue on the TAG.
  shane: Let's do that.
  Rossen: Let's resolve with following -- in all three cases we will
          be consistent in how we handle the condition.
  Rossen: And we will follow the TAG guideline on whether to throw
          or return null.
  <dbaron> The TAG guidance might not be all that prescriptive...
  <plinss> https://github.com/w3ctag/design-principles/issues/55

  RESOLVED: Be consistent in all three cases; follow TAG guidelines
            once they have them.

<br type = lunch>

Numeric Values Rethink Revisited

  <dbaron> Github topic: https://github.com/w3c/css-houdini-drafts/issues/359
  shane: We came up with a proposal over lunch.
  shane: Getting rid of previous proposal that we resolved on
  shane: and replacing it with CSSNumericValue which has two
         subclasses: CSSMathValue and CSSUnitValue
  shane: CSSMathValue has two members, operator and operands
  shane: operator is a string representing a math operator like "*"
  shane: *, /, min, max, +
  shane: operands is a list of CSSNumericValue.
  shane: CSSNumericValue has a method called toSum which returns a
         map of units to numbers
  shane: representing a sum of those dimensions, as previously.
  shane: If the CSSNumericValue cannot be so reduced, it either
         returns null or throws, whatever the TAG decides.

  SimonSapin: If the initial syntax uses unnecessary parentheses or
              calc() inside of calc(), do we want the tree to
              preserve that information?
  TabAtkins: I would prefer we don't.
  <TabAtkins> calc(1px + (2px + 3px)) => CSSMath("+", [1px, 2px,
  fantasai: I agree, because people put parenthesis when they want
            to clarify something, not just when they have a
            grouping, e.g. calc(1px + (2*2px))

  xidorn: Do we want to distinguish between 3px and calc(3px)?
  TabAtkins: Yes, and we'll probably default it to the plus operator.

  plinss: Going back to unnecessary parens, I think we should
          preserve that structure.
  plinss: If author wants to reduce, can use toSum()
  plinss: E.g. 2*3em, they did that for a reason.
  TabAtkins: Don't have a problem with it, but would mean
             operator(+,[operator(+, [2px, 3px])])
  <TabAtkins> Which would mean calc(1px + (2px + 3px)) =>
              CSSMath("+", [1px, CSSMath("+", [2px, 3px])])
  shane: Any code dealing with this would have to recurse anyway.
  TabAtkins: There's no non-broken code you could write that would
             break on extra parens being preserved.
  plinss: So let's preserve structure.
  SimonSapin: So no distinction between nested calc() and nested
  TabAtkins: We don't even when serializing, so no.

  shane: What do you do when animating between calc(5px + (4em +
         2%)) and calc(10px + 10em + 10%)
  TabAtkins: Animations are computed value anyway, and so they're
             necessarily reduced -- they're produced by the engine,
             not by the author.
  TabAtkins: The beginning point can be unit value, endpoint a
             calc(). What's in between? Engine decides.

  fantasai: Tab, since you were concerned about typing, could
            consider CSSMathValue as a listlike type, and .op as the
            operator member.
  TabAtkins: No, it's fine.

  SimonSapin: Earlier were talking about Proxy for arraylike stuff.
  SimonSapin: if it's not used here, where is it used in CSSOM?
  TabAtkins: TransformValue and UnparsedValue.
  SimonSapin: Why do we want to do something different here?
  TabAtkins: Semantically different -- this is an operator, and
             arguments to that operator. Those are fundamentally
  iank: So this proposal is completely replacing the CSSCalcValue
        stuff we discussed earlier?
  TabAtkins: Yep, throw it away.
  iank: So you wouldn't have any of those complex units like em*ch.
  iank: Right.

  TabAtkins: Still want to handle custom units whenever they exist.
  TabAtkins: Also may want to handle case-insensitivity.
  fantasai: Custom idents are case-sensitive.
  TabAtkins: Note in the spec that we don't have custom units yet,
             but plan to.

  Rossen: Sounds like ppl are happy with this?
  fantasai: Share Tab's earlier concern about operator and operand
            being perhaps a bit too long to type, but otherwise
            seems okay to me.

  [SimonSapin asks how percents represented]
  TabAtkins: As "percent". Didn't use "%" so that it wouldn't be
             weird to use as a .name

  plinss: Unitless zero?
  TabAtkins: Custom stuff can't use unitless zero, only in CSS
  TabAtkins: Also calc() can't have unitless zero.
  SimonSapin: I have some bugs to file then.
  SimonSapin: Specifically, a "0" value is a <number-token>, which
              gets typed by calc() to "integer", and you can't add
              "integer" and "length".
  TabAtkins: Servo/Stylo works the other way around: you try to
             parse <length>, unitless 0 and calc() are both valid

  RESOLVED: Switch to CSSMathValue-based expression tree with
            toSum() method for returning dictionary of unit types (
            as described above).

Issue 310: Consider using properties in addition to .get/.set
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  <shane> Topic: https://github.com/w3c/css-houdini-drafts/issues/310
  shane: I want to either say No or wait until level 2 to consider
  Rossen: I'd be fine for that.

  RESOLVED: Using properties (issue #310) is moved to L2

Topic 350: Move Houdini APIs to `window.CSS`
- - - - - - - - - - - - - - - - - - - - - -

  <shane> Topic: https://github.com/w3c/css-houdini-drafts/issues/350
  shane: Have window.getComputedStyleMap()
  shane: It should either be CSS.getComputedStyleMap or
  shane: We called it getComputedStyleMap() earlier so it doesn't
         collide with getComputedStyle, but now we have an
         opportunity to use the other name.
  iank: Does it make sense to move that particular one to CSS from

  dbaron: Why isn't this element.computedStyleMap?
  dbaron: Putting getComputedStyle() on window was a mistake
  <shane> 1. Window.getComputedStyleMap()
  <shane> 2. CSS.getComputedStyleMap()
  <shane> 3. CSS.getComputedStyle()
  <shane> 4. Element.computedStyleMap

  leaverou: Why not just element.computedStyle
  leaverou: Which is what getComputedStyle should have been in the
            first place?
  dbaron: That's more or less what I said in the first place...
  leaverou: I thought you were proposing a function.
  dbaron: I think, IIRC, that other things that return style maps
          end in StyleMap, and wouldn't want to have just one that
          omits the word Map.
  dbaron: But should be a getter.
  leaverou: Especially if it has Map at the end.
  shane: I quite like element.computedStyleMap.

  iank: Is this live?
  TabAtkins: Yes, it's in the minutes.
  <TabAtkins> (Per the minutes, it's live and we're very sad about
  SimonSapin: Style maps are live in general, but computedStyle is
              readonly isn't it?
  TabAtkins: Yes.
  SimonSapin: So it doesn't matter if it's live.
  dbaron: Yes it does, cuz then things are changed.
  TabAtkins: Nice thing is that values are hidden behind .get call
             so can compute them lazily.
  iank: One thing that getComputedStyle has is second argument is
        optional string for pseudo-element name.
  dbaron: We had this discussion before 5 years ago
  dbaron: We specced it all in CSSOM
  dbaron: But then deleted it because nobody implemented it.
  dbaron: But we did come up with API we liked for this
  dbaron: We had a pseudo-element class.
  birtles: I thought it was defined in two specs, in CSSOM and
  fantasai: Stuff in css-pseudo is "here is some stuff as ideas,
            please comment on it" not ready to impl..
  birtles: CSSPseudoElement is used by Web Animations

  shane: Let's do what dbaron says.
  shane: If we want to have pseudo-element class and have computed
         style of them hang off that class, then typed CSSOM might
         not let you get pseudo element styles.
  shane: Transiently while we put the rest of the mechanism in place.
  shane: But I don't think that's an issue given that the typed OM
         is incomplete in lots of other ways anyway.
  shane: So I think we should do what dbaron says.
  Rossen: I think we already established that :)
  shane: I'm gonna keep saying it until we resolve on it.
  Rossen: Was there some other option?

  shane: Yeah, I listed them out:
  <shane> 1. Window.getComputedStyleMap()
  <shane> 2. CSS.getComputedStyleMap()
  <shane> 3. CSS.getComputedStyle()
  <shane> 4. Element.computedStyleMap ( + pseudoElement mechanisms)
  Rossen: What's + pseudoElement mechanism?
  shane: Have an object representing the pseudoElement with a
  dino: Why not just .styleMap?
  ?: Because that's style attr.
  dino: But this is the API people actually want.
  ??: Could call it inlineStyleMap and computedStyleMap to be
      explicit about it.
  dino/smfr: People already get confused about .style being style
             attr and not computed style.
  TabAtkins: Don't really want to have .style = inlineStyleMap and
             styleMap = getComputedStyle

  <shane> 5. 4 + styleMap -> ??bikeshed??StyleMap
  <SimonSapin> .styleAttrMap / .computedStyleMap ?
  SimonSapin: Don't want to overload inline, already overloaded
  <leaverou> 4 (though it depends on the pseudo-element mechanisms)
  fantasai: I like .styleAttrMap / .computedStyleMap
  Rossen: attrStyleMap
  plinss: So that it's always StyleMap
  iank: No other DOM api abbreviates attribute.
  Rossen: Okay, we can bikeshed that later.

  Rossen: So, option #N is adopt element.attrStyleMap and
          element.computedStyleMap + pseudoElement mechanisms
  iank: I don't want the attribute thing.
  Rossen: We'll make it attributeStyleMap.

  RESOLVED: element.attributeStyleMap and element.computedStyleMap,
            attributeStyleMap to be renamed later, pseudo-element
            styles accessed through PseudoElement APIs.

  dino: Can someone summarize the pseudoElement stuff?
  TabAtkins: element.pseudos with ..
  dbaron: was a function pseudo(...) that returns element-like thing
  leaverou: What about parameterized pseudo elements?
  <dbaron> element.pseudo(":before").computedStyleMap
  <TabAtkins> "::before", certainly
  <fantasai> https://www.w3.org/TR/2013/WD-cssom-20131205/#extensions-to-the-element-interface
  fantasai: There's a reason we publish periodically to /TR with
            with dated snapshots :)
  <dbaron> https://hg.csswg.org/drafts/rev/26e59827f85c removed it
  <dbaron> It is present in
           although there may have been later improvements before
           the removal

Typed OM wrapup

  Rossen: we need to publish a new draft pending the changes

  RESOLVED: Update typed om draft on /TR with above edits
Received on Monday, 15 May 2017 08:42:31 UTC

This archive was generated by hypermail 2.4.0 : Friday, 17 January 2020 19:53:27 UTC