Showing posts with label FastDOM. Show all posts
Showing posts with label FastDOM. Show all posts

Saturday, June 27, 2015

Why Event Constructors are Way Better than Methods

Most developers will never need to deal with synthetic events and event constructors. You should be entirely fine hooking existing event handlers who already provide a fully filled out event object specific to the event which is being fired. Let's take a couple of examples of existing events. We'll do an onload handler which is really basic and an onclick handler which contains a ton of information.


The logging output from this shows us that the load event fires a standard Event and that we inherit from Event. The click event instead fires a MouseEvent and inherits from both Event and UIEvent. This will be key in our understanding of why event constructors are a very necessary improvement to the specs. The inheritance of more specific events from less specific events creates a versioning issue that has to be solved if you want to add new members to the base event types without existing code having to change. This becomes more obvious when we look at the init methods and how they are organized.

Init Methods


At each level in the hierarchy we have both a way to create an event of a given type and a method which initializes ALL of its members. For the Event.initEvent there are 3 members. The type of the event (which is really more like a name), whether or not it bubbles and whether or not it is cancelable. Pretty basic stuff. So to create and initialize an Event we'd run the following code.


A mouse event should be pretty easy too then right? Well, not really. The first thing to note is that the MouseEvent.initMouseEvent method takes 15 parameters. The first 3 of those parameters are the same as the initEvent method from earlier. Hum, and we have a UIEvent in our hierarchy so maybe some of those other parameters are also inherited. Turns out UIEvent.initUIEvent does exist and it takes 5 parameters (3 from initEvent and the remaining 2 specific to itself). Let's create a mouse event so we can see how tedious it is. We will also initialize a new mouse event from an existing one, which is fairly common for frameworks to do so they can overcome browser quirks related to preventDefault and return value behaviors.


It isn't easy to figure out and type 15 parameters. Many of the parameters have the same types and JavaScript is so nice that most of the time it would do conversions for you as well even if you got it wrong. This all conspires to make it hard to "get it right" when filling out an event manually. When we do the copy itself, the format is very verbose as well and we have to duplicate everything and ensure we get the ordering right since if we transposed the ctrl and alt keys, how would anyone ever know? That could fly under the radar on a top site for years.

We can also see that more derived methods are composed from their base class implementations. This means changing initEvent would cause all of the derived methods to shift their parameters. This would easily break the web, since the web doesn't adapt to that kind of change. We also don't want to have to add methods for each version while still maintaining support for the older stuff. We "could" kind of do this because these methods require a specific number of parameters and we could switch on that. Even doing this the developer would often get it wrong and the browser couldn't provide them with meaningful feedback, so the developer experience would be pretty poor.

So how can we solve this problem and get rid of these nasty init methods?

Event Initialization Dictionaries


It turns out, named parameters in other languages try to solve exactly this problem. By making all arguments optional with defaults and allowing the user to specify the ones they want to change by name, you can come up with an approach that versions pretty well. In JavaScript we can implement this functionality as a dictionary. This is a set of name/value pairs that is passed into the initialization method instead of just ordinal values.

Dictionaries in our case are defined in WebIDL. They have many of the same properties as interfaces. They can be derived (good thing, since we need that for UIEvent to derived from Event), they can contain any number of named properties, and each property can be supplied a not-present default. The ordering of properties no longer matters, since we grab them by name. Properties can be added on any base dictionary and they'll automatically be inherited by the derived dictionary.

Finally! We have the ability to enhance the event model, move things around to where they make sense and so without completely breaking all of the shipped code on the web.

Here is a peek at the dictionaries we use for the MouseEvent. Note we eat the complexity here, not you. All you have to do is pass us a simple object replacing only those properties you want and we'll do the rest.


Event Constructors


Now we are ready to tackle event constructors themselves. This is how you build a new event and initialize it at the same time. The created object is still "not dispatched" and so you can also call initMouseEvent or any of the less derived versions as well to change behavior, but ideally everything you would need to set could have been done during construction.

All event constructors take the form new EventType(DOMString type, optional EventInit dict).

When you don't specify a dictionary then this is equivalent to createEvent except that none of the "special names" like "MouseEvents" (note the s) are available. You must specify DOM type which is where the constructor is implemented.

Let's rewrite our mouse events example now using event constructors and see if we can save ourselves from pulling our hair out.


This code is almost readable. We had to specify only 3 parameters this time to match our previous initMouseEvent case and the dictionary is very consumable. The names in the dictionary match the names on the final event. This is actually so powerful that we can commit the first event as the dictionary to our copied event and it will actually work! This is because a dictionary follows the standard JavaScript duck typing patterns we've all grown used to.

Support for Event Constructors


