10

So I am a TA for a class at my University, and I have a bit of a disagreement about how to present datatypes for absolute beginner programmers (In which most never programmed before). My teacher tells students they must strictly use constructors to create primitive datatypes such as Numbers and Strings, her reasoning is to treat JavaScript as if its strongly typed so students will be used to the languages that are in the future. I understand why, but I think it has bad trade-offs.

var num = new Number(10); // This is encouraged.

var num = 10; // This is discouraged (students will lose points for doing this).

My instructor does not make a distinction between these and students are told to treat them as if they are primitive Numbers, Strings, etc. Although I believe at least for starters who don't know better to use datatype.valueOf() when necessary, and don't know much at all what objects are yet. Literal notation would be (and I consider it to be) more proper and standard, the other way would cause confusion. Since there a consistency issues with constructor notation because they are objects (and I don't want students to worry about that). For example these don't make sense to beginners:

var num1 = new Number(1);
var num2 = new Number(1);

if(num1 === num2) ... ; // Does not run.    

if(num1 == num2) ... ; // Does not run.

if(num1 == 1) ... ; // But this does.    

var num2 = new Number(2);

if(num1 < num2) ... ; // So does this.

switch(num1){
    case 1:
        ...  // Does not run.
        break;
    default:
        ... // This runs
        break;
}

As you can see this would be confusing for someone just learning what an if statement is.I feel as if she is encouraging bad practice and discouraging good practice. So what do you think between literal and constructor notation for primitive values, which is considered more standard/proper and which is better for beginners to use?

Derek 朕會功夫
  • 92,235
  • 44
  • 185
  • 247
Spencer Wieczorek
  • 21,229
  • 7
  • 44
  • 54
  • 2
    This question might be a good fit for http://programmers.stackexchange.com/ – Colin Brock Jan 28 '14 at 02:14
  • 4
    Never use constructors to create primitives or else you will get unexpected results like this...: `if(new Boolean(false)){ alert("This will get executed for no reason"); }` – Derek 朕會功夫 Jan 28 '14 at 02:14
  • 4
    Wow. I think you already know the answer to this, and this is really just a sanity check. – Mike Robinson Jan 28 '14 at 02:14
  • 1
    Your instructor may have a point to prove, but is out of step with common practice. Javascript is loosely typed, forcing a kind of typeing using objects is just making life way more difficult than it needs to be. Primitives are provided for convenience and mean you can do `a === b`, otherwise you must do `a.valueOf() === b.valueOf()`. – RobG Jan 28 '14 at 02:17
  • 3
    Sounds like *you* should be teaching the class... – monners Jan 28 '14 at 02:18
  • Furthermore, even MDN suggests constructors and primitives are not interchangeable, [example](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean). Even more, `typeof new Number(1)` is NOT `number`; instead, it is `object`. – Derek 朕會功夫 Jan 28 '14 at 02:21
  • 1
    I'd love to see someone actually put the time and effort into a well thought-out answer to this. It's an argument that crops up a lot. – monners Jan 28 '14 at 02:24
  • @Derek朕會功夫 I'm aware they are different. My argument is that they are objects. Misinforming students about primitive datatypes. – Spencer Wieczorek Jan 28 '14 at 02:30
  • @SpencerWieczorek - I know you are aware that they are different from the question. I was just posting some examples to support my claim that using primitives directly is better. – Derek 朕會功夫 Jan 28 '14 at 02:34
  • Thank you for you answers everyone. Although I would like to point out that the class is for client-side programming. Hence the reason why JavaScript is used, we use Python (a good starting language) for the main curriculum. – Spencer Wieczorek Jan 28 '14 at 14:19

4 Answers4

8

As someone who spent extra time creating a main function in every Python program so that we'd be more prepared for Java's public static void main when the time came, there is a place for slightly-less-than-best practices when it comes to learning how to programming.

Now a teacher myself, using constructor functions in JavaScript is not that place. First, it results in misbehavior with control flow, an essential part of the beginning steps of programming. Secondly, it does the students a disservice by mis-teaching an essential language in the web developer's toolkit. Finally, it does not prepare one for constructors! As a side note, JavaScript does not easily fall into any typical programming paradigm, and as such is unsuitable as a first language in a four-year college curriculum (in this author's opinion).

Constructor functions block understanding of control flow

Firstly, let's look at control flow. Without control flow, a beginner may never be able to construct anything more complex than Hello world. It is absolutely essential for a beginner to have a solid understanding of each item in the control flow basket. A good instructor will provide several examples for each type, as well as a full explanation of what the difference is between true and truthy.

