blog

A better language to replace backend JavaScript?

I've been experimenting with different programming languages recently, especially because I am getting sick of Node.js. There are so many problems with JavaScript, and instead of being fixed, there are more and more useless features being pushed into the language every iteration of EcmaScript. This is very frustrating, and it makes me look at simplistic languages like Go with a lot of hope. You are probably **not** thinking "what is wrong with Node.js?". Well, saying that JavaScript is not an excellent language and pointing out its flaws is pointless nowadays (really, it's 2018 and there are still people making articles "why JavaScript is terrible? the answer will shock you!"? Give me a break). Look, I don't have a problem with with JS per se - I think it is a really cool language. I'm just not a big fan of how bloated the language is becoming. There are tons of useless features being added, while the old, terrible ones are not being removed. I'll give you a few examples (yes, I will do exactly what I criticized in this same paragraph): --- ##### New feature: Symbols Symbols are absolutely beautiful, aren't they? They are supposed to be a solution for creating privacy in objects, if you don't want to expose public methods. For example: ```javascript function makeObject() { return { myPrivateMethod: () => { ... }, myPublicMethod: () => { ... }, }; } const o = makeObject(); o.myPrivateMethod(); // Oh no, people can access this! ``` We can achieve privacy by using a symbol: ```javascript function makeObject() { const myPrivateMethodKey = Symbol('myPrivateMethod'); const r = { // Now you can only access this method if you have access to // the "myPrivateMethodKey" variable! [myPrivateMethodKey]: () => { ... }, myPublicMethod: () => { ... }, } r[myPrivateMethodKey](); // I can still access my private method. That's good :D return r; } const o = makeObject(); o.myPrivateMethod(); // Doesn't work! ``` Fantastic, isn't it? Well, no. One thing that people ignored is that you can have the same thing by inserting a `_` in the beginning of the method name. It is widely known that a `_` in the beginning means that that method is private and you should not access it. This has been used by languages without that don't implement private methods such as Perl for a long time. "No!" - you may be thinking. "Appending a _ in the beginning is different than using symbols, because with symbols you can actually achieve true privacy, while a underscore won't prevent people from accessing it". Well, no. JavaScript also gives you a method called getOwnPropertySymbols which gives you a list of all the private methods using symbols, and you can iterate though this list and call all of them. This completely defeats the purpose. This feature is also often misused, for example, Google Datastore (a distributed database) uses the symbol *KEY* to reference the primary key of an entry. Which means that if you want to read the value of the primary key, you need to access the "private" property using the KEY Symbol, which they export from their library. This is probably the most inconvenient way to access a primary key I've ever seen. "Wait! But just because people don't use it correctly doesn't mean it is a bad feature!" - Sure. It just makes it as effective as prefixing properties with a `_`. Whew. I'm glad we introduced this new feature that only introduces complexity and does not solve any problems. --- ##### Old defects being kept: the "==" operator and "null" I think it's a general consensus in the JS community that the `==` operator should be abolished. If you don't know what I am talking about, JS has two operator for equality `==` and `===`, with `!=` and `!==` as their counterparts. These are the differences: ```javascript 1 === 1 // true 1 === '1' // false 1 === '' // false '' === 0 // false 0 === false // false null === undefined // false 1 == 1 // true 1 == '1' // true 1 == '' // false '' == 0 // true 0 == false // true null == undefined // true ``` The `===` operator evaluates equality based on **type** and **value**, while the `==` operator only evaluates **value**. An empty string ('') and false both evaluate to a *falsy* value, this is why `'' == 0`. This may seem like a powerful feature. It is indeed powerful, but it is a **terrible** powerful feature because it makes the code very difficult to maintain and read. When I am reading code that uses use a `==` instead of a `===` I don't know if that was intentional or not. Do we need the `==` because we expect some kind of type casting there? Did the programmer just forget to type another `=`? Why do we need it? Isn't the input already validated? Shouldn't we be validating the input before sending it to this function? Why must you do this to me? Now, about `null`: the default "there is no value here" value for JavaScript is `undefined`. If you try to access a variable that does not exist, that's *undefined*. If you try to access a property that does not exist, that's *undefined*. Undefined here, and undefined there. But wait! There is more! Null was created for when you can't have enough "undefineds" and there is yet another value to do the same thing! To make things even better, `null` is completely broken. Look at this: ```javascript > null === undefined false > typeof undefined 'undefined' > typeof null 'object' // ??? ``` I like how the type of `null` is `object`, but if you try to access any property inside `null` you get an error thrown. If you have things returning `null` in your codebase, it's not only required to check if something is undefined/an object or not, you have to do this: ```javascript if (typeof a === 'object' && a !== null) { ... } ``` Or this ```javascript if (a !== undefined && a !== null) { ... } ``` For the love of god, please remove `null` from the language, already! --- I don't want to make this post about every single thing I dislike about JS (we have enough of these on the internet already, besides, my blog's database doesn't have enough storage space), although I would love to expose my controversial opinions about why Classes are the **worst** feature brought to Node.js. The thing is: I value simplicity. If there are two things in the language that achieve the same thing, one of them must be removed. Yes, I know we will be breaking backwards compatibility and blah blah blah. Look: we have semantic versioning for a reason. We have *webpack* and *babel* for a reason too. Let bad features die! If you want to have a nice garden, you add the plants that are necessary and fit in the bigger picture, and remove what is ugly and rotten. We must treat our tools and programs the same way. Of course, there are always arguments that try to justify the mistake: "Null and Undefined are not the same! Undefined is a way to express that it was never defined, while null is a way to say that we explicitly set it to null". These features not only increase complexity and bugs while not adding anything useful, but it also makes programmers waste their time with long, useless arguments. The issue is not *"are null and undefined different conceptually?"*, but *"are differences relevant enough justify a totally different data type?"* And no, they are not. Anyway, what would I like to see in a language that replaces JavaScript? I've been thinking about this for a while, and here is a little list of what I, personally, would love to see: 1. **Good performance**. If possible the language should be as fast as C++ or Java. I don't expect a language to be as fast as C, but I think C++/Java-like performance is a reasonable thing to ask for. 1. **Static typing**. I am not a big fan of dynamic typing like what we have in JavaScript, and this is one of the reasons why I use TypeScript instead. I like static typing because I can have type-checking at compile time, as well as self-documenting code. It also reduces the amount of testing required, since I don't need to check if someone is sending me a string argument instead of an object, which happens in JS. 1. **A great package manager**. What I love about node is NPM is not having to worry about dependency conflicts and being able to ask for any package version I need. 1. **Garbage collection**. As much as I love C, I really don't feel like debugging memory leaks - it is error prone, and a team's time can be better spent elsewhere. 1. **Maturity**. A good community and wide adoption is obviously very important for any language nowadays. 1. **Multi-paradigm**. I find it hard to believe that we still have pure OOP languages nowadays. I don't think languages should be all functional either, but having a balance between functional, imperative, and OOP is a great thing, and kudos to JavaScript for being a good example at this (except for the "class" part). A few features I would love to have are If Expressions, Pattern Matching, and Currying, as well as some useful methods for lists such as *map*, *reduce*, *filter*... You get the idea. 1. **Easy to set up**. Spending 30 minutes just to set up a build environment is absolutely miserable. I appreciate the simplicity of just running `npm install` and having a `package.json` that describes my whole project in 5 seconds. 1. **Good tools for parsing, sanitizing, and validating JSON**. JSON is probably the internet's favourite data-interchange format nowadays, and having built-in capabilities to parse/stringify JSON into/from objects or interfaces is fantastic, especially if supports unstructured data. The availability of libraries to sanitize this data and then validate it is also essential. 1. **Simple error handling**. Try/Catch reminds me a lot of go-tos. Sure, go-tos are very useful if you are doing some very, very low-level programming, but they are considered bad practice if you are not writing a kernel. I think Try/Catch should have the same fate as go-tos, and kudos to Go for taking the initiative. 1. **Asynchronous/coroutines**. If working on single-core applications (like a microservice, for example), asynchronous execution is extremely important to have a decent performance when handling requests. 1. **No OOP bloat**. Objects are nice, but OOP is dangerous. I could have an entire post talking about this, but I will leave you with this gem instead.
The problem with object-oriented languages is they’ve got all this implicit environment that they carry around with them. You wanted a banana but what you got was a gorilla holding the banana and the entire jungle.
C++ and Java type systems are extremely bloated and complicated. I do not miss the old days when I was fooling myself with "I love programming in Java!". 1. **Simplicity**. No, I don't want five ways to do the same thing. I don't want the choice of using classes, prototypal inheritance, factory functions, etc. I want a standard way that will be used by everyone. 1. **Explicit null values**. Being able to assign `null` to an integer is terrible, but if the language makes it explicit that a value can be null (for example, by appending a **?** to the type of the variable), then it is not so bad. I would say this is a must-have feature nowadays. From what I've seen, *Go* and *Rust* are interesting candidates, although Go seems to lack in the functional area, while Rust lacks maturity. Well, maybe one day!