All of the major browsers now support event constructors in their latest releases. Support is not 100% complete or interoperable in all cases though. For instance in EdgeHTML we prioritized the most widely used event constructors and so our support across all events won't ship in Windows 10. Here is a quick list for events we don't support and if you see something on the list that you'd like prioritized feel free to file a Connect bug against us, ping me on Twitter or reply here and we'll see what we can do to bump up the priority.
AnimationEvent, AudioProcessingEvent, BeforeUnloadEvent, CloseEvent, DeviceMotionEvent, DeviceOrientationEvent, DragEvent, ErrorEvent, GamepadEvent, IDBVersionChangeEvent, MSGestureEvent, MSManipulationEvent, MSMediaKeyMessageEvent, MSMediaKeyNeededEvent, MSSiteModeEvent, MessageEvent, MutationEvent, OfflineAudioCompletionEvent, OverflowEvent, PageTransitionEvent, PopStateEvent, ProgressEvent, SVGZoomEvent, StorageEvent, TextEvent, TouchEvent, TrackEvent, TransitionEvent
Even though we are providing an easier and more consumable way to create these native event types, the new events are still synthetic and when dispatched may still not behave like the real thing. Browser's have a lot of protections to ensure the integrity of user initiated actions. Real events generated by the browser set an isTrusted property and this is true only for browser events. You can't change this flag when building your synthetic event. Also, certain actions like opening things in another tab via the ctrlKey or middle mouse button are based on the input stack state and not the state in the event. We've recently seen bugs where pages will craft a new event and dispatch it to try and change behavior associated with the user action.

Futures


Event constructors are fairly new and so there are still some things that don't work spectacularly. It is non-trivial to derive a new event from an existing event. You have to start by having the browser create the most derived type it can, and then from there you have to swap out the prototype chain. Some things will work with this, such as instanceof, but others might not, such as the way your object stringifies.


Some more complicated behaviors we discussed, such as catching an in-flight event, cloning it, and doing your own dispatch tend to not have well defined behavior across all browsers. As time goes on more work will have to be done in the standards around whether or not synthetic events should all have the same side effects as real events. While the side effects of "click" are well understood, could you imagine sending a mouse move event and have it invoke "hover" behavior? And if you never send another mouse move or mouse up or something, have the "hover" be stuck indefinitely?

I hope you enjoyed the latest in my constructor series. If you have any questions feel free to ask my on Twitter @JustrogDigiTec.

Monday, May 25, 2015

Do Browsers Create Closures? Sometimes and Its Ugly.

While trying to simplify and extract the crucial binding bits for the Chakra script engine and EdgeHTML engine, I've come head to head with a complicated set of features in my code. These features are trying to add DOM objects to the scope chain for a special classification of functions that are defined the way they are purely due to historical reasons. We often find that only legacy compatibility can bring out such nastiness.

The HTML 5 functionality that I'm referring to is 7.1.5.1 in the HTML 5.1 nightly. This section is on event handler attributes. By themselves they aren't scary. In fact, setting the onclick property of an element is little different from a script engine binding perspective than using addEventListener. They both take an already compiled function whose environment has already been set up and use it as a callback.

Let's combine them with another concept, the internal raw uncompiled handler, and now you are about to see a train wreck. What we have is a new and special way to construct functions whose environment blocks are not the same as normal JavaScript functions. Instead of using normal closure rules to determine how variable names are hooked up, we get to instead inject additional objects like the document, a form and even the element into the scope chain. This can be quite counter intuitive since most developers are likely to think that a markup inline handler and setting the attribute handler to a function are going to do the same thing. They don't, and thus the train wreck begins.

TL;DR; You can still vote for F12 to support visualization of this strange behavior on User Voice.

Element Lexical Scopes

Okay, so let's look at the most basic of lexical scope problems. We'll have a button, on which we'll put some variables. We'll establish an onclick handler using JavaScript syntax. And then we'll access our variables by using the this variable. I've also put in a naked access which shows that our default lexical scope is Closure followed by window (Global).


We will do the same thing using an inline event handler. This time, our variable1 resolves to our button since the element was added to the lexical scope per the rules on creating a function from the markup's inline source text. I've also shown that a callout function doesn't inherit these scopes. This is most likely why people don't write code to rely on this behavior since inline event handlers are usually function calls to another method. This strips away a lot of the magic.


Form Lexical Scopes

If an element happens to have a form owner then we inject that into the scope chain as well. This is pretty important, since forms have a lot of special semantics. For instance, they have their own custom namespace that allows you to find elements owned by the form. When dealing with form instances this allows you to get to form children by specifying an ordinal index or the name/id of the element depending on the promotion rules.

An element can even be outside of a form, but also associated with it through the form attribute. This attribute will take the id of the form you want to bind to and now voila you are a member of that forms submit items collections. This technique is so strange and obscure it can even break you out of your containing form and put you in a different once. I'm not sure you'd ever want/need to do that, but if you want to, you certainly can.

The form gets injected between your element and document. This means you now have 3 new scopes, not normally available to you, in your namespace lookup. The following code snippet exploits all of these behaviors for you so you can play around with them. In this case I'm not showing the fallback to a normal property handle or addEventListener, but note the scopes melt away as you would expect in those cases.


Document Lexical Scopes vs Global Scope