Constructor functions completely ruin a beginner's understanding of control flow, as in the following example:

var myBool = new Boolean(false);
if (myBool) { console.log('yes'); } // 'yes' is logged to the console.

Yes, this is one of JavaScript's 'wat' moments. Should the language act like this? Probably not. Does it? Absolutely. Beginners need to see simple examples that make sense to the uninitiated mind. There is no brain space for edge cases when first starting out. Examples like this only do a disservice to those the professor is supposed to be teaching.

Constructor functions have no place in JavaScript

This one's a bit more opinion-based. A caveat: JavaScripters may find some use for constructor functions in using them to convert between types (i.e. Number('10')) but there are usually better ways.

Virtually every time a constructor function is used in JavaScript, it's a misuse. I am of the mind that if one wants a literal number, just write that out. No need for all the extra typing, not to mention the various type conflicts and hidden gotchas that come from using constructors](https://stackoverflow.com/a/369450/1216976).

It's worth noting that both JSLint and JSHint (written by people much smarter than I) discourage the use of constructors in this fashion.

Community
  • 1
  • 1
SomeKittens
  • 38,868
  • 19
  • 114
  • 143
  • I'll be back to add more in a bit, oven's beeping. – SomeKittens Jan 28 '14 at 02:33
  • 2
    I am of two minds here. On one hand, the number of gotchas in JS make it pretty unsuitable as the first language. On the other, learning JS after a class-based OO language makes understanding the prototypal inheritance philosophy harder. I guess my ideal progression would be Scheme -> JS -> Proper OO (e.g. Ruby/Java): but I could totally be wrong. And when you do teach JS, teach it according to Crockford's *JavaScript: the Good Parts* to avoid the warts. – Amadan Jan 28 '14 at 02:44
  • I would agree somewhat with your progression, but Ruby is not 'proper' OO. – SomeKittens Jan 28 '14 at 02:50
  • Somewhat off topic, but - How so? Dynamic dispatch: check (duh). Encapsulation: check (can't even access instance variables except through accessors or reflection). Inheritance: check (all inheriting from `BasicObject`). Open recursion: check (`self`). What would you say is missing? (And before you say "strictness" or "class immutability", I haven't seen a single definition of OO where that is a criterion.) Then again, JS is an OO too, although not a class-based one (for which I unthinkingly used "proper", th very proof one should learn JS before one is indoctrinated into class-based paradigm) – Amadan Jan 28 '14 at 06:21
6

new Number(1) and 1 are not the same. The first one is an Object, and the latter one is a Number.

var num = new Number(1);
typeof num;    //object

var num = 1;
typeof num;    //number

In order to get the value of the object created by the constructor, one must use valueOf every single time in order to get a correct result.

if( new Boolean(false) ){            if( new Boolean(false).valueOf() ){
    console.log("True");                 console.log("True");
}else{                               }else{
    console.log("False");                console.log("False");
}                                    }

//> True                             //> False
//Student Be Like:                   //Student Be Like:
// What?! That doesn't even make     //Okay that makes sense.
// sense!

Because of the fact that using constructors will only confuse more learners and will cause more problems in further development of your program, IMO primitive constructors should never be used. (except in certain cases.)

Furthermore, using Constructors every time you declare a variable will greatly impact your execution speed because of the fact that allocating spaces for a new object takes longer than just a simple 64-bit floating point number. Here is the comparison: http://jsperf.com/constructors-vs-literalss

tl;dr

var num = new Number(10);  // bad, never do this, prone to errors

var num = 10;              // do this instead

Every time when there's a literal and your don't use it: Very likely to be bad code.

new Boolean(false);    // bad
new String("foo");     // bad
new Object();          // not as bad as the ones above, but still bad
new Array(10);         // bad, it initializes the array with
                       //  not-your-normal `undefined`
pushkin
  • 9,575
  • 15
  • 51
  • 95
Derek 朕會功夫
  • 92,235
  • 44
  • 185
  • 247
1

Starters or not, prefer primitives. I think this question is no different than the primitive or boxed primitive question in Java.

Using primitives is simpler and more expressive: Number, Boolean or String although available objects in JavaScript are Objects and not just the values. To quote Joshua Bloch from effective Java: 'Objects have identities apart from their values.' When you refer to a Number object its not the same as number value. When we are dealing with a numbers its the value we usually are bothered about. Primitives save the additional effort of understanding it as object for the developer as well as on the readers' part.

