Avoiding the weird parts

If I was learning about knives, I would refuse to learn how to cut man's throat with it.

A weird sentence to start a post on programming? Perhaps, yet I find it very adequate.

Back to JavaScript?

My first steps with JavaScript were in 2008. Or, perhaps it was in 2009? I don't remember such details. It was too long ago, and it seemed so unimportant at that time, at least for me. It should be enough to say, that it was a beginning of a long journey. In the following years, I became more and more proficient in JavaScript. At my peak, I was an expert: it was really difficult to find something about JavaScript, that I didn't know about.

Am I a JavaScript expert today? I wouldn't say so. Although I'm still able to write browser-based applications, and I have no problems using such libraries, like Preact, or Mithril (1), I don't use JavaScript on a daily basis. When the world was (quite slowly) moving towards more OOP JavaScript (2), and then towards TypeScript, I was moving towards Elm (for a very short period of time), and then towards ReasonML, Erlang, Haskell and PureScript. A completely different direction.

1 (BTW, why I don't use React, nor Angular? Because I love simplicity. Angular was never simple - it was always complex as hell. And React became much more complex, than a simple library it was in 2014.)

2 (I don't know JavaScript stuff like classes and methods. In the past, I had written at least two different OOP-ish codebases for my own purposes, which supported inheritance and polymorphism, and I had done it without using a single class keyword. Let me be clear: if someone is unable to write such a micro-framework in JavaScript, and without support for those classes would be unable to write JS in OOP-style, such person is not a JavaScript expert.)

We live in 2021, though. Nowadays, JavaScript (technology) is widely used much more, than ever. There are many jobs for those, who know modern JavaScript, or TypeScript, and Node.js. And that's the problem: I do not know modern JavaScript. What I know, or remember, is ES5/ES6. With one remark: I was never used the class keyword in my code. Well, not voluntarily.

And since I'd like to become more proficient for the modern job market, I decided to refresh my JavaScript knowledge a little. I don't like this OOP stuff. But I'm also not afraid of it. And I'm sure I can learn it. Well, I was able to learn languages like Python, Java, Haskell, many Lisp dialects, Lua... to name only a few. I really think I can handle modern JavaScript.

This post is not about the beginning of my (new?) journey into modern JavaScript world. It's about some thoughts on quite old JavaScript API. An API, that preceeds the ES6, and probably also ES5 (I haven't checked it, so I'm not sure).

JavaScripts objects, primitives, and auto-conversion

I decided to use The Modern JavaScript Tutorial. And there I found this: https://javascript.info/object-toprimitive. Let me cite a fragment here:

What happens when objects are added obj1 + obj2, subtracted obj1 - obj2 or printed using alert(obj)?

In that case, objects are auto-converted to primitives, and then the operation is carried out.

I decided to skip that chapter. I'm simply not interested, what is there. I'm not interested in this topic. You may call it ignorance, and perhaps it is. Yet I'm also going to explain the reason for my complete and utter lack of interest in this knowledge.

First things first

Let's start with some fundamental remarks.

In order to process data, programmers write functions. Functions solve two different problems:

  • they are a way to group computations, to reuse them, whenever neccessary,
  • by giving functions proper names, the code becomes more readable.

So, when numbers should be added, the + operator (function) is used, when strings should be joined (or concatenated), some join (or concat) function is used, and so on. Names for functions are very important, and they should be meaningful, and descriptive. When both strings and arrays are concatenated, it can be done with String.concat and Array.concat functions/methods, or with join function for strings, and concat function for array, or vice versa, or whatever else sane name convention is used.

Quite obvious, and trivial, at least for someone, who has some experience in programming.

It should be obvious, that functions meant to perform the same (or similar) task, should be given the same (or similar) names.

Just imagine the opposite situation: you call a function named Math.sin, and it returns the input argument... squared. It would be a disaster: not only the expected result is incorrect, but also the function name is misleading. No one should ever write such a code, right?

So, in sane programming languages, the + operators are used to add numbers (in OCaml there are even separate operators for adding integers and floating point numbers!), and for joining strings other operators (or functions) are available.

Of course, sometimes the same function should be available for different data types. For example, some convention can be used to convert a value of some type, to a string. It can be toString function/method, in Haskell there's the Show type class for that purpose, and in OOP languages with classes, interfaces are probably the way to go in such cases. (I'm not an OOP expert, but I would expect something like IPrintable, or perhaps IStringify?).

(It can be also achieved with inheritance, yet inheritance bounds object's classes, and sometimes it's not desirable.)

Once again I'm going to state it: quite obvious, and trivial, at least for someone, who has some experience in programming.

And what about JavaScript?

So, why the heck the + operator in JavaScript is used for:

  • adding numbers,
  • strings concatenation,
  • and for performing possibly weird things with objects (which are first auto-converted to primitives, and then the + operator is applied to the obtained values)?

I'll tell you, why: because JavaScript is a very weakly typed language.

It means, that there are a few constraints for activites, which can be done with data types. So:

  1. When you try something like 1 + 2, the result will be 3.
  2. When you try "1" + "2", the result will be "12". It can be surprising, especially when you take both values from input fields in some browser form, and expect the result to be a number... You have to properly convert the values to numbers, before adding them.
  3. When you try 1 + "2", the result will be still "12". Why? Because JavaScript converts the number 1 to string, and then just concatenates two strings. If you'd rather convert the string to number, and then wanted both numbers to be added, you'd have to perform explicit type conversion manually.

The third case may seem to be weird: who would write code 1 + "2"? Perhaps no one - such code is pointless. Yet it is possible to write functions like the following one:

const plusTimesMinus = (a, b) => (a + b) * (a - b);

The function is simple and trivial, and its result is obvius. What happens, though, when the function is called with a string, and a number? Yes, it can happen - in JavaScript, data of any type can be passed to any function!

Conclusion

Let's get real, though, and try to focus on serious, production-quality code.

In such code, functions, which perform data processing of the same type, will be given the same name. Functions, which perform data processing of different types, will be named differently. The code should be written for sane humans to read.

For this reason, in order to add numbers in JavaScript, the + operator should be used. For adding strings... it is possible to use the + operator (when you are 100% sure, that both arguments are strings), or the concat method (of the String object) can be used, or the join method (of the Array object) can be used. And for sending messages to objects, a proper object's method should be used.

I would never use the + operator on objects!

And I would strongly advice against it for anyone.

That's the reason, why I skipped the mentioned chapter.

As I already written, perhaps it's ignorance. I find it something else, though: common sense. I'm interested in updating my knowledge on modern JavaScript, not in learning about some oddities of the language. I'm not interested in tricky code, and magic done behind the scenes: such things are code smells, and should be avoided, and eliminated in production.

(I decided this post deserves not only a weird sentence for beginning, but also for the end, so...)

Such as cutting people's throats should be avoided, condemned, and prosecuted.