I wanted to exploit a situation where you would get a different value if you used markup inline event handlers versus the property based event handler. The place where this can bite you the easiest is when dealing with differences between the document implicit namespace and the window frames namespace. Here are how the collections break down and I'm also giving them names very close to what we have in our sources:

  • window - frames collection - Returns IFRAME and FRAME elements. When indexed returns their WindowProxy of type [object Window].
  • window - window collection - All named items in the document. When indexed returns them as an element. Prior to EdgeHTML we did not count objects in forms. For WebKit Interop EdgeHTML now counts all elements, regardless of whether or not they are in forms.
  • document - navigator document collection - Can you guess this one is named after Netscape Navigator ;-) This is another smorgasbord collection of random stuff. Images, iframes, objects, embeds, images... The HTML 5.1 Nightly has the write-up on the specific conditions of this collection at the bottom of the document object section.
When looking up on the document, we only have one namespace to retrieve from. However, when looking up from the window, we have 2. We first lookup in the frames collection before falling back to the window collection. This all blows up when you inject the document into the lookup, and you have more than one element or object that collides by name. The following example shows collisions between multiple named items for iframe/embed objects and shows how this collision is avoided by normal function bindings vs markup inline event handlers.


Wrap up

Don't use inline event handlers.

EVER!!!

They are decrepit legacy bindings with some rather non-trivial behavior backing them. And I didn't even get into all of the complexities involved. For instance, since you can't define your own parameter name to accept the event object, we have to create a named parameter called event so you have something to bind to. If we didn't you might be able to get window.event directly, but there is code on the web that just access event. This in turn will break if the element, form or document has a property or named object named event. Wow, how fragile is that!

Figure 1: Chrome showing Lexical Scopes
That said, if you have an interesting use case for when to use one I'd love to hear about it. I'm sure there are some clever uses out there somewhere. For now, this feature feels too much like the with keyword which I hate with a passion. In fact, I think that is how V8 implements these custom scopes, since in their dev tools they display them as With Block's. You can see this in Figure 1.

Sadly these intricate details are not available in the F12 toolbar making them seem like even more magic. I will add a user-voice to this article shortly after posting. I'd like to refer to it, along with the captured image of the Chrome developer tools when describing the behavior I'm after. A chicken and egg problem for sure ;-)

Update: Here is the new link for F12 Support of showing these scope chain items.

Sunday, May 17, 2015

Chrome and Shadow Constructors

Up until now we've discussed that a constructor object is a highly visible (attached to the Global by name) function that provides you access to the type system of a given type. While the prototype describes what you can do with a type and in fact is stored on each instance, the constructor is how you begin playing with a type system before you have any knowledge of what might be available.

That is why the next type of constructors, for which we currently have no WebIDL syntax, is actually kind of interesting. I'm calling them Shadow Constructors, though my first thoughts on a proper naming scheme are to use a custom attribute [Hidden] on the interface definition to note that when building the constructor itself, it should not be attached to the Global namespace. Were we to implement such a feature only in EdgeHTML and before WebIDL had such support we'd probably define it as an [msPrototypeObjectOnly]. This would be in stark contrast to the previously described [msInterfaceObjectOnly] which describes a constructor from which no instances can be made.

So what does this odd entity look like and why might it be important?

StyleMedia

The StyleMedia constructor is pretty much dead. FireFox has acknowledge this and removed it completely. There is no StyleMedia constructor and there is no window.styleMedia property instance to retrieve.

Chrome has taken a different approach. They removed the StyleMedia constructor, but they still have a window.styleMedia property and in fact, this also returns an instance, whose constructor is, you guessed it, StyleMedia. So how is that even possible? Well, they clearly implemented some form of Shadow constructors to make this happen. While I can't comment on how this works in their system, in my own FastDOM implementation it would simply be a flag controlling whether or not I set the constructor into its slot on the Global after creation.

Finally, in EdgeHTML, we still have this legacy. Primarily, since we support the instance and we tend towards a purist view that if you can have an instance you should be able to both a) find and b) impact its type system using standard methods. That said, the differences in all 3 browser type systems is concerning and maybe worth a look at doing something. My first proposal would be to remove the legacy styleMedia property. That cleans up the most, but if this is untenable as determined via use counters then Shadow constructors are a good middle-ground I suppose.

What do you guys think about Shadow constructors? Do they seem useful as a tool for slow deprecation? Could they be used to hide Browser specific capabilities by NOT exposing them on the Global?

Feel free to have a conversation in the comments or reach me @JustRogDigiTec.

Thursday, May 14, 2015

Implementing Pure Static Browser Constructors

While working on Constructors by Construction in JavaScript, MSHTML and EdgeHTML I left out a few interesting details that might be useful to others. Specifically, I left out the concept of a purely static interface, where you will never provide any instances of said object, have no need of a prototype and simply want to hang constants, methods and properties off of something other than the Global. You also don't want to provide a fully prototyped instance, just to give access to a namespace of methods. Think about the various collections of APIs that exist on the window today, under sub-objects, that could have effectively been static methods and properties in a namespace. A primary example being singletons like the navigator and history objects.

Okay, those aren't GREAT examples, but they are good examples. The instance in that case may make sense if you want to execute in the context a window other than your own. In that case the instance makes sense and you can pass it around as you see fit. But the same can be said for Constructor with static methods on it. For instance, take an existing Constructor like Node and pass it around. People can still access constants on it like ELEMENT_NODE even across window boundaries (assuming same domain) so the Constructor itself behaves like an instance and we do construct one of those per document.