Equals comparison: equals comparison of objects with = operator is actually the reference comparison, which is always misunderstood and creates scope for errors.

Primitives are faster: (proof needed?) Why bother with object creations when it's just the value that matters to us?

Type validation in exposed functions: JavaScript being loosely typed we at times require a failsafe type check in exposed functions. Say a general check on type: typeof param === "string" or "number". You give me an "object" m not gonna spend time in guessing what object you might be passing..

The only places I have used a Number constructor is when parsing strings to numbers. My work has mostly been development on a banking product and I would rather take a NaN than guess a number using parseInt (different question altogether).

NikhilWanpal
  • 2,960
  • 3
  • 23
  • 40
1

First of all if you're a teaching assistant at a university then you should tell your professor not to teach JavaScript as an introductory language to students. The reason is that JavaScript is:

  1. Ambivalent about the kind of a language it wants to be: functional vs object-oriented.
  2. Too unintuitive: many a times it doesn't behave the way you would expect it to.
  3. Too verbose: there are too many syntactical elements diverting your attention.

JavaScript is not a suitable introductory language. It's not even a suitable production language which is why we have LiveScript and other compile-to-javascript languages.

Since you're a teaching assistant I would highly recommend that you read Bret Victor's amazing blog post on Learnable Programming. It describes the constituents of a good introductory programming language.

Anyway, I digress. Coming back to the original question, "Literal vs Constructor notation for primitives, which is more proper for starters?" This question is a no-brainer. You know the answer: literals.

I surmise that your professor is trying to teach the following point to the students:

Everything in JavaScript is an object.

Now while it's ideal to think about everything in JavaScript as an object this ideal is too far-fetched. Primitives are not objects. Primitives consist of:

  1. Undefined.
  2. Null.
  3. Booleans.
  4. Numbers.
  5. Strings.

I think your professor is confusing JavaScript with Java which advocates that everything is an object (which is actually not true because you still do have primitives in addition to classes, interfaces, etc.)

JavaScript is more object-oriented than Java simply because everything (except for primitives) is an object. You don't have classes in JavaScript. Objects simply inherit from other objects.

On a sticky side note here's a good analogy to explain the difference between primitive vs reference values to students: Primitive value vs Reference value.

Now although you do have primitives in JavaScript you also have wrapper objects for these primitives (i.e. Boolean, Number and String constructors) so as to treat them as objects.

These wrappers expose several useful utility methods. For example you could do: 42..toString(2) to get the value of 42 in binary as a string. As you can see JavaScript coerces the primitive value 42 into a Number object automatically when you call a method on the primitive. Hence it makes no sense to create wrapper objects for primitives explicitly. Read The Secret Life of JavaScript Primitives.

In fact if you really wanted a wrapper object instead of a primitive (for performance reasons) the I would do it as follows:

Object.prototype.getObject = function () {
    return this;
};

var yes = true.getObject();
var answer = 42..getObject();
var greet = "hello".getObject();

This actually makes more sense to me. You're taking a primitive, coercing in into an object and returning the coerced reference value. By the way, 42 is an allusion to The Hitchhiker's Guide to the Galaxy.

Beside being more succinct another good reason to use literals over wrapper objects is mathematical equivalence. As you described in your question it's desirable to be able to compare two values for mathematical equivalence. Objects break mathematical equivalence. Since objects have a distinct identity two mathematically equivalent objects may not be logically equivalent. For example:

console.log(new Number(42) === new Number(42)); // false

To solve this problem you need to convert the numbers to primitives using valueOf:

console.log(new Number(42).valueOf() === new Number(42).valueOf()); // true

It's really asinine to write code like this. Why circumscribe yourself to such unnecessary hacks when you could write clean understandable code?

console.log(42 === 42); // true

Everyone know thats 42 is indeed 42 but not many beginners would understand why two objects which are mathematically equivalent are logically distinct.

To summarize, when you're teaching somebody how to program you need to make sure that your code is intuitive (i.e. it shouldn't work in unexpected ways). If it doesn't work the way you would expect it to work then you're doing something wrong. You'll end up struggling with the language instead of writing useful programs.

Community
  • 1
  • 1
Aadit M Shah
  • 72,912
  • 30
  • 168
  • 299
  • Thank you for your answer! Although the class is web-development based ( 'Client-side Programming' is the title ), our primary programming introduction course uses Python. The reason why it's so many students first language in the class is that many come from HTML/CSS class onto a JavaScript class. – Spencer Wieczorek Jan 28 '14 at 03:48