A hidden secret of the addition and subtraction operators is that they can be used for type coercion from a given type into a number. This is, in essence, equivalent to using Number().
Having said this, the more robust way of doing this is by using the parseInt() and parseFloat() methods.
Another curiosity is that the parseInt() method takes in a second argument called radix that, broadly speaking, specifies the base of the number in the string.
Useful, for example, when converting binary numbers to base10 numbers, as seen in the examples above.
Assuming I have a hypothetical program that’s supposed to take in two numbers, calculate their sum, and output that result onto the console. Somewhere along the way there’s a bug in the program, as the output comes out 1000 higher than expected.
A harmless example of a mistake nested inside a method that doesn’t crash the program and yet renders it unuseful. Node has a built-in debugger that allows me to run through the program, line by line, in and out methods, directly from the console. Below is a visualization of the debugger in use.
The debugger can be called in the command line by adding the inspect flag:
Once inside, I control the running of the program through a series of simple navigational commands.
Two more functionalities that are worth mentioning. The first being that I can insert a break-point anywhere in the program by using the debugger keyword. This will make node’s inspector to run through the program up until the debugger. This keyword is often also recognized by browsers in front-end code.
The second being that I can keep watch of certain variables as the program runs by adding them to the watchers-list. Adding, as well as checking, these variables can be done using the two keywords below.
Probably a lot more could be said about debugging, namely that VScode has a real neat and far more visual debugger. But I just wanted to leave here some rough notes for myself with the basics of debugging directly from the console.
There are some tools that are useful to prevent and handle these errors. Starting with a top-level understanding of the errors themselves, the try-catch construct, the guard clause, and finally the Error object itself.
1. Error types
Type Errors are thrown when the program is trying to read something that doesn’t exist; when there is an attempt to change a constant; or when something that isn’t a function is called as such.
Reference Errors are thrown when a variable or function that does not exist is called by a program – reference because there is no reference to that variable or function.
These are the most common errors, but there’s a more comprehensive list available on Mozilla’s website.
The errors mentioned above will cause a program to crash during runtime. To prevent this from happening, I can encapsulate the fallible portion of the code inside a try clause and handle the error in the catch clause. This is most helpful especially when getting data from external sources such as user input or information coming in from an API.
When error occurs inside a try clause, the error information gets passed onto the catch clause as an argument that can then be fleshed out and printed onto the console without having to stop the program from running.
3. Guard Clause
Like the try-catch construct, the guard clause is a way to prevent fallible content from producing a runtime error and crashing the program. Useful, for example, at the start of a function to prevent invalid data from getting in without even having to run the rest of the function code.
4. Error Object
This is useful in instances similar to the case mentioned inthe guard clause. As a way to flag onto the console a potential error, or faulty data input. These errors are instantiated just like an object.
As I develop as a programmer, I take on certain habits that are helpful when planning a program. These could be summed up as taking a step back and thinking straight before getting to the thick of code.
Compartmentalizing the two creates a space of focus solely dedicated to logic. When the time comes for programming, I have a clear-enough map of the territory ahead. A clear-enough idea of what I’m trying to accomplish which in turn facilitates the search for specific solutions built-into the language. This, it turns out, can be a helpful antidote against trying to memorize every method in a language – a shift from what to how.
When giving it all some thought, some themes emerge:
1. Breaking things down
Any problem or challenge is made of parts. The first question is to determine what these parts are; and then what parts those parts are made of. Answering this question pulls me away from trying to solve everything at once.
In the case of a simple calculator, for example, I can break it down into first, getting user input (numbers and operator); then performing the operation; and finally displaying the result.
The broad idea of a calculator is broken down into three more granular procedures; and to each, the same question can be asked. What parts is it made of?
Cultivating this mindset is not only helpful in programming, but it trickles down into other areas of life. It creates a stronger sense that things can be achieved if properly broken down. Having said this, I recognize that knowing what to break something into is, in itself, a skill.
2. Writing before coding
In essence, writing pseudo-code before getting into the thick of programming. Being an experimentalist myself, it can be hard sometimes to find the patience to plan before doing. Personally, instruction manuals don’t stand a chance to the joy of figuring it out.
But, writing pseudo-code can be to programming what prototyping is to design. Prototyping the logic of a program in advance makes it so that by the time I’m coding it, I’m already working on a more sophisticated idea of the solution. This is helpful!
So, my version of a helpful yet doable pseudo-code is one where I’m already writing programming logic, despite it being in a more human-friendly language. Pseudo-code is most helpful to me, personally, when I can strike a balance between the two.
3. Prioritizing imperative problem-solving
At this stage, there is a helpful distinction to keep in mind: that of an imperative versus declarative approach to problem solving.
John V. Guttag of MIT puts it clearest, in Introduction to Computation and Programming using Python, when he states that imperative knowledge is “how-to” knowledge; a recipe for deducing a solution. Whereas declarative knowledge is made of statements-of-fact about said solution.
This translates to pseudo-code in that taking an imperative approach to problem solving is akin to focusing on the logic without using any specific constructs or tools of a specific programming logic.
To put it clearest, to manually go through an array of numbers:
Even though, at times, it’s helpful to jump straight to a declarative solution, in the overall context of problem solving, taking an imperative approach and actually figuring out the recipe makes for better thinking.
4. Using programmatic keywords
Now that we’ve made this distinction between imperative and declarative thinking, we can look at the syntax of actual pseudo-code. At its core, it's meant to be unconstrained by the syntax of programming languages, while still using certain keywords and constructs that map to the universe of programming.
Some keywords lend themselves more to imperative thinking by virtue of being non-language specific programming constructs. These are primitive concepts akin to directions such as: move, left, right, turn back.
Other keywords are declarative in that they mirror existing methods in a given language and can encapsulate a series of procedures into one single word. The real world example of this is to tell someone to go from Venice to Santa Monica – a lot is implied in that simple direction.
In the example of the calculator mentioned earlier, I can write pseudo-code to explore the first step of getting input from the user. This combines an imperative approach to the overall design with some declarative tools such as the use of a function with an argument, and a RegEx test to check if the input provided is indeed a number or an operator.
5. Visualizing to reduce complexity
In cases when the problem is more complex and / or a whiteboard is at hand, there is a form of visualization through flowcharts. Just like in written pseudo-code, I learned (at Launch School) that there is a method to the madness in the form of visual keywords.
So if I take the pseudo-code from before, I can also plot it visually, it goes somewhat like this:
I wrote this to organize my thoughts, but if this is of help to you out there, awesome. Any improvement suggestions are welcome!
Install and usage:
Rules can be found here.
The logical operators && (and) and || (or) run on what can be called short-circuit logic. Simply put, that means that expressions will only be evaluated if the expression preceding it is not enough to determine the truthiness of the logical expression.
In the example below, all three expressions need to be true for the entire logical expression to be true. But given that 7 isn’t bigger than 8, the last logical expression, a simple true expression, doesn’t need to be evaluated since all three are no longer true.
The same is true for the || (or) operator. Whereas the && (and) operator short-circuits if it finds a false statement, the || (or) operator short-circuits when it finds a true operator. Since all it needs is for one of the expressions to be true.
In the example below, undefined.length would crash the program and result in a TypeError. But in this logical expression, because the first argument is true, and only one expression needs to be true, the remaining is short-circuited, and not evaluated.Uses of short-circuiting
Uses of short-circuiting
Short-circuiting can be used as a replacement for simple if statements. In the example below, I’m setting an if statement to make sure the function foo() only runs when the number variable is bigger than 6.
Well, the same could be stated simply with a logical expression. If the first expression (number > 6) is false, the second will be short-circuited. If true, it runs.
A short-circuit can also be used to replace a variable when the intended value is not available. In the example below, the greet function takes in an argument name.
When name is passed into the function call, name is true enough that ‘you’ can be short-circuited. If not, it’s run and returned as the value to be stored in the variable name.
The same can be achieved with a simple default value on the function’s parameter, but for the sake of example I’m using the short-circuit as an alternative method.
Short-circuiting returns more than booleans
As seen in the example above, this mechanism doesn’t only return true or false values. It returns whatever-the-value-is of the last evaluated expression.
In the case below, ‘Frank’ is true enough that ‘you’ does not need to be evaluated. But if the first expression were false enough, i.e. undefined, then the returned value would be true.
In essence, that’s what was happening in the function detailed above.