So for the FastDOM type system, we decided it was necessary to make a non-conforming WebIDL construct to support this behavior. We call it the [msInterfaceObjectOnly] attribute and it can hang off of an existing interface to give us the behaviors that we want. If we were to propose this into WebIDL it'll probably get a much nicer syntax such as replacing interface with module or namespace.

msInterfaceObjectOnly support

So the following is the list of things that msInterfaceObjectOnly does. First and foremost it creates a Constructor the interface by name. In our case check out the NodeFilter interface which is kind of defined to be a callback interface in the spec and there are even rules around the callback interface keywords and how to code generate. Our implementation predates all of those rules and so we've continued to use our existing mechanisms

So try it out in the toolbar. Bang out NodeFilter and hit enter. You'll get some output that is either an object (IE 9 through IE 11) or you'll find a Function is returned in either Chrome, FireFox or EdgeHTML. Nice, we all agree there. Also, so we can all be on the same page, here is a listing of how our version of NodeFilter is defined.



Our next difference from a standard interface is that we should NOT have a prototype. Why? We can't create instances of this guy. It exists solely to promote the constants into the type system. Note if you try this in Chrome stable it looks, oddly, like NodeFilter does have a prototype and even more strange, there is a native function called acceptNode hanging off of said prototype. I'm a little bit confused by that, since that doesn't match the spec, but maybe there is some a cool use case there. If anyone knows feel free to leave a comment!

The interface also describes criterion for what it takes to supply a custom NodeFilter to APIs. Basically that an acceptNode method must exist or that the function passed in must itself be callable. This is a bit confusing so I'll state it one more way, you can either pass in a function directly to an API taking a NodeFilter and it will be called directly, or you can pass in an object that has property named acceptNode that returns a function that will be called instead.

Since we have some constants, they must be placed on our Constructor instance. This is no different from a normal interface binding, except that since we don't have a prototype, we won't mirror the constants on the prototype as well. Constants  are kind of interesting. If you get their property descriptor you'll find that they are writable: false and configurable: false. They can't be reconfigured, shadowed or updated in any way, which is good, since they ARE constants after all.

Statics

The last interesting bit is that we like to define things on these special constructors as 'static'. This way you can use the name of the constructor like a namespace. Only methods and properties can be made to be static. Constants are already static by their definition so they don't need to be augmented with the keyword to work.

When we see a static, we define the method or property directly on the Constructor instance just like we do for the constants. This is somewhat interesting in that when the method or property is called your 'this' instance is actually the Constructor object and not an instance. This means you have to do a bit of work to figure out where and how you are being called, but as these are statics, once you know which engine you are in, you only care about the parameters and you can ignore whatever the this pointer is.

Our crowning example of this is an object most web developers won't be familiar with. The MSApp object which we define when you are running inside of a WWA. It allows you to access a scheduler like system on the thread. These types of systems don't need instances to hang off of and so they naturally fall into the model of using statics. Here is a trimmed version of the webIDL for this type.



Hopefully this is enough for you to see the pros and cons of the static model and also why we'd implement this for some of our behaviors. You often see this model in JavaScript in the form of modules, namespaces and singletons. It makes the most sense to web developers when the Browser libraries follow the same patterns that they are used to when writing their own libraries.

Futures

