Showing posts with label Constructor Series. Show all posts
Showing posts with label Constructor Series. 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.

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.