Re: Why can't we just use constructor instead of createdCallback?

2014-02-18 Thread Dimitri Glazkov
On Fri, Feb 14, 2014 at 3:58 PM, Jonas Sicking jo...@sicking.cc wrote:


 What I mean is that for nodes that doesn't have a constructor, and
 whose parent doesn't have a constructor, no need to add them to the
 above arrays. Just insert them into their parent. That means that when
 that the constructor of an element runs, the element doesn't have any
 parents or children.

 So no need to hide parents or children anywhere.


Okay, let me see if I got this right. The list is effectively a serialized
representation of a document subtree. The parent + order in the list
provides all the necessary information. We use this list to separate tree
construction into two stages: one before custom element constructors are
called, and one after.

In cases when the custom element is just a like button widget (a leaf in
the tree), the list is short and just contains the widgets.

In cases like bodymy-appdiv ... the entire doc tree ...
/my-app/body, the list contains the entire subtree of my-app, which
is effectively the document.

In cases like divmy-bar../my-barspan.../span ... more siblings
... /div, the list will contain at least all siblings of my-bar,
because they can't be inserted into tree until after my-bar's constructor
runs.

When run, the constructors are free to explore the partially-completed
tree, which enables interesting hacks like this:

in document:
div id=amy-bar/my-bar lots more markup...

in my-bar constructor:
var myFutureParent = document.querySelector(#a);
// redirect tree construction to resume at a new point.
document.body.appendChild(myFutureParent);

Or, in my-bar constructor:
var myFutureParent = document.querySelector(#a);
var iframe = document.body.appendChild(document.createElement(iframe));
// teleport the tree into another frame
iframe.contentDocument.body.appendChild(myFutureParent);

I can't immediately tell whether these hacks are cool or scary.

The thing that really bothers me is that this approach is contradicting
itself. We go to into pretty elaborate lengths to enable running
constructors during parsing, but the key performance lesson developers will
immediately learn is to avoid constructors on custom elements, because they
will trigger the two-phase code path during parsing. Here's a thing that
you can use, but you probably don't want to ever use it.

Here's an alternative proposal:

1) The Web developers are already aware of the fact that you can create new
instances of JS objects without running their constructors with
Object.create

2) Let's make sure that when they call constructors directly (as in var b =
new MyB(arg1,arg2);), the constructor is actually called.

3) When the parser instantiates the element, it does the equivalent of
Object.create, so no constructor is called.

It seems simple and easy to understand.

:DG


Re: Why can't we just use constructor instead of createdCallback?

2014-02-18 Thread Erik Arvidsson
On Tue, Feb 18, 2014 at 1:35 PM, Dimitri Glazkov dglaz...@google.comwrote:

 Here's an alternative proposal:

 1) The Web developers are already aware of the fact that you can create
 new instances of JS objects without running their constructors with
 Object.create


These are not the instances you are looking for.

We need to have real instances here. @@create gives us the semantics for
doing this.


 2) Let's make sure that when they call constructors directly (as in var b
 = new MyB(arg1,arg2);), the constructor is actually called.

 3) When the parser instantiates the element, it does the equivalent of
 Object.create, so no constructor is called.


That would not set the internal state as needed. It would not know how to
associate the instance object with the C++ backing object for example.
Also, all the DOM methods are using brand checks (and not instanceof
checks) so the brand needs to be setup as well.

The solution is to call `MyElement[Symbol.create]()` which would setup the
internal state as needed. We can make this non writable, non configurable
which allows the implementation to skip calling any js code at that point
because the semantics is unobservable.


 It seems simple and easy to understand.


With ES6 it is possible to create instance objects without ever calling the
constructor (this is NOT possible in ES5) so maybe we should just give up
on having the parser calling the constructor?


-- 
erik


Re: Why can't we just use constructor instead of createdCallback?

2014-02-18 Thread Dimitri Glazkov
On Tue, Feb 18, 2014 at 11:24 AM, Erik Arvidsson a...@chromium.org wrote:


 On Tue, Feb 18, 2014 at 1:35 PM, Dimitri Glazkov dglaz...@google.comwrote:

 Here's an alternative proposal:

 1) The Web developers are already aware of the fact that you can create
 new instances of JS objects without running their constructors with
 Object.create


 These are not the instances you are looking for.

 We need to have real instances here. @@create gives us the semantics for
 doing this.


Ah, yes. Sorry :)




 2) Let's make sure that when they call constructors directly (as in var b
 = new MyB(arg1,arg2);), the constructor is actually called.

 3) When the parser instantiates the element, it does the equivalent of
 Object.create, so no constructor is called.


 That would not set the internal state as needed. It would not know how to
 associate the instance object with the C++ backing object for example.
 Also, all the DOM methods are using brand checks (and not instanceof
 checks) so the brand needs to be setup as well.

 The solution is to call `MyElement[Symbol.create]()` which would setup the
 internal state as needed. We can make this non writable, non configurable
 which allows the implementation to skip calling any js code at that point
 because the semantics is unobservable.


 It seems simple and easy to understand.


 With ES6 it is possible to create instance objects without ever calling
 the constructor (this is NOT possible in ES5) so maybe we should just give
 up on having the parser calling the constructor?


Sounds good to me.

:DG


Re: Why can't we just use constructor instead of createdCallback?

2014-02-18 Thread Ryosuke Niwa
On Feb 18, 2014, at 10:35 AM, Dimitri Glazkov dglaz...@google.com wrote:
 On Fri, Feb 14, 2014 at 3:58 PM, Jonas Sicking jo...@sicking.cc wrote:
 
 What I mean is that for nodes that doesn't have a constructor, and
 whose parent doesn't have a constructor, no need to add them to the
 above arrays. Just insert them into their parent. That means that when
 that the constructor of an element runs, the element doesn't have any
 parents or children.
 
 So no need to hide parents or children anywhere.
 
 Okay, let me see if I got this right. The list is effectively a serialized 
 representation of a document subtree. The parent + order in the list provides 
 all the necessary information. We use this list to separate tree construction 
 into two stages: one before custom element constructors are called, and one 
 after.
 
 In cases when the custom element is just a like button widget (a leaf in the 
 tree), the list is short and just contains the widgets.
 
 In cases like bodymy-appdiv ... the entire doc tree ... 
 /my-app/body, the list contains the entire subtree of my-app, which is 
 effectively the document.
 
 In cases like divmy-bar../my-barspan.../span ... more siblings ... 
 /div, the list will contain at least all siblings of my-bar, because 
 they can't be inserted into tree until after my-bar's constructor runs.
 
 When run, the constructors are free to explore the partially-completed tree, 
 which enables interesting hacks like this:
 
 in document:
 div id=amy-bar/my-bar lots more markup...
 
 in my-bar constructor:
 var myFutureParent = document.querySelector(#a);
 // redirect tree construction to resume at a new point.
 document.body.appendChild(myFutureParent);
 
 Or, in my-bar constructor:
 var myFutureParent = document.querySelector(#a);
 var iframe = document.body.appendChild(document.createElement(iframe));
 // teleport the tree into another frame
 iframe.contentDocument.body.appendChild(myFutureParent);

You can already do this in a regular script element so this isn't a new issue 
custom element's constructor is introducing.


 The thing that really bothers me is that this approach is contradicting 
 itself. We go to into pretty elaborate lengths to enable running constructors 
 during parsing, but the key performance lesson developers will immediately 
 learn is to avoid constructors on custom elements, because they will trigger 
 the two-phase code path during parsing. Here's a thing that you can use, but 
 you probably don't want to ever use it.

Have you tried implementing this and found that you can't implement it 
efficiently?  Could you quantify the runtime or memory cost?

 Here's an alternative proposal:
 
 1) The Web developers are already aware of the fact that you can create new 
 instances of JS objects without running their constructors with Object.create
 
 2) Let's make sure that when they call constructors directly (as in var b = 
 new MyB(arg1,arg2);), the constructor is actually called.
 
 3) When the parser instantiates the element, it does the equivalent of 
 Object.create, so no constructor is called.