So most of this is already available in WebIDL. The static keywords were added a while back and they even feigned support for static properties before any Browser implemented one (it is actually possible that no shipped Browser has a static property, the EdgeHTML engine doesn't currently have any that I know of). 

The closest thing to our msInterfaceObjectOnly attribute is some of the verbage around callback interfaces, but they have additional restrictions that make them not able to be used for our purposes. I'm currently hoping that we can gain support for a module or namespace keyword and remove our custom attribute. Since we have an implementation object in MSApp it would be cool to prototype that up and see it in action. There is also an open question about whether these type system members should be implemented as objects or functions the way other Constructors are. They aren't constructable since they don't have instances, so maybe they shouldn't be typeof function. After all, that does add a lot of extra methods and properties to them by default and it would be handy if they were a much cleaner abstraction.

Hopefully you enjoyed this short addendum to my original Constructor post. Feel free to let me know in comments or ask questions via @JustrogDigiTec.

Sunday, May 10, 2015

Constructors by Construction in JavaScript, MSHTML and EdgeHTML

Today we are going to be talking about Constructors and how they work in both Internet Explorer and Microsoft Edge. This is part 2 in a series about how the browser type system is constructed, the primitives that make it up and how you can use this to your advantage when integrating deeply with the browser. If you have not read Part 1: Type System, then you probably want to take a quick foray. These articles are designed to be read in order unless you are a JavaScript grand master (black belt's, go back and read ;-)

The History of Constructors


It turns out that Constructors in JavaScript are older than dirt and even Constructors in the browser have been around for a very long time. The first 2 supported constructors in IE were the Image and Option constructors. While they did allow you to create instances of the <img> and <option> elements, they weren't REALLY constructors. Here are some of the many infractions they suffered:
  1. They were "object" and not "function" types. This is because they were themselves DOM objects retrieved by property getter lookup when queried by name.
  2. They had a strange create method on them. This was for languages which didn't support the new operator through the DISPATCH_CONSTRUCT functionality of IDispatchEx::InvokeEx.
  3. They didn't have prototype properties that allowed the basic round-trip of constructor -> prototype -> constructor, etc...
  4. There were literally 2 of them for the longest time, then 2 more when XMLHttpRequest and XDomainRequest were added. By the time we added more FastDOM existed and so did a new method for doing constructors that was "proper" ;-)
So that was pretty much the world in IE 5 and 7 modes. When we introduced 8 we introduced MDP or Mutable DOM Prototypes (more information in Part 1 of this blog series) and this introduced a slightly more advanced implementation of constructors.

First and foremost we added names for all of the constructor types for at least the leaf types. This resulted in a little over 100 new constructor objects being added to the window namespace. Still, interrogating an IE 8 type system would be very foreign since the hierarchy represented OUR C++ hierarchy in the code more than it represented anything in a W3C spec. It was a solid attempt to provide value to web developers though and it was pretty cool to interact with the beginnings of a type system.

Just like with our COM implementation of constructors, the new system had some flaws. Here is another list of infractions observed in the IE 8 system:
  1. They were still "object" types, which means you still couldn't see them as functions. You also couldn't use call/apply on them. This may not strike you as odd, but in the same technology we added "native methods" which did support call and apply so it was odd that a constructor did not receive the love.
  2. All of the new methods added the "create" method which mapped to DISPID_VALUE behind the scenes. However, since this was still COM based, it meant that property gets would return the name of the constructor "[object Element]" for instance, and invokes would try the objects factory if one existed.
  3. The prototype properties pointed at an actual object this time around, but the constructor pointed back at a DIFFERENT object than the constructor instance on window. This meant that Element.prototype.constructor !== Element... But Element.prototype.constructor === Element.prototype.constructor.
  4. We didn't yet support new features like the "name" property on the constructors.
So IE 8 was, well, confusing and probably the features were only used by a handful of sites. In IE 9 and FastDOM we wanted to build a fully integrated type system combined with the new Chakra engine that was fully ES 5 compatible. It is here that we'll start describing in more detail how the browser is able to achieve this goal and the types of objects and APIs used to create a seamless JavaScript + Browser DOM experience. To close this down though, even IE 9 had some problems which I'll briefly list and then we'll describe in more detail:
  1. In FastDOM we had a choice of being a "function" or an "object" when making our constructors. The trade-off was memory. A "function" required that we fully initialize the instance with its prototype and any constant. An "object" we could defer this processing until first access. For this reason, we chose only to make objects which had a non-empty constructor function of type "function" and the rest "object".
  2. We in some cases still had "create" functions for legacy purposes. But they were implemented as static methods, a feature of WebIDL.
  3. We tolerated the use of call/apply on some constructors which seemed correct at the time. We still have such a tolerance while other browsers throw.

Constructor Basics


A constructor object is generally a field on the Global instance. It should be a proper-cased. It should be derived from the Function prototype and therefore be of type "function" when queried with the typeof operator. These requirements will mean that it implicitly gets call/apply/bind from Function. It will also get properties for "name" and "length". The name property should reflect the name of the field on the global window.Node.name === "Node", though type system modifications could break this semantic easily. The "length" property should report the number of required arguments. For constructors this should normally be 0 as traditionally all arguments have been optional.

To make this a bit more clear, I wanted to use JavaScript itself to make a mirror of the Node constructor which we'll call ANode. There aren't any complexities here like inheritance, etc... but those aren't actually that complex so this should cover all of the basics.



Also important is to understand what the WebIDL might look like for such an interface. Its very simple, and we'll build on this to add more features shortly.



Basically, the interface keyword specifies that we are building a concrete prototype object. The name in our case is ANode. This construct by itself tells us to build a constructor object, a prototype object with a default super (Object is the default super class), point the constructor and prototype at one another, and finally define a constant and a method.

Check out the definition of the constant itself. The const keyword in this context supplies some additional configuration information for us to follow. The property must be a) configurable: false and b) writable: false. You can't mess with these properties ;-)

Also, since we specified static for the create method, it goes on the constructor instead of the prototype object. Normally, we'd put any attributes or methods directly on the prototype, but not in this case.

There is one additional piece of information that I've left out, but is important. When you define constants, they must be written to both the constructor and the prototype. Our example ANode does not do this so it is technically incomplete, but I've left that out for brevity.

Specifying Constructability

There are two keywords in WebIDL that allow for a constructor function to be specified by a type. The first is the Constructor keyword and the second is the NamedConstructor keyword. The first says, use my current interface name, while the second says, use my specified name. We'll build one of each in the next WebIDL snippet. Namely the Image constructor and XMLHttpRequest.


These annotations simply mean, that we should expect a constructor function to be available for these types. This is how the IE 9 type system would pick between a constructor being an "object" or "function" type. If you didn't have a constructor, then we could get away with you being an "object" type instead and thus get some memory efficiency by deferring construction. This is demonstrated by Figure 1.

Figure 1: Type Configuration for Constructors

