# 10: Approaching A New Language: JavaScript and JavaScript Concurrency ###### tags: `Tag(sp22)` ## Logistics and Preview * Class next Tuesday: React * **Class next Thursday: Emmanuel Schanzer guest lecture** * The week after: advanced testing/validation. Emmanuel is co-Director of [Bootstrap](https://www.bootstrapworld.org). Bootstrap is a successful program to teach middle-school algebra via video-game programming. Note that I didn't say "teach computer science"; I said "teach algebra *using* computer science". It turns out that's an important distinction. Bootstrap also has a few other curricula, like physics and data science. Emmanuel has spent a great deal of effort on equity and accessibility in Bootstrap, including supporting visually-impaired students. Expect to hear about designing for real impact in a tightly constrained space, and about what it's like to take accessibility very seriously for legal, as well as ethical, reasons. We timed his visit to precede the start of Project 2, when many of you will be dealing with similar design requirements. This course takes guest-lecture attendance (in-person or virtual) and participation seriously. **Show our hospitality: don't miss Emmanuel's talk, and ask him questions!** ## A Few Words On User Interfaces Some of today's content is on the [slides](https://docs.google.com/presentation/d/1_XKrs-Bds8e7a0pi_CF4qiFy6MF9wCPqB1flnX38AwY/edit?usp=sharing). What makes a user interface "good"? * Are user interfaces always about computer interfaces? No! There's a whole rich history in designing the _steering wheel_, for goodness' sake. And who could forget the slide rule... ![A slide rule](https://i.imgur.com/S7IEq0S.jpg) *A slide rule (image taken from [Wikipedia](https://en.wikipedia.org/wiki/Slide_rule))* Interfaces like the slide rule are good examples of "good interfaces" subject to physical constraints. A slide rule is a mechanical computer---its interface reflects that. We have simpler, easier-to-use calculator interfaces today, but I'd argue that the slide rule was a great interface _for the technology available_. Much additional material is in the slides (link above). But make sure to read the caution below; it's important. ### Caution: Don't Do This There's a saying in customer support: _"Problem Exists Between Keyboard And Chair"_. Sometimes, yes, your users are just missing something obvious. But is that entirely _their_ fault? Blaming the user is a very natural human defense mechanism, but you'll never build something really great unless you actively fight that instinct. Here's an example. We just had to modify the Sprint 2 requirements. Many of you thought that you needed to finish Sprint 1 objectives to succeed at Sprint 2. But, should we have just blamed the confused students and continued as planned? No! **Don't let your own human defense mechanisms get in the way of your goals.** By the way: this is one of the few things I require of final project presentations. If anyone says "PEBKAC", there will be a loss of points. ## JavaScript <A name="js"></A> Why start talking about JavaScript _now_? Because "concurrency" in JavaScript is very different from Java. You've seen some of this in the lab this week. But, more broadly, we're spending time on JavaScript because you're starting to wrestle with a _new language_, and it's a good time to talk about how to learn a new programming language productively. Yeah, it can be useful to read books and articles and ask questions on Ed and check StackOverflow and so on. But there's a sort of deeper checklist I like to follow when learning a new language, and as we follow it for JavaScript together we'll discover a few of the nastier surprise differences. I like to identify language features that I rely on, and experiment with them. Coming up with these facets isn't always easy, which is why we're doing it together. For instance, let's check out _equality_, a deceptively simple and incredibly subtle idea that many languages differ on. I'll use Safari's JS console (Command-Option-C): ```javascript > 15 == "15" true > 15 == true false > 1 == true true 0 == false true ``` Already we've learned a great deal. JavaScript's `==` operator performs type conversion before comparing values. It allows us to pretend that the number `1` is "true" and that the number `0` is "false", but other numbers aren't equivalent to either. Those of you who have programmed in Racket before (CSCI0170): notice this is different from Racket! In Racket, every non-false value (Racket calls false `#f`) is considered true. The same is true in many other languages. JavaScript has a second equality operator, `===`, that checks for equality _without_ type conversion. So: ```javascript > 15 === "15" false ``` Java also has two different types of equality (`==` and the `.equals` method), but there the difference has nothing to do with implicit type conversion, but with references vs. structural equality. JavaScript's implicit conversion adds an extra layer of complexity. ### Java Isn't Always Unsurprising By the way, even Java might surprise you. If you haven't read the Nim Telson posts this semester, what this Java program produces might be surprising: ```java package edu.brown.cs32.fall21.Oct14Prep; public class InterningIsStrange { public static void main(String[] args) { System.out.println("----- new Integer -----"); System.out.println(new Integer(100) == new Integer(100)); System.out.println(new Integer(200) == new Integer(200)); System.out.println("----- valueOf -----"); System.out.println(Integer.valueOf(100) == Integer.valueOf(100)); System.out.println(Integer.valueOf(200) == Integer.valueOf(200)); System.out.println("----- Integer x = -----"); Integer a1 = 100; Integer b1 = 100; System.out.println(a1 == b1); Integer a2 = 200; Integer b2 = 200; System.out.println(a2 == b2); } } ``` In particular, it outputs: ``` ----- new Integer ----- false false ----- valueOf ----- true false ----- Integer x = ----- true false ``` So even languages we *think* we know can benefit from a little experimentation! In fact, time permitting, Tim is going to finish the lecture with an experiment, and is still trying to find good answer... Back to JavaScript. ### Arithmetic Let's try a few arithmetic operators that are often overloaded across different languages. ```javascript > '1' + 1 '11' > 1 + '1' '11' > 1 - '1' 0 > '1' - 1 0 ``` JavaScript tries to "do the reasonable thing" whenever possible. When in doubt, use explicit conversions (e.g., `parseInt`). In fact, let's try a couple more (Credit for these to [Gary Bernhardt](https://www.destroyallsoftware.com/talks/wat) from 2012---it's 4 minutes long; watch it.) ```javascript > [] + [] "" > {} + {} NaN > [] + {} [object Object] > {} + [] 0 ``` "Addition" isn't even commutative in JavaScript, because addition isn't always addition. Do you see why TypeScript is helpful, now? JavaScript lets you throw off the constraints of the type system, but those constraints are like a safety belt on a roller coaster. #### What's Really Happening? The details involve how JavaScript is implicitly converting between different types. Before applying `+`, it converts to a "primitive" type, which for an object is a string. An empty array is converted to the empty string. And so on. The details would consume a full class, or more! Just beware, and embrace types. ### Objects ```javascript cat = {talk: function() { console.log('meow'); }} cat.talk() ``` Objects are collections of fields; there's no sharp distinction between fields that are methods and fields that are data. **Takeaway:** In JavaScript, functions _are_ values. ### Prototypes Objects in Javascript don't have the same sort of inheritance as they do in Java. They have _prototypes_: ```javascript a = {a1: 1, a2: 2} b = Object.create(a) b.b1 = 1 b.b1 b.a2 a.b1 ``` Run these in order, and see what they produce. I added that last one for the first time this year, after realizing I sure _hoped_ it would be `undefined` but wasn't entirely sure. ### New Prototypes are usually set automatically by constructors. Any function can be a constructor if you use `new`: ```javascript function point(x, y) { this.x = x this.y = y } ``` But, be careful. Try these in order: ```javascript pt1 = point(1, 2) x y pt2 = new point(4, 5) pt2 ``` What's going on? It turns out that `this` isn't what you think it is. ### This ```javascript philosopher = {talk: function() { console.log(this); }} philosopher.talk() speech = philosopher.talk speech() ``` The problem is that, in Javascript, `this` is more about context than identity. This can trip up functional programmers as much as OO programmers. (By the way, you can try this experiment in Python with `self`, and in Python `self` _does_ work the way you expect.) In JavaScript, `this` is set a few ways: * During object construction with `new`, `this` is a fresh object. * Globally it begins set to some root object (`window` in browsers). * Most Java-like: When a function is invoked "through" an object (as in the first call above). * There are `f.apply` and `f.call`, used to invoke `f` with a specific `this`. Also, `f.bind(o)` produces a new function, like `f()`, but where `this` will be `o`. * When browsers invoke event handlers, `this` is set to the DOM object. Vitally, but confusingly: `this` is NOT set to an object, `X`, just because you call a function that you got by saying: `const f = X.m;`. It's context, not "the object". #### Beware Yeah, there are OO constructs in JavaScript, like `class`, but they are built atop this foundation. So you might still find yourself encountering bugs caused by the above features. Hopefully, you also see why we switched from JavaScript to TypeScript this year. TypeScript is just JavaScript with types, but in a language like this, getting _some_ help from the type system can be incredibly helpful. ### Blank Space How does Javascript handle blank space? How about the ultimate blank space: new lines? ```javascript five = function() { return 5; } ``` JavaScript automatically inserts semicolons where it believes they are needed. It turns out this often makes sense, but can be confusing. I found [this great StackOverflow thread](https://stackoverflow.com/questions/2846283/what-are-the-rules-for-javascripts-automatic-semicolon-insertion-asi) that explains the policy in detail. ### There's more I could go on. E.g., `var` vs. `const` and how their hoisting behavior differs. There's good info out there, including _JavaScript: the good parts_, which is [available online](https://www-oreilly-com.revproxy.brown.edu/library/view/javascript-the-good/9780596517748/?ar) from Brown's library. The key here is that JavaScript is _very_ different. It's powerful, and many of its quirks actually make perfect sense when writing web UIs. But still, beware, and treat your JavaScript programs like a science project: if you've got weird behavior, _experiment_. And use types when you can. Really. ### Strict Mode You can "opt in" to a less permissive version of JavaScript by enabling _strict mode_. You'll get fewer silent failures (more errors); I prefer working in strict mode where possible. ## JavaScript Concurrency On the surface, JavaScript has _really_ convenient support for concurrency: ``` console.log('1') setTimeout(() => console.log('2'), 5000) console.log('3') ``` But just under that surface, complexity lurks: ``` console.log('1') setTimeout(() => console.log('2'), 5000) console.log('3') while(true) {} ``` What's happening here? JavaScript is a language whose design is _deeply and unavoidably_ tangled with concurrency. Click a button? That's a callback. Need to request information from a login database or fetch an advertising image? That's a callback. And yet, JavaScript itself (barring some modern extensions) is itself _single threaded_. How does it manage to do this? Through a _callback queue_. Every time a callback is registered (as in the `setTimeout` above) it is added to a queue. Crucially, these calls will only ever take place if they're popped off the queue. And they're only ever removed when the main thread of execution has nothing to do. This week's lab contains a lot of content specifically aimed at this complication. ## Code Review Exercise Since TypeScript, we can't run this directly in the console; we need to compile. Still, we can anticipate potential errors... [Exercise link here!](https://forms.gle/3LjKFnZqyGDKVGUt6) ```javascript function sayHello(): number { let toReturn: number = 0 setTimeout(() => { toReturn = 3 }, 5000) return toReturn } function main(): void { const num: number = sayHello() console.log("Num:", num) } ``` <details> <summary>Think, then Click!</summary> ```javascript async function sayHelloAsync(): Promise<number> { let toReturn: number = 0 return new Promise<number>(resolve => {setTimeout(() => { toReturn = 3 resolve(toReturn) }, 5000)}) } function mainAsync(): void { sayHelloAsync().then(value => { console.log("Num:", value) }) console.log('still doing things') } ``` </details> <br/> ## Moving Forward The truth is that, mostly, you won't be programming in just vanilla JavaScript: you'll have support from types in TypeScript, and and we'll be using some helpful frameworks, too. And on your term project, you're free to use even more frameworks. But these tend to all _compile_ to Javascript, meaning that an awareness of the underlying language will help you debug odd issues. More on this Thursday, when we'll react to a popular framework called React.