I don't see why we want to make the edge case like the one you described above 
prevent us from making common cases easy to use and understand.

Just call constructor whenever a custom element is created.  If you're doing 
weird stuff in constructor, then weird things happen.

- R. Niwa



Re: Why can't we just use constructor instead of createdCallback?

2014-02-18 Thread Jonas Sicking
On Tue, Feb 18, 2014 at 10:35 AM, Dimitri Glazkov dglaz...@google.com wrote:



 On Fri, Feb 14, 2014 at 3:58 PM, Jonas Sicking jo...@sicking.cc wrote:


 What I mean is that for nodes that doesn't have a constructor, and
 whose parent doesn't have a constructor, no need to add them to the
 above arrays. Just insert them into their parent. That means that when
 that the constructor of an element runs, the element doesn't have any
 parents or children.

 So no need to hide parents or children anywhere.


 Okay, let me see if I got this right. The list is effectively a serialized
 representation of a document subtree. The parent + order in the list
 provides all the necessary information. We use this list to separate tree
 construction into two stages: one before custom element constructors are
 called, and one after.

Yes

 In cases when the custom element is just a like button widget (a leaf in the
 tree), the list is short and just contains the widgets.

Yes

 In cases like bodymy-appdiv ... the entire doc tree ...
 /my-app/body, the list contains the entire subtree of my-app, which
 is effectively the document.

Well. With the optimization I mentioned you only need to make the
my-app element and it's immediate children into the list. Any
grand-children of my-app can immediately be inserted into their
parent.

So I guess you could say that the list contains basically the whole
document. But most nodes would only indirectly be in the list. I.e.
the list would be short, but each entry could contain large subtrees.

 In cases like divmy-bar../my-barspan.../span ... more siblings
 ... /div, the list will contain at least all siblings of my-bar,
 because they can't be inserted into tree until after my-bar's constructor
 runs.

Yes

 When run, the constructors are free to explore the partially-completed tree,
 which enables interesting hacks like this:

 in document:
 div id=amy-bar/my-bar lots more markup...

 in my-bar constructor:
 var myFutureParent = document.querySelector(#a);
 // redirect tree construction to resume at a new point.
 document.body.appendChild(myFutureParent);

 Or, in my-bar constructor:
 var myFutureParent = document.querySelector(#a);
 var iframe = document.body.appendChild(document.createElement(iframe));
 // teleport the tree into another frame
 iframe.contentDocument.body.appendChild(myFutureParent);

Yup

 I can't immediately tell whether these hacks are cool or scary.

You can already do exactly this with script elements. I also am not
sure if that's cool or scary. But I also haven't heard of anyone
running into trouble because of it. I suspect it's not a common thing
to do.

 The thing that really bothers me is that this approach is contradicting
 itself. We go to into pretty elaborate lengths to enable running
 constructors during parsing, but the key performance lesson developers will
 immediately learn is to avoid constructors on custom elements, because they
 will trigger the two-phase code path during parsing. Here's a thing that you
 can use, but you probably don't want to ever use it.

The above paragraph appears to assume that creating this list is slow.
Do you have data to back that up?

The whole premise of my original email was that we should not do this
if it's slow. And that we should measure if it's slow or not.

I absolutely agree that we should not add features that are slow
anytime they are used.

/ Jonas



Re: Why can't we just use constructor instead of createdCallback?

2014-02-18 Thread Erik Arvidsson
On Tue, Feb 18, 2014 at 5:59 PM, Jonas Sicking jo...@sicking.cc wrote:

 On Tue, Feb 18, 2014 at 10:35 AM, Dimitri Glazkov dglaz...@google.com
 wrote:
 
 
 
  On Fri, Feb 14, 2014 at 3:58 PM, Jonas Sicking jo...@sicking.cc wrote:
 
 
  What I mean is that for nodes that doesn't have a constructor, and
  whose parent doesn't have a constructor, no need to add them to the
  above arrays. Just insert them into their parent. That means that when
  that the constructor of an element runs, the element doesn't have any
  parents or children.
 
  So no need to hide parents or children anywhere.
 
 
  Okay, let me see if I got this right. The list is effectively a
 serialized
  representation of a document subtree. The parent + order in the list
  provides all the necessary information. We use this list to separate tree
  construction into two stages: one before custom element constructors are
  called, and one after.

 Yes

  In cases when the custom element is just a like button widget (a leaf in
 the
  tree), the list is short and just contains the widgets.

 Yes

  In cases like bodymy-appdiv ... the entire doc tree ...
  /my-app/body, the list contains the entire subtree of my-app,
 which
  is effectively the document.

 Well. With the optimization I mentioned you only need to make the
 my-app element and it's immediate children into the list. Any
 grand-children of my-app can immediately be inserted into their
 parent.

 So I guess you could say that the list contains basically the whole
 document. But most nodes would only indirectly be in the list. I.e.
 the list would be short, but each entry could contain large subtrees.


Would that cause issues with the order of the mutation record reported by
mutation observers?



  In cases like divmy-bar../my-barspan.../span ... more siblings
  ... /div, the list will contain at least all siblings of my-bar,
  because they can't be inserted into tree until after my-bar's
 constructor
  runs.

 Yes

  When run, the constructors are free to explore the partially-completed
 tree,
  which enables interesting hacks like this:
 
  in document:
  div id=amy-bar/my-bar lots more markup...
 
  in my-bar constructor:
  var myFutureParent = document.querySelector(#a);
  // redirect tree construction to resume at a new point.
  document.body.appendChild(myFutureParent);
 
  Or, in my-bar constructor:
  var myFutureParent = document.querySelector(#a);
  var iframe = document.body.appendChild(document.createElement(iframe));
  // teleport the tree into another frame
  iframe.contentDocument.body.appendChild(myFutureParent);

 Yup

  I can't immediately tell whether these hacks are cool or scary.

 You can already do exactly this with script elements. I also am not
 sure if that's cool or scary. But I also haven't heard of anyone
 running into trouble because of it. I suspect it's not a common thing
 to do.

  The thing that really bothers me is that this approach is contradicting
  itself. We go to into pretty elaborate lengths to enable running
  constructors during parsing, but the key performance lesson developers
 will
  immediately learn is to avoid constructors on custom elements, because
 they
  will trigger the two-phase code path during parsing. Here's a thing that
 you
  can use, but you probably don't want to ever use it.

 The above paragraph appears to assume that creating this list is slow.
 Do you have data to back that up?

 The whole premise of my original email was that we should not do this
 if it's slow. And that we should measure if it's slow or not.

 I absolutely agree that we should not add features that are slow
 anytime they are used.

 / Jonas




-- 
erik


Re: Why can't we just use constructor instead of createdCallback?

2014-02-18 Thread Dimitri Glazkov
On Tue, Feb 18, 2014 at 2:59 PM, Jonas Sicking jo...@sicking.cc wrote:

 On Tue, Feb 18, 2014 at 10:35 AM, Dimitri Glazkov dglaz...@google.com
 wrote:
 
 
 
  On Fri, Feb 14, 2014 at 3:58 PM, Jonas Sicking jo...@sicking.cc wrote:
 
 
  What I mean is that for nodes that doesn't have a constructor, and
  whose parent doesn't have a constructor, no need to add them to the
  above arrays. Just insert them into their parent. That means that when
  that the constructor of an element runs, the element doesn't have any
  parents or children.
 
  So no need to hide parents or children anywhere.
 
 
  Okay, let me see if I got this right. The list is effectively a
 serialized
  representation of a document subtree. The parent + order in the list
  provides all the necessary information. We use this list to separate tree
  construction into two stages: one before custom element constructors are
  called, and one after.

 Yes

  In cases when the custom element is just a like button widget (a leaf in
 the
  tree), the list is short and just contains the widgets.

 Yes

  In cases like bodymy-appdiv ... the entire doc tree ...
  /my-app/body, the list contains the entire subtree of my-app,
 which
  is effectively the document.

 Well. With the optimization I mentioned you only need to make the
 my-app element and it's immediate children into the list. Any
 grand-children of my-app can immediately be inserted into their
 parent.

 So I guess you could say that the list contains basically the whole
 document. But most nodes would only indirectly be in the list. I.e.
 the list would be short, but each entry could contain large subtrees.

  In cases like divmy-bar../my-barspan.../span ... more siblings
  ... /div, the list will contain at least all siblings of my-bar,
  because they can't be inserted into tree until after my-bar's
 constructor
  runs.

 Yes

  When run, the constructors are free to explore the partially-completed
 tree,
  which enables interesting hacks like this:
 
  in document:
  div id=amy-bar/my-bar lots more markup...
 
  in my-bar constructor:
  var myFutureParent = document.querySelector(#a);
  // redirect tree construction to resume at a new point.
  document.body.appendChild(myFutureParent);
 
  Or, in my-bar constructor:
  var myFutureParent = document.querySelector(#a);
  var iframe = document.body.appendChild(document.createElement(iframe));
  // teleport the tree into another frame
  iframe.contentDocument.body.appendChild(myFutureParent);

 Yup

  I can't immediately tell whether these hacks are cool or scary.

 You can already do exactly this with script elements. I also am not
 sure if that's cool or scary. But I also haven't heard of anyone
 running into trouble because of it. I suspect it's not a common thing
 to do.


I see. I am continually amazed at the exciting world we live in.



  The thing that really bothers me is that this approach is contradicting
  itself. We go to into pretty elaborate lengths to enable running
  constructors during parsing, but the key performance lesson developers
 will
  immediately learn is to avoid constructors on custom elements, because
 they
  will trigger the two-phase code path during parsing. Here's a thing that
 you
  can use, but you probably don't want to ever use it.

 The above paragraph appears to assume that creating this list is slow.
 Do you have data to back that up?


No, of course not :) It's a first intuitive reaction.

:DG


Re: Why can't we just use constructor instead of createdCallback?

2014-02-18 Thread Adam Klein
On Tue, Feb 18, 2014 at 3:26 PM, Dimitri Glazkov dglaz...@google.com wrote:
 On Tue, Feb 18, 2014 at 2:59 PM, Jonas Sicking jo...@sicking.cc wrote:
  On Tue, Feb 18, 2014 at 10:35 AM, Dimitri Glazkov dglaz...@google.com 
  wrote:
   The thing that really bothers me is that this approach is contradicting
   itself. We go to into pretty elaborate lengths to enable running
   constructors during parsing, but the key performance lesson developers 
   will
   immediately learn is to avoid constructors on custom elements, because 
   they
   will trigger the two-phase code path during parsing. Here's a thing that 
   you
   can use, but you probably don't want to ever use it.
 
  The above paragraph appears to assume that creating this list is slow.
  Do you have data to back that up?

 No, of course not :) It's a first intuitive reaction.

One example that seems intuitively problematic about this approach (to
me, anyway) are those parts of the parser that inspect the tree during
parsing: foster parenting. I'm not sure it's a performance issue so
much as a complexity issue. Consider:

div
  my-element
table
  div

When following the spec
(http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#appropriate-place-for-inserting-a-node),
any text in that algorithm which says parent node need to be patched
to say something about this new list of to-be-attached nodes.

Patching all such references seems likely to be difficult and
error-prone, but I admit that I can't quantify those worries.

- Adam



Re: Why can't we just use constructor instead of createdCallback?

2014-02-14 Thread Dimitri Glazkov
On Thu, Feb 13, 2014 at 6:50 PM, Jonas Sicking jo...@sicking.cc wrote:

 Dimitri, I'd still love to hear feedback from you on the idea above.
 Seems like it could fix one of the design issues that a lot of people
 have reacted to.


I am not sure I fully understand how this will work. Let me try to repeat
it back and see if I got this right.

Basically, we are modifying the tree construction algorithm to be a 3-pass
system:

1) Build a meta tree (each node in the tree is a meta object that
represents an element that will be constructed)
2) Instantiate all elements by calling constructors on them
3) Build the tree of elements from the meta tree.

Right?

:DG


Re: Why can't we just use constructor instead of createdCallback?

2014-02-14 Thread Jonas Sicking
On Fri, Feb 14, 2014 at 9:25 AM, Dimitri Glazkov dglaz...@google.com wrote:
 On Thu, Feb 13, 2014 at 6:50 PM, Jonas Sicking jo...@sicking.cc wrote:

 Dimitri, I'd still love to hear feedback from you on the idea above.
 Seems like it could fix one of the design issues that a lot of people
 have reacted to.


 I am not sure I fully understand how this will work. Let me try to repeat it
 back and see if I got this right.

 Basically, we are modifying the tree construction algorithm to be a 3-pass
 system:

 1) Build a meta tree (each node in the tree is a meta object that represents
 an element that will be constructed)
 2) Instantiate all elements by calling constructors on them
 3) Build the tree of elements from the meta tree.

 Right?