Notice how the NamedConstructor resulted in an object and an function that both point to the same prototype. Both constructors represent different ways of referring to objects of that type. The HTMLImageElement is the primary interface and so it gets a complete prototype -> constructor round-trip in the type system. The Image constructor is just an alias or name used in order to build instances of the HTMLImageElement type. The prototype also controls the final object. We don't build Image objects from the Image constructor, we instead return a new instance of the HTMLImageElement type instead.

As of EdgeHTML the "object" constructor difference has been eliminated. In EdgeHTML the HTMLImageElement is also a function. However, it implicitly binds its [[Code]] property to a default constructor function which simply throws. All browsers have this functionality now, so if you tried to execute code such as, new HTMLImageElement(), you would get an exception.

Browser vs JavaScript Constructors


A browser constructor is different from a standard JavaScript constructor in that the implicitly created and passed in "this" pointer is simply discarded. When you build a JavaScript constructor you set up new properties on the passed in "this" and it turns out that the passed in "this" already has its prototype set up and everything is cool. That would even work for the Image case for the Browser since its prototype property also points to the HTMLImageElementPrototype. Alas, things aren't that simple.

Turns out a generic object with a prototype property set up is still NOT an image element. Let's say for now that CImageElement, a C++ type in the backend, actually contains the code to be a full on image with rendering, ability to be put into a tree, etc... So we need one of those instead.

The browser resolve this issue by simply using the constructor to determine the scope of the script engine. Image was a function created by some script engine, that script engine in turn was created by some browsing context, so we get to the browsing context and create an image of the appropriate type.

Consequently this means if you screw up the type system, it doesn't matter. We'll still create the right type. For instance, if you null out Image.prototype, we can still create a proper image, because behind the scenes the browser has a complete and static view of the type mapping. You can still insert prototypes and do other tricks, but you can't fool the browser into creating the wrong type. At least not yet, we'll get to that in the "futures" section ;-).

Wrap-up and Apologies


I'm going to wrap this up. Its already getting very long and I feel like event constructors could be covered in their own right. They are a huge feature and I would do them a disservice by trying to describe them in 3-4 paragraphs. So look forward to event constructors in a future installment and I apologize if this is the only reason you dropped by.

So to wrap up how constructors work in general, you've seen that as a browser we implement the as either native JavaScript objects or as native JavaScript functions depending on the version of the browser and whether or not they have their own [[Code]] property set. For all of these cases we obey the Constructor and NamedConstructor properties to figure out who gets a [[Code]] property and who does not.

Because they are native, working with constructors and prototypes is extremely efficient. From Part 1 I showed that constants are entirely described in JavaScript (the constructor simply points fields at native JavaScript values). Further, the name, length, etc... are all inherited from the built-in Function object. We'll cover prototypes more in Part 3 along with inheritance, but they too are completely, 100% native, JavaScript objects. It turns out the only thing we don't implement natively as script objects are the native bindings, as you can see from the various green boxes spread throughout the diagrams, and also the gold boxes (again referring to Part 1) which describe the native instance of an object which is shadowed by its JavaScript instance.

You also got to see a rather cool feature called static. This was originally not in the WebIDL specification, but was inspired by IE's create methods. We needed a solution to implement legacy compatibility in IE 9 and thus were born static methods on constructors. Static can also be applied to properties (attributes in webIDL) but you'll be hard pressed to find a spec using such a complicated behavior today since usually constants are sufficient for this purpose. That is starting to get into Futures again, so lets just jump in!

Futures


We've been evolving WebIDL and the capabilities of the type system, very, very rapidly. This leads to some interesting potential for future specifications to take advantage of, or even for improvements to existing specifications.

Event constructors, was one such evolution. Once we described dictionaries as a way to describe the parameters of a function in a very loose, sparse way, we could then add a constructor which took such a dictionary and now events are super easy to create. It also beat the 27 parameter behemoth functions that were being created for initPointerEvent. It also allowed us, as browser developers, to begin adding new properties to existing events, without having to constantly evolve the init* methods to contain the new parameters. Basically this was becoming a mess, and constructors+dictionaries immediately rectified the mess.

Another evolution will be static methods and properties. This allows the use of an interface as a namespace on which to hang things. Namespaces or modules are something very familiar to JavaScript developers. We use them all the time to create hierarchies and scopes of isolation. The browser, however, doesn't really use such a model. Instead, we rely on instances to create the hierarchy and our constructors flatten the hierarchy right back onto the global anyway. An example would be things like window.navigator, where effectively all of the capabilities there are static capabilities. There is nothing truly instance based, yet, we use the instance to namespace the properties and methods available there. Shouldn't it be Gamepad.getGamepads() and not window.navigator.getGamepads()? Which one makes more sense to you?

