DEV Community

Adam Crockett
Adam Crockett

Posted on • Updated on

➕ Operator Overloading in JavaScript, yes you can!

It struck me that it would be nice to have some form of ByteString in JavaScript utilizing TextEncoder but instead of having some fancy newing up and going through a couple of hoops to make something that couldn't be handled like a string anymore what if a user could just do this.

b`hello world`;
Enter fullscreen mode Exit fullscreen mode

And here is what the idea is based on, Rust's byte string.

b"hello rustations";
Enter fullscreen mode Exit fullscreen mode

The JavaScript version would take on the form of a tagged function for a template literal, that's cool in itself, it never occurred to me that we could make such psudo primitive types. Okay what would the Byte string return? In theory it should return a Uint8Array of unicode utf8 encoded bytes, this is all doable so far. But what if I want to concatinate them?

JavaScript doesn't officially offer the ability to change what + does, but a couple of languages do, this is known as operator overloading, changing an oporators behaviour on a type that you own. Therefore if I want to do:

b`hello` + b`world` // TypedArray + TypedArray 😵
Enter fullscreen mode Exit fullscreen mode

Unfortunately though this is possible it does mean that I must provide the return value as part of an API, remember the result of this string notation is Not a string, it's a Uint8Array, you cannot add 2 TypedArrays together, so the API version could be kind of useful, a bunch of methods on my type would make it feel just a bit more native.

Here's how it's done:

function b(str) {
   const _value = str[0];
   return {
      _value,
      toUtf8Bytes() {
         return new TextEncoder().encode(_value)
      },
      valueOf() {
         // When the interpreter asks for the value of this object we give it the original string.
         return _value;
      }
   }
}
Enter fullscreen mode Exit fullscreen mode

The valueOf overides the method used by the interpreter to compute and display values in Console etc etc, as far as JavaScript is concerned, this is a regular string, Meaning that any time I do use any operator, the valueOf will be called like a setter getter. In my example in fact it's like I'm adding 2 objects together but tricking the interpreter into thinking it's a string. Don't worry if this is safe, everything is an object in JavaScript anyway it's not that wierd. What would work even better would be a es6 class instance of ByteString extending String, Anyway I found this absolutely fascinating and could be an incredible technique, I hope you did learn something too.

But why?

Post note, you can use interpolation syntax with this (with some modifications as to how you put the pieces back together) and pass this to webgl or Wasm really easily.

If byte strings are not your thing, what about a Vector class instance you could just add together or an abstraction of the CSSOM units, I can think of a lot of cool uses for this ahem hack.

Discussion (14)

Collapse
drsensor profile image
DrsEnsor

I wonder if it still work for vector operation 🤔

Collapse
adam_cyclones profile image
Adam Crockett Author

I thought about it again, I remember the problem with vector 3 or vector 4 sizes, you need to retain all 4 or 3 values and represent them as a type in such a way that the plus can be used, eg string and number, and then re translate them back to vectors again, it sounds like a fun challenge, let me know if you try it

Collapse
adam_cyclones profile image
Adam Crockett Author

It has been a long time but I think I have a vector implementation

Collapse
drsensor profile image
DrsEnsor • Edited

How do you detect what kind operation it is (e.g +, *) by just listening on valueOf()?

Thread Thread
adam_cyclones profile image
Adam Crockett Author

Here we go, the very technical details
2ality.com/2011/12/fake-operator-o...

Thread Thread
adam_cyclones profile image
Adam Crockett Author

Details of that are here 2ality.com/2011/12/fake-operator-o...

Thread Thread
drsensor profile image
DrsEnsor • Edited

Unfortunately that technique is bound to fail when each expressions executed asynchronously. I think there is need a way to mark or even better get the value of the right hand side of the operator 🤔

Thread Thread
adam_cyclones profile image
Adam Crockett Author

I'm afraid at that point in the article, I reached my limit of comprehension, my attention span crumbled into little pieces of biscuits 😎. I did stumble across a method using Proxy, I know the reality breaking power of Proxy, so I suspect it may be the way to go. If you try to solve this one, I would like to see the results. But I can tell you that NPM does have this problem solved in the form of a few packages, some compiling and some runtime, best of luck my friend

Thread Thread
drsensor profile image
DrsEnsor

At least it doesn't do any string operation. Another approach is to use either tagged-template-literal or JSX but it hit perf quite bad since it need to translate math ops that is in string into the real one (e.g "+" -> +). This is a big no for gamedev. The solution is to use babel-macro but it slow down the devserver since it depend on babel. I wish esbuild support macro or there is a go esbuild-plugin for this.
Sorry for the rambling. Best luck to us 😃

Collapse
delta456 profile image
Swastik Baranwal

You wrote Oporator instead of Operator.

Collapse
adam_cyclones profile image
Adam Crockett Author

Dyslexia, so I meant whatever 😁

Collapse
diegomgar profile image
Dieg Oto

Oporator it's really nice, I will call oporator to all my tests of this kind of weirdo programming. Ty for inspiring me xD

Thread Thread
adam_cyclones profile image
Adam Crockett Author

You are most welcome 🤪

Collapse
pyrocto profile image
Mike Stay

You might enjoy this, then:
reperiendi.wordpress.com/2020/08/3...