I'd rather put it as:

1) Construct the objects, but rather than inserting them in their
parents, remember which parent they should be inserted in.
2) Call constructors on all elements
3) Insert elements in their parent

So no need to construct any meta objects.

You can further optimize by only doing this for custom elements with a
constructor.

/ Jonas



Re: Why can't we just use constructor instead of createdCallback?

2014-02-14 Thread Dimitri Glazkov
On Fri, Feb 14, 2014 at 10:36 AM, Jonas Sicking jo...@sicking.cc wrote:

 On Fri, Feb 14, 2014 at 9:25 AM, Dimitri Glazkov dglaz...@google.com
 wrote:
  On Thu, Feb 13, 2014 at 6:50 PM, Jonas Sicking jo...@sicking.cc wrote:
 
  Dimitri, I'd still love to hear feedback from you on the idea above.
  Seems like it could fix one of the design issues that a lot of people
  have reacted to.
 
 
  I am not sure I fully understand how this will work. Let me try to
 repeat it
  back and see if I got this right.
 
  Basically, we are modifying the tree construction algorithm to be a
 3-pass
  system:
 
  1) Build a meta tree (each node in the tree is a meta object that
 represents
  an element that will be constructed)
  2) Instantiate all elements by calling constructors on them
  3) Build the tree of elements from the meta tree.
 
  Right?

 I'd rather put it as:

 1) Construct the objects, but rather than inserting them in their
 parents, remember which parent they should be inserted in.


Sure, this is the meta tree construction. At the limit, if every element is
a custom element, then you're effectively building a tree of things that
remember where their respective elements need to be.


 2) Call constructors on all elements


Yup.


 3) Insert elements in their parent


Yup.



 So no need to construct any meta objects.


Okay, we don't have to call them meta objects, but we need some storage to
remember where the element should go :)



 You can further optimize by only doing this for custom elements with a
 constructor.


Interesting. What if the element's constructor decides to walk the DOM tree
or mutate it? What does it see? Are there holes for elements that haven't
yet been inserted, or are the elements just appended regardless of their
initial position in the tree?

:DG


Re: Why can't we just use constructor instead of createdCallback?

2014-02-14 Thread Erik Arvidsson
Another alternative is to disallow DOM traversal and DOM mutation inside
these constructors. By disallow I mean throw an error! Here is a rough
outline of what the algorithm might look like.

Let there be a global counter CostomElementConstructionCounter which is
initially set to 0.

