Menu

Filip Zawada

👨🏻‍💻 iOS tinkerer

Operators overloading in AS3 (JavaScript too) – Workaround

It’s possible to overload operators in AS3, e.g:
[1, 2, 3] + [“a”, “b”] will result in [1, 2, 3, “a”, “b”].

You can try it yourself in Fingers, where such a constructions are possible:

Before you start, please get familiar with a prototype language concept [1][2] (if you haven’t played with it already).

LET’S START: valueOf

In AS3 every object has a valueOf() method, which in general returns the object itself. In an experiment below, you can see, that valueOf is called whenever AVM2 doesn’t know what to do with an instance of a specified type.

As you can see, results are not obvious. AVM2 sometimes chooses valueOf method, sometimes toString method. Here are some rules, that I’ve found. Let’s say AVM2 is performing A + B , while the types of A and B are different.

1. When A is String, then B is casted to String = toString() method is called (this applies also when B is String).

2. When A and B are not strings, then on each of them valueOf method is called (which by default return the object itself).

a) If results of valueOf() calls are both Numbers or Strings, then the + operator is applied on them.

b) If the types are different, they’re casted to String and String concatenation is performed.

* In above example I’ve treated int, uint also as a Number.

Please note, that in the trace below:

we got:  1 valueOf  toString. That’s because when the first 1 + new O() operation is computed, the result is of type String (rule 2.b). Then we have got another operation string + new O(), and the rule 1. is used.

Extend the idea with: prototype

What is cool, thanks to prototype concept, we can override valueOf method of any class in the real-time. So, let’s make use of that. Assume that we’d like to have following functionality of summing up arrays:

So, we need to inject a functionality of summing up an array into a valueOf method:

You’re probably saying now: that’s quite interesting, but playing with prototype object is a really bad habit, I’m not going to use that. Well, I definitely agree – changing global prototype methods makes code really messy, but…

We can solve that. The idea is to change prototype only when needed. If you know, when you’re going to use operator overloading, then you can inject your concrete valueOf  at the concrete time, and later on revert it. Your changes are “local” – that’s is good! (This concept was used in Fingers).

Let’s continue our example

In this particular example, we can override Array.valueOf, while accessing money getter, and then revert it in setter phase.

This approach has one serious drawback. Take a look at a following code:

Only setter hadn’t been called, a valueOf hadn’t been injected. In Fingers, I’ve solved this, by injecting valueOf during on(…) call.

Squeezing out most from valueOf + prototype.

Let’s say we’d like to concatenate arrays (should be much more useful):

Briefly the idea is to:

  1. Whenever Array.valueOf is called on an array instance, this instance is getting stored in a global register (and get an identifier, on which position is it stored).
  2. Array.valueOf should return position of an array in a global register.
  3. hero.items is of type *. It can get the resulting value, check which bits are set and recognize which arrays where used.

If you would like to read a more detailed explanation, just drop me a line. I’d be happy to write it in a next post. If you can’t wait, feel free to explore Fingers source-code.

One more thing, in some rare cases this approach can fail. Calling functions during getter/setter access, results in having valueOf changed then. Therefore some rare operations in these functions body can fail, because of this modified valueOf.

You can also use this approach for other operators, like -, |, ^, … But you’ll probably need to cheat a compiler a bit. So, instead of:

For me it’s really cool, but still rather an AS3 experiment (except from Fingers). You should definitely let me know, if you’re using it in a production. What’s more, the concept can be easily ported to JavaScript as well.

Hope you enjoy!

Comments

Ash says:

Thank you for the cool info!
The valueOf() function works perfect with arithmetic operators. What about comparison operators? I compare two instances with “==”-operator. Redefined valueOf() function returns identical info, but trace gives me “false”. Could you help me please?

Thanks!

Filip Zawada says:

Indeed, comparison operators aren’t cast while being compared (what makes sense). The only exception I know is when comparing object to string, e.g.: anyInstance == “str”. In such a case you just need to override toString() method.

thienhaflash says:

Very good finding and an interesting post read for a very long time.

Thanks for sharing !

p/s : I don’t know Polish, please try to change the language for the comment box !

WORMSS says:

why write in english and then use a polish as a test to allow comments? Idiotic..

I just wanted to say it was too bad I can’t use valueOf so I can do

__n = new Object(value, value2, value3);
ended up using
__n = new Object(value, value2, value3).value; Shame..

Filip Zawada says:

Hi Wormss,
It depends what you want to achieve. Once on a stackoverflow I’ve suggested a solution to cast quickly a color object using 0+ statement:

var someColor:uint = 0+new Color(…);

I fixed issue with polish captcha and fixed autoresponder – thanks for noticing.

One more interesting thing about JavaScript, you can get current timestamp there in such a way: (+new Date()) instead of new Date().getTime()

Leave a Reply

Blue Captcha Image
Refresh

*