Okay, so we can namespace and module and scope and all of that. What else? How about element constructors? Right now everything goes through document.createElement and then once you get an instance back you have to operate on said instance. IE used to have a strange feature where you could createElement("
") and we would return an instance with some attributes set. That was actually kind of cool and in fact, when we removed that, we broke a lot of sites that relied on it. Imagine if we combined dictionaries with constructors like we did for events? This might allow for some neat scenarios such as creating an element with all of it attributes in one shot. I'm not saying it will happen or even that its a full baked good idea, but its worth thinking about.


I hope you've enjoyed this deep dive into constructors. If I've missed anything or you have a nagging question, feel free to leave me comments or ping me on Twitter @JustrogDigiTec.

Sunday, May 3, 2015

JavaScript Type System Evolution from MSHTML to EdgeHTML

In new Microsoft fashion I left it up to the community to decide what kind of article I would write next. A quick poll with options like how we build our type system or how to write a real-time game loop was put up. After a day, the results seem to be 15 of 27 votes for information on how the EdgeHTML Type System is built. You can view the set of questions and the full results here, http://www.strawpoll.me/4262678/r.

Now, to be clear this is still my personal blog. The details will mostly be rooted in standards and inspection of the browser, but the details will indeed be backed by an intimate knowledge of the details of the architecture. So expect little but be surprised ;-)

Evolution of Prototypes in the DOM

In IE 7 and older modes, IE was a purely COM extensible architecture. The binding from script to the DOM was all through this COM binding, specifically IDispatchEx. This was a complicated interface but its abstraction allowed for some very complicated scenarios. If IDispatchEx were the only binding method then this story might have unfolded differently. Perhaps with an IDispatchEx2 or similar, but it wasn't all there was, and in fact, most of IE was simply an IDispatchEx wrapper around real COM interfaces. COM interfaces favor static binding over dynamic binding and thus most of our DOM was statically, tightly bound to legacy while we wanted to move forward, progressively improving. Something had to give.

Well, IE 8 would not be the release for dramatic improvement on this front. with over 3000 APIs already bound to COM, some sort of stop gap needed to be inserted. It would come in the form of Document Modes and those in turn would drive OM Versions. With 8 we introduced a compatibility mode and an IE 8 mode and with some tricks played on top of IDispatchEx, we could get any script callers who did dynamic binding to dynamically bind to the an alternate version of the interface based on their document mode. This seemed fairly clever at the time and in fact, any system with two versions scales pretty well. The fault would come when we started adding more modes.

The trick was simple, have the script engine know its OM Version and have it pass this information when querying for the interface mapping. You could even get clever and have the same document pretend to be 8 and compat at the same time, since the caller was in charge of noting their version. This also allowed for some clever scenarios. We would eventually rip this out in favor of version locking and callee based versioning in IE 9, but this in turn caused a slightly different set of problems.

But what about prototypes? Well, IE 8 was released with MDP or Mutable DOM Prototypes. I can find almost no public information about it, but it is out there, and we did write MSDN documentation for it. It allowed you to use some of the later ES 5 methods like defineProperty to reconfigure IE. This was quite a bit of work, was built on top of IDispatchEx, and obeyed all of the OM versioning logic. For the first time, IE would push constructors into the window global type system, allow you to add your own property getters/setters/methods, and those objects would be included in name resolution when script was trying to figure out what to execute on a given instance. We built a minimal inheritance support (so you could derive types), we allowed wrapping of our own native methods so you could do composition, the delete operator started working more reliably. If it weren't completely bolted on to a legacy system whose performance was suffering, with early versions of Chrome demonstrating much faster script execution, it might have stuck.

But it couldn't stick. With slow DOM performance compared to other browsers IE needed an overhaul. We also began to find that not all of the features in ES 5 were going to be possible to implement. And the final straw was the versioning semantics that we had been employing. As we added more and more COM interfaces to provide versioned characteristics of the same API (some APIs have 4 different implementations) the composition problem started to get really bad. COM could undercut your API replacement. If you wanted to log all calls to setAttribute, for instance, there were some callers that could avoid you by going through older internal methods without being redirected properly.

I apologize for all of the history, take a short breather, and we'll move into the modern and stop talking about COM.

Enter IE 9 and FastDOM

IE 9 was when we introduced a brand new script engine which everyone all knows now as Chakra. The primary goals behind Chakra were to improve native JavaScript execution speeds, garbage collection and improve overall Browser performance. Thankfully, we all knew that the existing COM binding was not going to be fast enough for us to build on, since it entailed crossing component boundaries. At the same time Chakra had this insanely fast built in type system model, with JIT support for type system lookups and all of the new ES 5 bells and whistles you could think of. So it was natural that we would create our new type system natively in the script engine. That would solve the lookup problems, but we'd be left with the binding problems. We also needed a way to describe the type system and bindings.

Well, that got to be my full-time project for a release and is what we called FastDOM. FastDOM is a set of compile time and run-time components for interfacing native JavaScript code and type system, with instances of browser components. Its the boundary between the managed JavaScript and the native browser. Most importantly, due to prioritizing JavaScript over COM, it also meant the later could be much thinner. JavaScript got the fast route and COM got to be the wrapper, not the other way around.

Don't get me wrong, this transformation doesn't happen over night. We had, at the time, over 3400 properties and methods to convert. So there were a lot of "go to the COM" redirection bindings. For critical APIs though, we removed this redirection and made super lightweight bindings instead. I'll get more into the details of this a bit later.

So FastDOM was first and foremost a compiler. It took in a modified version of webIDL which describes the prototype hierarchy, methods, properties, constants and any specialized configurations (read-only, not enumerable, etc..., stuff you can do on defineProperty). From there it builds out the code for configuring a full type system of constructors and prototypes. Finally it sets up the engine so that it can then bind instances to the rest of the type system. This is already getting deep, so if you are unfamiliar with some of the concepts, look at Figure 1. It details how all of these objects interact with one another and thus helps to explain the glue code that we have to create to combine them.