1. Parse and build the DOM tree as usual. Keep track of all custom elements
we encounter.
2. At some later point, before any script is run:
3. For each pending custom element (in tree order):
  1. Create the instance objects for the custom element.
  2. Increment CostomElementConstructionCounter
  3. Call the constructructor for the custom element, passing the object
instance as `this`.
  4. Decrement CostomElementConstructionCounter

Then we need to guard all DOM traversal and DOM mutation methods and throw
if the counter is non zero.

The point is that the timing of the constructor invocation is mostly not
observable. If an implementation wants to invoke it as it builds the DOM
that also works since there is no way to traverse the tree at that time.



On Fri, Feb 14, 2014 at 1:50 PM, Dimitri Glazkov dglaz...@google.comwrote:




 On Fri, Feb 14, 2014 at 10:36 AM, Jonas Sicking jo...@sicking.cc wrote:

 On Fri, Feb 14, 2014 at 9:25 AM, Dimitri Glazkov dglaz...@google.com
 wrote:
  On Thu, Feb 13, 2014 at 6:50 PM, Jonas Sicking jo...@sicking.cc
 wrote:
 
  Dimitri, I'd still love to hear feedback from you on the idea above.
  Seems like it could fix one of the design issues that a lot of people
  have reacted to.
 
 
  I am not sure I fully understand how this will work. Let me try to
 repeat it
  back and see if I got this right.
 
  Basically, we are modifying the tree construction algorithm to be a
 3-pass
  system:
 
  1) Build a meta tree (each node in the tree is a meta object that
 represents
  an element that will be constructed)
  2) Instantiate all elements by calling constructors on them
  3) Build the tree of elements from the meta tree.
 
  Right?

 I'd rather put it as:

 1) Construct the objects, but rather than inserting them in their
 parents, remember which parent they should be inserted in.


 Sure, this is the meta tree construction. At the limit, if every element
 is a custom element, then you're effectively building a tree of things that
 remember where their respective elements need to be.


 2) Call constructors on all elements


 Yup.


 3) Insert elements in their parent


 Yup.



 So no need to construct any meta objects.


 Okay, we don't have to call them meta objects, but we need some storage to
 remember where the element should go :)



 You can further optimize by only doing this for custom elements with a
 constructor.


 Interesting. What if the element's constructor decides to walk the DOM
 tree or mutate it? What does it see? Are there holes for elements that
 haven't yet been inserted, or are the elements just appended regardless of
 their initial position in the tree?

 :DG




-- 
erik


Re: Why can't we just use constructor instead of createdCallback?

2014-02-14 Thread Boris Zbarsky

On 2/14/14 2:03 PM, Erik Arvidsson wrote:

Then we need to guard all DOM traversal and DOM mutation methods and
throw if the counter is non zero.


This is a fairly nontrivial whack-a-mole exercise, sadly (starting with 
defining traversal).


-Boris



Re: Why can't we just use constructor instead of createdCallback?

2014-02-14 Thread Jonas Sicking
On Fri, Feb 14, 2014 at 10:50 AM, Dimitri Glazkov dglaz...@google.com wrote:



 On Fri, Feb 14, 2014 at 10:36 AM, Jonas Sicking jo...@sicking.cc wrote:

 On Fri, Feb 14, 2014 at 9:25 AM, Dimitri Glazkov dglaz...@google.com
 wrote:
  On Thu, Feb 13, 2014 at 6:50 PM, Jonas Sicking jo...@sicking.cc wrote:
 
  Dimitri, I'd still love to hear feedback from you on the idea above.
  Seems like it could fix one of the design issues that a lot of people
  have reacted to.
 
 
  I am not sure I fully understand how this will work. Let me try to
  repeat it
  back and see if I got this right.
 
  Basically, we are modifying the tree construction algorithm to be a
  3-pass
  system:
 
  1) Build a meta tree (each node in the tree is a meta object that
  represents
  an element that will be constructed)
  2) Instantiate all elements by calling constructors on them
  3) Build the tree of elements from the meta tree.
 
  Right?

 I'd rather put it as:

 1) Construct the objects, but rather than inserting them in their
 parents, remember which parent they should be inserted in.

 Sure, this is the meta tree construction. At the limit, if every element is
 a custom element, then you're effectively building a tree of things that
 remember where their respective elements need to be.

I don't think that you need a tree of things. What you need is an
array of objects that need to be inserted, and an array of parents
that they need to insert them into. That's it.

 So no need to construct any meta objects.

 Okay, we don't have to call them meta objects, but we need some storage to
 remember where the element should go :)

Sure. You'll need two arrays. Or really, you'll need one array of
node+parent tuples.

 You can further optimize by only doing this for custom elements with a
 constructor.

 Interesting. What if the element's constructor decides to walk the DOM tree
 or mutate it? What does it see? Are there holes for elements that haven't
 yet been inserted, or are the elements just appended regardless of their
 initial position in the tree?

What I mean is that for nodes that doesn't have a constructor, and
whose parent doesn't have a constructor, no need to add them to the
above arrays. Just insert them into their parent. That means that when
that the constructor of an element runs, the element doesn't have any
parents or children.

So no need to hide parents or children anywhere.

/ Jonas



Re: Why can't we just use constructor instead of createdCallback?

2014-02-13 Thread Jonas Sicking
Dimitri, I'd still love to hear feedback from you on the idea above.
Seems like it could fix one of the design issues that a lot of people
have reacted to.

/ Jonas

On Wed, Jan 22, 2014 at 5:21 PM, Jonas Sicking jo...@sicking.cc wrote:
 On Thu, Jan 9, 2014 at 9:27 PM, Boris Zbarsky bzbar...@mit.edu wrote:
 One idea that came out of our discussion is was to add an additional step
 in the parser to call constructors on all pending elements before they're
 being constructed into the DOM tree.

 Isn't that the bad thing we _don't_ want to do?  That is, invoke arbitrary
 page JS from the middle of the parsing algorithm?

 The idea was to do something like this:

 1. While parsing, when you hit a custom element (with a constructor)
 don't insert that element into its parent, nor insert any of its
 children into the element.
 2. Put each such element into an array along with meta-info about what
 parent and children it should have.
 3. Once you're done parsing as much as you want to parse (i.e. until
 you hit a network boundary or feel the need to return to the event
 loop), unwind enough of the calling stack until you feel comfortable
 running content JS.
 4. Run the constructor for the first element in the array.
 5. After a constructor has been run, insert the element into its
 parent, and insert its children into the element.
 6. Remove the element from the array and, unless the array is empty,
 go back to step 4.

 This is somewhat simplified. You also have to make sure not to insert
 an elements into a parent where previous siblings are still pending to
 be inserted.

 The big question of course is if tracking the elements in the separate
 array and inserting them after their constructor has run will be a
 performance issue.

 In Gecko it might be a bit of a problem since we can get O(n^2)
 performance issues where n is the nesting depth of custom elements.
 This is due to our recursive BindToTree notification which cause
 problems when trees are constructed bottom up

 But possibly this can be solved. And possibly other implementations
 doesn't have the same problem. Or possibly they have worse problems.

 But it wasn't immediately obvious to me that this wouldn't work.

 / Jonas



Re: Why can't we just use constructor instead of createdCallback?

2014-02-13 Thread Ryosuke Niwa
We (Apple) support this proposal assuming that we can implement the proposed 
algorithm efficiently.

We would try to prototype it in WebKit in the coming months and will report 
implementation issues, including the feasibility of efficient implementation, 
if exists.

- R. Niwa

