Undefined and null

Apr 12, 2012 at 3:14 PM

I don't want this to sound like a sterile rant, and I apologize in advance if it does, but I really don't see the need for the Undefined and Null classes. Javascript's "undefined" and .NET's "null" seem to be similar enough to be interchangeable, and as for Javascript's "null" there's System.DBNull which serves the purpose perfectly, as long as I can see (which I admit may be not so long, since I don't know a thing about compiler internals).

I think getting rid of Jurassic.Undefined and Jurassic.Null in favor of null and DBNull.Value, respectively, would be a step towards perfect interoperability between Javascript and other .NET languages.

Any thoughts, Paul?

Coordinator
Apr 12, 2012 at 9:32 PM
Edited Apr 12, 2012 at 9:32 PM

There are actually two types of undefined: a variable is "undefined" when it doesn't exist and it is "undefined" when it is explicitly set to the value "undefined".  These two cases need to be distinguished:


[undefined,].hasOwnProperty(0) === true
[undefined,].hasOwnProperty(1) === false

Jurassic uses "null" to represent the first case and Undefined.Value to represent the second.  If there had been a standard type for undefined, possibly I would have used that, but there wasn't and it didn't really make sense to me to have a custom undefined type and a standard null type.

Of course, in hind-sight I could do some sleight of hand to hide the fact that undefined has two different values and most likely everyone would be better off :-)

Unfortunately, changing it now would be quite a large breaking change.  There's not really any major benefits of switching right now either, given that Jurassic's support for the DLR and dynamic is pretty non-existant.  Possibly I could make the change as part of supporting dynamic, as of some future date.

Apr 13, 2012 at 7:12 AM

I see your point; as a matter of fact, support for dynamic is exactly what I'm trying to achieve. ;-)

I'm not entirely convinced by your example, though. I know that "undefined" has those two meanings, but Object.prototype.hasOwnProperty should check for actual existance of a property, regardless of the value it stores.

Then again, property access should do the same thing (i.e. checking for the property's existance before trying to get its value) and that looks like no small change: every "GetProperty"-like method should become a "TryGetProperty", returning bool and with an out object parameter, to be able to tell a missing property from a null one. I'm thinking about GetPropertyValue, InlineGetPropertyValue, GetMissingPropertyValue, and I just had a glance at the code. Furthermore, since GetMissingPropertyValue is virtual, that would be a breaking change (although probably a welcome one) for code that overrides it.

Not quite a quick fix, indeed... <sigh>

Coordinator
Apr 19, 2012 at 10:01 AM

There are cases, arrays being a good one, where it is cheaper & faster to use a sentinel value to indicate existance or non-existance.  Arrays are a good example.  I want to allocate a block of array elements but somehow store the fact that some or all of them don't exist.  I could have two arrays, one storing the values and one storing the existance/non-existance, but this would be wasteful - it is cheaper just to store null to indicate non-existance and any other value to indicate existance of a value.  Does that make sense?

Apr 19, 2012 at 10:22 AM

It makes a lot of sense. On the other hand, if there was a NoSuchProperty class, similar in code to Undefined and Null, its Value property could be used as a placeholder for non-existant array elements. Sort of an Undefined, but with somewhat reversed semantics. Of course, NoSuchProperty.Value would need to be converted to null when getting a property or array element, and surely there are other use cases I did not think of, waiting to bite me.

Just thinking aloud. ;-) Please don't get me wrong, Paul, I'm not trying to denigrate your work in any way. I use Jurassic on a daily basis, one of these days I'm going to publish an extension library for it (whose embryonic form you can see in the other discussion I recently opened) and all I desire is for Jurassic to be the best it can be. I imagine that every design choice you've made has its rationale; by understanding what that rationale is, I can understand the library better and therefore use it better.

Coordinator
Apr 19, 2012 at 11:56 AM
Edited Apr 19, 2012 at 11:57 AM

The reason I chose null to represent non-existance is because it has the nice property that you don't have to set it - arrays are zero-initialized when they are created.  If I chose any other sentinel value I would have to fill the array after creating it.

Don't worry, I'm not offended.  It's not always easy to intuit the reasoning behind a design decision - and often even when the decision was made with the best of intentions, it can turn out to be a bad decision when you revisit it with the advantage of 20/20 hindsight :-)