Figure 1: Relationships of a Browser Type System

The constructors all become fields, based on their name, on the Global object itself. This had already been there in IE 8 with MDP in the same way. When interrogating the window.HTMLElement, there was something there. A Function object, whose prototype in turn pointed to the HTMLElementPrototype. And that in turn was referred to by any HTMLElement instances to discover its methods and properties.

Figure 1 has its limitations. It doesn't get into the details of the prototype itself, which is important to this discussion. To finish the type system, we have to put all of the types methods and properties onto each prototype. Further, we have to make sure that those properties and methods bind to some appropriate behavior. A setter probably needs to change some state and a method probably needs to run some algorithm. In Figure 2 we add in this missing state for the Node prototype. The edges represent field names that you'd see when writing some JavaScript while the boxes represent different types of objects based on their colors. I've also broken out what is within the script engine and what appears outside of it.

Figure 2: Methods, Properties and Constants, Oh My!!!

So now we can build the final piece of the compiler. For every method and or property, it has to build a native binding in the green boxes and forward that native binding to the instance itself in the gold box nearer the bottom. Our native instance is represented in the script engine as an actual JavaScript object, a proxy of sorts, to the real deal. This is where browsers are really blurring the lines though. Some objects that we create are now purely native to the script engine and have no gold or green boxes. They are implemented purely in JavaScript. For other objects, known as Foreign Objects, we still have a proxy instance, but that proxy has no built in type system. Instead, we can query the objects dynamically asking for which properties and methods it supports instead. Complicated indeed, but hopefully with another 3 months of blogging I can explain it all ;-)

If you don't take anything else away from the article, I do want you to take this. With IE 9 on, IE's type system is entirely in the script engine, with the exception of those foreign objects. That means it is completely interrogatable and it obeys all of the features of ES 5 (actually ES 5.1) and with future installments, it gets ES 6 as well with minimal work, since the objects are implemented as true native JavaScript objects. This is the current evolution you see happening in EdgeHTML as we speak as the binding gets ever thinner. 

This means is that every function instance is a true Function and so anything you can do in JavaScript with one of those you can do to our functions as well. Our constants, are just fields, with actual native JavaScript objects in them as values. So ELEMENT_NODE is just a variable entry with the value of 1. There is nothing in the native side servicing that. Anything we can put into the script engine directly we can and do, for maximum configurability and maximum performance.

The Bindings of IE

So those green boxes are looking interesting right about now. Why do we have them? What do they do? What else do they enable? Well, I'll answer all of that ;-)

We have bindings because at the end of the day, there is still script engine code written in JavaScript and Browser code written in C++. We aren't yet at the cross-roads of a browser written purely in JavaScript where the entire Browser can be JIT'ed and optimized based on usage, etc... That would be super cool, but we simply aren't quite there yet. The C++ code in turn doesn't know about loosely typed JavaScript objects and thus there is some conversion, as specified by the strongly typed language in WebIDL about how JavaScript values get converted into native values. If you've never read the WebIDL binding semantics I highly recommend it. It has a lot of details on how and why APIs work the way they do and can be hugely informative. For instance, the old null becomes "null" conversions when passed to a DOMString method and how to avoid them, etc...

So bindings allow us to convert from JavaScript types to internal types. That also means they let us convert in the other direction. We can for instance, turn a native C++ array into a TypedArray of floats. This is pretty critical if you are WebGL and you need to do it efficiently. The bindings allow for this. You may also discover an error and need to notify the script engine. So the binding layers also translate between the native code error handling system and the exception based mechanism used by the browser.

Bindings also do browser important things that might go unnoticed by web developers. Have you ever wondered why evaluating a property on a prototype object throws an exception? Okay, maybe you've never tried that so let me give an example:
> Node.prototype.nextSibling
Error: Illegal Invocation
Okay so this happens because you've execute the nextSibling "getter" with the this pointer of the prototype object. The prototype object is not a Node instance, and so it can't possibly know how to return a nextSibling. While most JavaScript methods are duck typed, most browser methods are not. They require that the this pointer be of an appropriate type. So the bindings are also in place to validate the native type and make sure it matches the native type of the binding. Consequently we can enforce other constraints as well, such as disallowing construct semantics (don't call my method with the new operator ;-) or ensuring that all required parameters are passed. So yes, we enforce those as well.

Type System in a Nutshell

So that is the evolution of the type system from IE 7 through to current. I'll be expanding on these areas over the next few weeks. I'll be relying on WebIDL and the WebIDL annotations to demonstrate how browsers achieve interesting semantics. For instance, what is [Unforgeable] and how does that impact what you can do in the global scope of a Window or Web Worker? Or how about [Replaceable] and the odd semantics of a read-only property that isn't really read-only ;-)

There is a lot of ground to cover and I'm open to using questions as a way to guide progress. So let me know what you think. Its probably easiest to grab me on Twitter and the resulting Tweetfests should be fun for others as well, @JustrogDigiTec.