On Feb 13, 2014, at 6:50 PM, Jonas Sicking jo...@sicking.cc wrote:

 Dimitri, I'd still love to hear feedback from you on the idea above.
 Seems like it could fix one of the design issues that a lot of people
 have reacted to.
 
 / Jonas
 
 On Wed, Jan 22, 2014 at 5:21 PM, Jonas Sicking jo...@sicking.cc wrote:
 On Thu, Jan 9, 2014 at 9:27 PM, Boris Zbarsky bzbar...@mit.edu wrote:
 One idea that came out of our discussion is was to add an additional step
 in the parser to call constructors on all pending elements before they're
 being constructed into the DOM tree.
 
 Isn't that the bad thing we _don't_ want to do?  That is, invoke arbitrary
 page JS from the middle of the parsing algorithm?
 
 The idea was to do something like this:
 
 1. While parsing, when you hit a custom element (with a constructor)
 don't insert that element into its parent, nor insert any of its
 children into the element.
 2. Put each such element into an array along with meta-info about what
 parent and children it should have.
 3. Once you're done parsing as much as you want to parse (i.e. until
 you hit a network boundary or feel the need to return to the event
 loop), unwind enough of the calling stack until you feel comfortable
 running content JS.
 4. Run the constructor for the first element in the array.
 5. After a constructor has been run, insert the element into its
 parent, and insert its children into the element.
 6. Remove the element from the array and, unless the array is empty,
 go back to step 4.
 
 This is somewhat simplified. You also have to make sure not to insert
 an elements into a parent where previous siblings are still pending to
 be inserted.
 
 The big question of course is if tracking the elements in the separate
 array and inserting them after their constructor has run will be a
 performance issue.
 
 In Gecko it might be a bit of a problem since we can get O(n^2)
 performance issues where n is the nesting depth of custom elements.
 This is due to our recursive BindToTree notification which cause
 problems when trees are constructed bottom up
 
 But possibly this can be solved. And possibly other implementations
 doesn't have the same problem. Or possibly they have worse problems.
 
 But it wasn't immediately obvious to me that this wouldn't work.
 
 / Jonas




Re: Why can't we just use constructor instead of createdCallback?

2014-01-22 Thread Jonas Sicking
On Thu, Jan 9, 2014 at 9:27 PM, Boris Zbarsky bzbar...@mit.edu wrote:
 One idea that came out of our discussion is was to add an additional step
 in the parser to call constructors on all “pending” elements before they’re
 being constructed into the DOM tree.

 Isn't that the bad thing we _don't_ want to do?  That is, invoke arbitrary
 page JS from the middle of the parsing algorithm?

The idea was to do something like this:

1. While parsing, when you hit a custom element (with a constructor)
don't insert that element into its parent, nor insert any of its
children into the element.
2. Put each such element into an array along with meta-info about what
parent and children it should have.
3. Once you're done parsing as much as you want to parse (i.e. until
you hit a network boundary or feel the need to return to the event
loop), unwind enough of the calling stack until you feel comfortable
running content JS.
4. Run the constructor for the first element in the array.
5. After a constructor has been run, insert the element into its
parent, and insert its children into the element.
6. Remove the element from the array and, unless the array is empty,
go back to step 4.

This is somewhat simplified. You also have to make sure not to insert
an elements into a parent where previous siblings are still pending to
be inserted.

The big question of course is if tracking the elements in the separate
array and inserting them after their constructor has run will be a
performance issue.

In Gecko it might be a bit of a problem since we can get O(n^2)
performance issues where n is the nesting depth of custom elements.
This is due to our recursive BindToTree notification which cause
problems when trees are constructed bottom up

But possibly this can be solved. And possibly other implementations
doesn't have the same problem. Or possibly they have worse problems.

But it wasn't immediately obvious to me that this wouldn't work.

/ Jonas



Re: Why can't we just use constructor instead of createdCallback?

2014-01-10 Thread Erik Arvidsson
On Thu, Jan 9, 2014 at 10:57 PM, Ryosuke Niwa rn...@apple.com wrote:

  1. The parser does not know that it needs to use MyElement.@@create to
 create the JS objects when it sees a my-element.

 On the other hand, solving this seems to require running some author
 scripts at the element creation time, at some later time but before the
 node is inserted into the document.


My hope was that it would be rare to override Symbol.create for Elements so
in most cases we would not need to call user code.

After further discussing this with Dominic and others I've given up the
hope that an object instance cannot be reached before the constructor has
been called. This can happen due to navigating the DOM tree but also be
manually calling `MyCustomElement[Symbol.create]()`. At this point I
believe we should just resolve to best practice and that is to not use
@@create directly and do not navigate the DOM tree in your constructors.


-- 
erik


Re: Why can't we just use constructor instead of createdCallback?

2014-01-10 Thread Boris Zbarsky

On 1/10/14 11:10 AM, Erik Arvidsson wrote:

My hope was that it would be rare to override Symbol.create for Elements
so in most cases we would not need to call user code.


For spec purposes and parser implementation design purposes that doesn't 
matter.  If user code can be called, the algorithms involved have to 
handle user code being called at that point and potentially tearing the 
world down (or apart, or just rearranging it in macabre ways like user 
code tends to do)...



After further discussing this with Dominic and others I've given up the
hope that an object instance cannot be reached before the constructor
has been called. This can happen due to navigating the DOM tree but also
be manually calling `MyCustomElement[Symbol.create]()`. At this point I
believe we should just resolve to best practice and that is to not use
@@create directly and do not navigate the DOM tree in your constructors.


Yeah, agreed.

-Boris




Re: Why can't we just use constructor instead of createdCallback?

2014-01-10 Thread Ryosuke Niwa

On Jan 10, 2014, at 8:16 AM, Boris Zbarsky bzbar...@mit.edu wrote:

 On 1/10/14 11:10 AM, Erik Arvidsson wrote:
 My hope was that it would be rare to override Symbol.create for Elements
 so in most cases we would not need to call user code.
 
 For spec purposes and parser implementation design purposes that doesn't 
 matter.  If user code can be called, the algorithms involved have to handle 
 user code being called at that point and potentially tearing the world down 
 (or apart, or just rearranging it in macabre ways like user code tends to 
 do)...
 
 After further discussing this with Dominic and others I've given up the
 hope that an object instance cannot be reached before the constructor
 has been called. This can happen due to navigating the DOM tree but also
 be manually calling `MyCustomElement[Symbol.create]()`. At this point I
 believe we should just resolve to best practice and that is to not use
 @@create directly and do not navigate the DOM tree in your constructors.
 
 Yeah, agreed.

An alternative idea we had was to “recursively” call constructors on the 
“unconstructed” elements in such situations.  So if the constructor of an 
element A tries to access to another unconstrcuted element B, then call B’s 
constructor at that point.

Either solution is better than not being able to use ES6 classes in my opinion.

- R. Niwa




Re: Why can't we just use constructor instead of createdCallback?

2014-01-09 Thread Ryosuke Niwa
Jonas, William, Ted, and I had some discussion about this last month.  (Sorry 
for the delayed response).

On Dec 5, 2013, at 10:58 PM, Boris Zbarsky bzbar...@mit.edu wrote:
 On 12/6/13 1:49 AM, Ryosuke Niwa wrote:
 Then how do we define a custom element using ES6 classes?  Are we going to 
 not call the constructor?
 
 An excellent question, indeed.  I don't have a good answer for you.
 
 If we do make elements subclassable (which it seems like we should), we would 
 presumably need to make the actual default constructor of the built-in 
 element classes a no-op, since we can't actually rely on the subclass calling 
 it.  All the relevant setup would need to be done by @@create.
 
 Given that, we could maybe cheat and in fact do some sort of delayed calling 
 of the constructor of ES6 subclasses of elements.  You'd still be able to 
 observe these objects in an unconstructed state from the subclass pov, but 
 at least it wouldn't be a security issue in terms of operating on a DOM 
 that's in an inconsistent state from the point of view of privileged code.

Calling constructors after the tree had been constructed will be an issue 
because then you could access “unconstructed” nodes via nextSibling, 
parentNode, etc...

 It's not clear to me how OK such an unconstructed state is.  I suppose it's 
 no worse than someone extending the ES6 subclass in question and then never 
 calling its constructor...  But that's a programming error on the someone's 
 part, typically, while here we would be effectively forcing this sort of 
 thing on all Element subclasses.
 
 All that still seems more palatable than trying to completely revise HTML 
 parsing to be robust to constructors running when the element is created….

One idea that came out of our discussion is was to add an additional step in 
the parser to call constructors on all “pending” elements before they’re being 
constructed into the DOM tree.


On Dec 6, 2013, at 7:05 AM, Erik Arvidsson a...@chromium.org wrote:
 The custom element draft does add a new synchronization point. After setting 
 innerHTML (for example), before returning to the script the callbacks for the 
 custom elements created by innerHTML are called in tree order.
 
 This does lead to the possibility to observer objects that have not yet had 
 their created callback been called yet. I think this trade off is inevitable, 
 no matter whether we use @@create, constructor or created. I just don't see 
 us being able to call user code every time a node is created.


I do understand your concern.

On Dec 6, 2013, at 7:37 AM, Erik Arvidsson a...@chromium.org wrote:
 The things that fail here are:
 
 1. The parser does not know that it needs to use MyElement.@@create to create 
 the JS objects when it sees a my-element.

On the other hand, solving this seems to require running some author scripts at 
the element creation time, at some later time but before the node is inserted 
into the document.

 2. No callbacks for enteredView, leftView and attributeChanged.
 3. It depend on the magic of document.createElement which is circular. A 
 better way would be to do `super('my-element')` or something like that.


- R. Niwa




Re: Why can't we just use constructor instead of createdCallback?

2014-01-09 Thread Boris Zbarsky

On 1/9/14 10:57 PM, Ryosuke Niwa wrote:

Given that, we could maybe cheat and in fact do some sort of delayed calling of the 
constructor of ES6 subclasses of elements.  You'd still be able to observe these objects 
in an unconstructed state from the subclass pov, but at least it wouldn't be 
a security issue in terms of operating on a DOM that's in an inconsistent state from the 
point of view of privileged code.


Calling constructors after the tree had been constructed will be an issue 
because then you could access “unconstructed” nodes via nextSibling, 
parentNode, etc...


Right, I did say that above.  Is that really a problem in practice, though?


One idea that came out of our discussion is was to add an additional step in 
the parser to call constructors on all “pending” elements before they’re being 
constructed into the DOM tree.


Isn't that the bad thing we _don't_ want to do?  That is, invoke 
arbitrary page JS from the middle of the parsing algorithm?



On the other hand, solving this seems to require running some author scripts at 
the element creation time, at some later time but before the node is inserted 
into the document.


The parser is expected to insert the nodes into the document pretty much 
immediately after creating them, no?


-Boris



Re: Why can't we just use constructor instead of createdCallback?

2014-01-09 Thread Andrew Fedoniouk
On Thu, Jan 9, 2014 at 9:27 PM, Boris Zbarsky bzbar...@mit.edu wrote:
 On 1/9/14 10:57 PM, Ryosuke Niwa wrote:

 Given that, we could maybe cheat and in fact do some sort of delayed
 calling of the constructor of ES6 subclasses of elements.  You'd still be
 able to observe these objects in an unconstructed state from the subclass
 pov, but at least it wouldn't be a security issue in terms of operating on a
 DOM that's in an inconsistent state from the point of view of privileged
 code.


 Calling constructors after the tree had been constructed will be an issue
 because then you could access “unconstructed” nodes via nextSibling,
 parentNode, etc...


 Right, I did say that above.  Is that really a problem in practice, though?

 One idea that came out of our discussion is was to add an additional step
 in the parser to call constructors on all “pending” elements before they’re
 being constructed into the DOM tree.


 Isn't that the bad thing we _don't_ want to do?  That is, invoke arbitrary
 page JS from the middle of the parsing algorithm?

 On the other hand, solving this seems to require running some author
 scripts at the element creation time, at some later time but before the node
 is inserted into the document.


 The parser is expected to insert the nodes into the document pretty much
 immediately after creating them, no?

 -Boris


Calling of constructors (in JS/ES sense) instead of callbacks is not
semantically correct I would say.

Consider this declaration:

class MyElement inherits HTMLElement {
public  prop = 1;
constructor( text ) {
   super(my-element);
   this.textContent = text;
}
}

UA simply cannot call such constructor as it requires parameter.
UA can call only implicit default constructor,  :  ({ prop:1
}).__proto__ =  MyElement;  in this case.
And call some designated method of the class ('callback' in this
discussion) when element gets
attached to the DOM tree.

Constructors are used for 'external' element creation:

  var myel = new MyElement(woo-hoo!);

About callbacks:

It should be two callbacks actually:

attached() - called when element *gets attached to the DOM*, it is not
a constructor, sic!
detached() - when it gets detached from the DOM.

so here:

  var myel = new MyElement(woo-hoo!);
  someParent.append(myel);

call of myel.attached() will happen inside the append() above.

  detached() is called when parent.removeChild() for the element is called.

Just in case: this is how it is implemented and works in my Sciter [1]
and I didn't find any problems with element/script life cycles.

And yet. I also have dynamic element class assignment
by CSS with custom 'prototype' property, e.g.:

  input[type=masked] { prototype: MaskedInput url(code/widgets.tis); }

In that case attached/detached are also called when the element
gets/looses that style. But that's probably another story.

[1] http://terrainformatica.com/sciter


-- 
Andrew Fedoniouk.

http://terrainformatica.com



[WebComponents] List for new bug announcements [Was: Re: Why can't we just use constructor instead of createdCallback?]

2013-12-07 Thread Arthur Barstow

On 12/6/13 3:28 PM, ext Ryosuke Niwa wrote:


On Dec 6, 2013, at 7:37 AM, Erik Arvidsson a...@chromium.org 
mailto:a...@chromium.org wrote:


1. The parser does not know that it needs to use MyElement.@@create 
to create the JS objects when it sees a my-element.

2. No callbacks for enteredView, leftView and attributeChanged.
3. It depend on the magic of document.createElement which is 
circular. A better way would be to do `super('my-element')` or 
something like that.


I wish we could resolve these remaining issues.


In fact, fixing these issues is a requirement for us.


I just noticed that yesterday Erik filed three Custom Element bugs but I 
didn't receive an announcement about them:


* [Custom]: No way to pass parameters to constructor
https://www.w3.org/Bugs/Public/show_bug.cgi?id=24018

* [Custom]: No way to associate class/constructor function
https://www.w3.org/Bugs/Public/show_bug.cgi?id=24019

* [Custom]: A tag name should be associated with the constructor and not 
the prototype

https://www.w3.org/Bugs/Public/show_bug.cgi?id=24020

Unlike other specs/components, new Web Components bugs are not announced 
on public-webapps (although like all of WebApps' components, new Web 
Components bugs are announced on public-webapps-bugzilla [which only has 
5 subscribers]).


For consistency reasons, and to facilitate transparency, it seems like 
all new Web Component bugs should be announced on public-webapps. Does 
anyone object to that?


-AB




Re: [WebComponents] List for new bug announcements [Was: Re: Why can't we just use constructor instead of createdCallback?]

2013-12-07 Thread Edward O’Connor
Art wrote:

 For consistency reasons, and to facilitate transparency, it seems like all 
 new Web Component bugs should be announced on public-webapps. Does anyone 
 object to that?

I think that's a fine idea.


Ted



Re: Why can't we just use constructor instead of createdCallback?

2013-12-06 Thread Erik Arvidsson
The custom element draft does add a new synchronization point. After
setting innerHTML (for example), before returning to the script the
callbacks for the custom elements created by innerHTML are called in tree
order.

This does lead to the possibility to observer objects that have not yet had
their created callback been called yet. I think this trade off is
inevitable, no matter whether we use @@create, constructor or created. I
just don't see us being able to call user code every time a node is created.




On Fri, Dec 6, 2013 at 1:58 AM, Boris Zbarsky bzbar...@mit.edu wrote:

 On 12/6/13 1:49 AM, Ryosuke Niwa wrote:

 Then how do we define a custom element using ES6 classes?  Are we going
 to not call the constructor?


 An excellent question, indeed.  I don't have a good answer for you.

 If we do make elements subclassable (which it seems like we should), we
 would presumably need to make the actual default constructor of the
 built-in element classes a no-op, since we can't actually rely on the
 subclass calling it.  All the relevant setup would need to be done by
 @@create.

 Given that, we could maybe cheat and in fact do some sort of delayed
 calling of the constructor of ES6 subclasses of elements.  You'd still be
 able to observe these objects in an unconstructed state from the subclass
 pov, but at least it wouldn't be a security issue in terms of operating on
 a DOM that's in an inconsistent state from the point of view of privileged
 code.

 It's not clear to me how OK such an unconstructed state is.  I suppose
 it's no worse than someone extending the ES6 subclass in question and then
 never calling its constructor...  But that's a programming error on the
 someone's part, typically, while here we would be effectively forcing this
 sort of thing on all Element subclasses.

 All that still seems more palatable than trying to completely revise HTML
 parsing to be robust to constructors running when the element is created

 Might be worth checking on public-script-coord to see what the TC39 folks
 think about all this.

 -Boris




-- 
erik


Re: Why can't we just use constructor instead of createdCallback?

2013-12-06 Thread Erik Arvidsson
On Fri, Dec 6, 2013 at 2:33 AM, Ryosuke Niwa rn...@apple.com wrote:

 It appears to me that we should definitely have a good answer for this
 question before the specification reaches CR
 given that the definition of ES6 classes is pretty stable at this point.


ES6 classes do not introduce any new semantics over ES5. However I do agree
that we need to think about user ergonomics here. If we cannot use ES6
class syntax to do custom elements we have failed. What we have now is OK
but not perfect.

Here is how you can use class syntax today

```js
class MyElement extends HTMLElement {
  createdCallback() {
console.log(I'm not a real boy);
  }
}
MyElement = document.create('my-element, MyElement);

// or

var MyElement = document.create('my-element, class extends HTMLElement {
  createdCallback() {
console.log(I'm not a real boy);
  }
});
```

This works fine in Blink today: http://goo.gl/HZLpqG

The relevant addition to ES6 is how @@create participates in object
creation.

I've previously voiced concern that custom elements do not use @@create and
the spec draft was changed in a way where it would allow using it in the
future. There was strong concern from Mozilla that they did not want custom
elements to depend on this ES6 feature due to them needing
document.register ASAP.

The way this would work without custom elements is:

```js
class MyElement extends HTMLElement {
  constructor(name) {
console.log(`I'm a real boy and my name is ${name}`);
  }
  [Symbol.create]() {
return document.createElement('my-element');
  }
}
new MyElement('Pinocchio');
```

The things that fail here are:

1. The parser does not know that it needs to use MyElement.@@create to
create the JS objects when it sees a my-element.
2. No callbacks for enteredView, leftView and attributeChanged.
3. It depend on the magic of document.createElement which is circular. A
better way would be to do `super('my-element')` or something like that.

I wish we could resolve these remaining issues.

-- 
erik


Re: Why can't we just use constructor instead of createdCallback?

2013-12-06 Thread Ryosuke Niwa

On Dec 6, 2013, at 7:37 AM, Erik Arvidsson a...@chromium.org wrote:

 On Fri, Dec 6, 2013 at 2:33 AM, Ryosuke Niwa rn...@apple.com wrote:
 It appears to me that we should definitely have a good answer for this 
 question before the specification reaches CR
 given that the definition of ES6 classes is pretty stable at this point.
 
 ES6 classes do not introduce any new semantics over ES5. However I do agree 
 that we need to think about user ergonomics here. If we cannot use ES6 class 
 syntax to do custom elements we have failed. What we have now is OK but not 
 perfect.
 
 Here is how you can use class syntax today
 
 ```js
 class MyElement extends HTMLElement {
   createdCallback() {
 console.log(I'm not a real boy);
   }
 }
 MyElement = document.create('my-element, MyElement);
 
 // or
 
 var MyElement = document.create('my-element, class extends HTMLElement {
   createdCallback() {
 console.log(I'm not a real boy);
   }
 });
 ```

What if that class definition had constructor() in it?  It would be called?  If 
so, when?

 1. The parser does not know that it needs to use MyElement.@@create to create 
 the JS objects when it sees a my-element.
 2. No callbacks for enteredView, leftView and attributeChanged.
 3. It depend on the magic of document.createElement which is circular. A 
 better way would be to do `super('my-element')` or something like that.
 
 I wish we could resolve these remaining issues.

In fact, fixing these issues is a requirement for us.

- R. Niwa



Re: Why can't we just use constructor instead of createdCallback?

2013-12-05 Thread Dimitri Glazkov
There were several threads around this in March/April, but the main gist is
that we can't allow running user code when the parser is building the tree,
and thus we would need to decouple the timing of the constructor being
called from the [[Construct]] internal method to make constructors
workable. But then they aren't constructors, but callbacks, since the
object would already be exist (and be in a tree). So we decided to not lie
and just call them callbacks, rather than constructors.

http://lists.w3.org/Archives/Public/public-webapps/2013JanMar/0728.html
http://lists.w3.org/Archives/Public/public-webapps/2013AprJun/thread.html#msg152
I am probably forgetting some...


:DG


On Thu, Dec 5, 2013 at 5:31 PM, Ryosuke Niwa rn...@apple.com wrote:

 Could someone point me to a discussion/reasoning behind why we're using
 createdCallback as opposed to the constructor
 as a way of instantiating a custom element?

 It's so awkward to have a separate callback in the world where we have ES6
 classes.

 - R. Niwa





Re: Why can't we just use constructor instead of createdCallback?

2013-12-05 Thread Ryosuke Niwa
On Dec 5, 2013, at 8:43 PM, Dimitri Glazkov dglaz...@chromium.org wrote:
 There were several threads around this in March/April, but the main gist is 
 that we can't allow running user code when the parser is building the tree, 
 and thus we would need to decouple the timing of the constructor being called 
 from the [[Construct]] internal method to make constructors workable.

That sounds like an implementation detail of Blink/WebKit.  Also, JS wrappers 
aren't even constructed immediately for builtin elements in WebKit and Blink so 
delaying the construction of elements until later time (e.g. end of micro task) 
seems fine.

 But then they aren't constructors, but callbacks, since the object would 
 already be exist (and be in a tree). So we decided to not lie and just call 
 them callbacks, rather than constructors.

It would be extremely unfortunate if authors can't use constructor() in the 
world we have ES6 classes.

class MyButtonElement extends HTMLElement {
constructor() {
...
}
}

looks much more natural than

class MyButtonElement extends HTMLElement {
constructor() {
// Would I ever be called? If so, when?  Is that safe?
}
createdCallback() {
...
}
}

 http://lists.w3.org/Archives/Public/public-webapps/2013JanMar/0728.html
 http://lists.w3.org/Archives/Public/public-webapps/2013AprJun/thread.html#msg152
 I am probably forgetting some…

Thanks for the pointers again.

- R. Niwa



Re: Why can't we just use constructor instead of createdCallback?

2013-12-05 Thread Dimitri Glazkov
On Thu, Dec 5, 2013 at 9:03 PM, Ryosuke Niwa rn...@apple.com wrote:

 On Dec 5, 2013, at 8:43 PM, Dimitri Glazkov dglaz...@chromium.org wrote:

 There were several threads around this in March/April, but the main gist
 is that we can't allow running user code when the parser is building the
 tree, and thus we would need to decouple the timing of the constructor
 being called from the [[Construct]] internal method to make constructors
 workable.


 That sounds like an implementation detail of Blink/WebKit.  Also, JS
 wrappers aren't even constructed immediately for builtin elements in
 WebKit and Blink so delaying the construction of elements until later time
 (e.g. end of micro task) seems fine.


FWIW, the concern was brought up first by Microsoft's Tony Ross and then
separately Mozilla's Jonas Sicking. Technically, both Blink and WebKit are
capable of doing this. It's just mostly a terrible idea to interrupt tree
construction with user code. Delaying construction of elements until end of
microtask doesn't solve the problem -- you're just shifting the timing of
tree construction.

:DG


Re: Why can't we just use constructor instead of createdCallback?

2013-12-05 Thread Ryosuke Niwa
On Dec 5, 2013, at 9:23 PM, Dimitri Glazkov dglaz...@chromium.org wrote:
 On Thu, Dec 5, 2013 at 9:03 PM, Ryosuke Niwa rn...@apple.com wrote:
 On Dec 5, 2013, at 8:43 PM, Dimitri Glazkov dglaz...@chromium.org wrote:
 There were several threads around this in March/April, but the main gist is 
 that we can't allow running user code when the parser is building the tree, 
 and thus we would need to decouple the timing of the constructor being 
 called from the [[Construct]] internal method to make constructors workable.
 
 That sounds like an implementation detail of Blink/WebKit.  Also, JS 
 wrappers aren't even constructed immediately for builtin elements in WebKit 
 and Blink so delaying the construction of elements until later time (e.g. end 
 of micro task) seems fine.
 
 FWIW, the concern was brought up first by Microsoft's Tony Ross and then 
 separately Mozilla's Jonas Sicking. Technically, both Blink and WebKit are 
 capable of doing this. It's just mostly a terrible idea to interrupt tree 
 construction with user code. Delaying construction of elements until end of 
 microtask doesn't solve the problem -- you're just shifting the timing of 
 tree construction.

I'm not suggesting to do that.  Simply call the constructor at when 
createdCallback is currently called.

- R. Niwa



Re: Why can't we just use constructor instead of createdCallback?

2013-12-05 Thread Boris Zbarsky

On 12/6/13 12:03 AM, Ryosuke Niwa wrote:

That sounds like an implementation detail of Blink/WebKit.


It seems like a pretty fundamental restriction for all current HTML 
parsers.  In particular, the HTML parsing algorithm has no provisions 
for script mutating the DOM at random points in the algorithm (in fact, 
pretty much anywhere other than when script elements are inserted).



Also, JS
wrappers aren't even constructed immediately for builtin elements in
WebKit and Blink


Now _that_ is a WebKit/Blink specific implementation detail (though one 
shared by other browser engines at the moment).  Last I checked, Servo 
plans to have a single JS object for an element, not separate actual 
object and JS wrapper objects.  And it seems like we don't want to 
preclude that sort of implementation strategy, which requires that the 
ES object be created when the element is created..



so delaying the construction of elements until later time (e.g. end of micro 
task) seems fine.


End of microtask is not acceptable, unfortunately.  It would mean that 
if you set innerHTML on a node and then try to touch its new kids you 
get not-yet-constructed objects.  :(


We could try to invent a new synchronization point for this sort of 
thing (e.g. similar to Gecko's scriptrunners), but any such setup with 
delayed construction has a significant failure mode in the innerHTML 
case: When one of the constructors is running, the other nodes that got 
inserted are still in a not-constructed state.  That doesn't seem great.


Which then puts us back to running script while the innerHTML parser is 
running.  Which is also not great.  For example it would completely 
preclude any attempts to parallelize innerHTML parsing.  And yes, I know 
those might be doomed to failure anyway...


I can't tell you how you should weight these various drawbacks, obviously.

-Boris



Re: Why can't we just use constructor instead of createdCallback?

2013-12-05 Thread Ryosuke Niwa
On Dec 5, 2013, at 10:44 PM, Boris Zbarsky bzbar...@mit.edu wrote:

 On 12/6/13 12:03 AM, Ryosuke Niwa wrote:
 That sounds like an implementation detail of Blink/WebKit.
 
 It seems like a pretty fundamental restriction for all current HTML parsers.  
 In particular, the HTML parsing algorithm has no provisions for script 
 mutating the DOM at random points in the algorithm (in fact, pretty much 
 anywhere other than when script elements are inserted).
 
 Also, JS
 wrappers aren't even constructed immediately for builtin elements in
 WebKit and Blink
 
 Now _that_ is a WebKit/Blink specific implementation detail (though one 
 shared by other browser engines at the moment).  Last I checked, Servo plans 
 to have a single JS object for an element, not separate actual object and 
 JS wrapper objects.  And it seems like we don't want to preclude that sort 
 of implementation strategy, which requires that the ES object be created when 
 the element is created..
 
 so delaying the construction of elements until later time (e.g. end of micro 
 task) seems fine.
 
 End of microtask is not acceptable, unfortunately.  It would mean that if you 
 set innerHTML on a node and then try to touch its new kids you get 
 not-yet-constructed objects.  :(
 
 We could try to invent a new synchronization point for this sort of thing 
 (e.g. similar to Gecko's scriptrunners), but any such setup with delayed 
 construction has a significant failure mode in the innerHTML case: When one 
 of the constructors is running, the other nodes that got inserted are still 
 in a not-constructed state.  That doesn't seem great.
 
 Which then puts us back to running script while the innerHTML parser is 
 running.  Which is also not great.  For example it would completely preclude 
 any attempts to parallelize innerHTML parsing.  And yes, I know those might 
 be doomed to failure anyway...
 
 I can't tell you how you should weight these various drawbacks, obviously.

Then how do we define a custom element using ES6 classes?  Are we going to not 
call the constructor?

- R. Niwa




Re: Why can't we just use constructor instead of createdCallback?

2013-12-05 Thread Ryosuke Niwa
On Dec 5, 2013, at 10:58 PM, Boris Zbarsky bzbar...@mit.edu wrote:
 On 12/6/13 1:49 AM, Ryosuke Niwa wrote:
 Then how do we define a custom element using ES6 classes?  Are we going to 
 not call the constructor?
 
 An excellent question, indeed.  I don't have a good answer for you.

It appears to me that we should definitely have a good answer for this question 
before the specification reaches CR
given that the definition of ES6 classes is pretty stable at this point.

 If we do make elements subclassable (which it seems like we should), we would 
 presumably need to make the actual default constructor of the built-in 
 element classes a no-op, since we can't actually rely on the subclass calling 
 it.  All the relevant setup would need to be done by @@create.
 
 Given that, we could maybe cheat and in fact do some sort of delayed calling 
 of the constructor of ES6 subclasses of elements.  You'd still be able to 
 observe these objects in an unconstructed state from the subclass pov, but 
 at least it wouldn't be a security issue in terms of operating on a DOM 
 that's in an inconsistent state from the point of view of privileged code.

Right.  I know it sounds so cheesy but I was suggesting something along that 
line.

 It's not clear to me how OK such an unconstructed state is.  I suppose it's 
 no worse than someone extending the ES6 subclass in question and then never 
 calling its constructor...  But that's a programming error on the someone's 
 part, typically, while here we would be effectively forcing this sort of 
 thing on all Element subclasses.

I think the question is how observable such a delay is and what implications it 
would have.

 All that still seems more palatable than trying to completely revise HTML 
 parsing to be robust to constructors running when the element is created….

Indeed.

 Might be worth checking on public-script-coord to see what the TC39 folks 
 think about all this.

Sounds like a good idea.

- R. Niwa