Squirrel Class Notes

Squirrel features both Delegates and Classes for creating types and providing default values and actions. They are mutually exclusive, meaning you either use a class or a delegate (attached to a table/array).

The following is a collection of notes on Classes.

Sample Class

The class below features a constructor, metamethods (like operator overloading), and a few additional functions.

Create instances with function syntax

Creating an instance is a lot like JavaScript.

The constructor is called with mentioned arguments.

Not to be confused with the _call metamethod.

Problems to consider: Functions are not overloaded, but replaced

In C++ and GLSL/HLSL, it’s common to have operators overloaded that let you Add, Subtract, and Multiply vectors by other vectors, scalars and matrices. This can (mostly) be done in squirrel by looking at the type of the argument received by your metamethods. Here’s an example that supports scalar multiplication as well as vector multiplication (component wise).

The problem though is this is one way. I can do “MyVec * 10”, but “10 * MyVec” will not work. To make it work, you would have to add a custom _mul metamethod to the number type… except I’m not sure that’s allowed by Squirrel (custom delegates are, but metamethods?).

One solution would be to create a “real” type (similar to GEL), but Squirrel doesn’t exactly provide a nice way to create custom automatic type conversions, so the syntax wouldn’t be ideal (i.e. real(10) * vec2(10,20) everywhere). I do live with this in GEL, but it would be a shame to not have a cleaner syntax here. This also assumes custom math metamethods are not supported by Squirrel (and technically I have the source, so it’s not like I couldn’t add any feature I wanted).

It’s also a shame the operator code ends up being so complex. A function that started as one line (the last line) has become 5 lines to add float and integer support. Add in Matrix multiplication too, and then I start getting scared.

An alternative solution would be to add .tovec3() and .toscalar3() functions to the default float delegate (where tovec3() is (10,0,0) and toscalar3 is (10,10,10)). This would be a cleaner option, but is somewhat wasteful, especially once we get to higher order maths like Matrix multiplication.

One more option would be to add language level vector and matrix support. After all, a table with x,y,z slots can’t exactly be the most efficient thing. This would certainly be the most difficult though.

It’s a shame Squirrel doesn’t have a way of adding shadow members. Like a MyObject.x() without the brackets that could be assigned (MyObject.x = 10).

I shouldn’t be expecting a scripting language to be ideal for high performance math anyway. Like I’ve said, specialization is the key. That is what scripting is for. Leave the low-level to the low-level.

Copy Constructors: meh

This is inconclusive currently. I may have found a bug with what should be the ideal way of doing it. I’ve since posted a question to the forum on it.

What I would like to do:

What I have to do instead.

This works, but isn’t as elegant as cloning.

Weak References

All built-in types have a .weakref() function in their delegate (classes, instances, generators, tables, etc). Bools, floats and integers return the actual type, but everything else returns a weakref type.

The weakref type is exactly that, a type containing a reference. To access the data referenced, you can call the .ref() function.

If the data referenced runs out of references, it is recycled. Any weakrefs pointing to it will thereafter return null.

In addition, Squirrel does some cleverness with weakref types. If you omit the .ref() call, it will still return the data referenced. For the most part, a weakref will act like the real type, except typeof will be weakref instead of the original type. To get the type referenced, you do typeof on the value returned by .ref().

Strong References

Okay, the reason for the brief exploration of weak references was because of an experiment I was doing with strong references.

Contrary to C++, instead of an assignment operator being called, a strong reference is created. Thus both Pos and Old point to the same data. In this way, Squirrel works like Java/JavaScript/C#, in that everything (other than int/float/bool) are references.

Instead, one should use clone to make a copy.

Clone performs a shallow copy, meaning all top-level members are copied. Integers, Floats, and Bools work as expected, but most other types are references, which may not be the behavior you desire.

Cloning Classes

In the case of a class, you can write a simple _cloned metamethod to handle the above case..

If a table, you can use a delegate like the following to automatically clone all members.

No General Purpose Copier for Classes

The general purpose copier doesn’t seem to work very well with classes. At least when I was trying to do it, I couldn’t get it working properly. Here’s a snapshot.

_get metamethod: are you even useful?

I have this code in my 3D vector class.

It’ll let you syntactically use the class like an array, but it’s not an array. So this is fine for inside Squirrel code, but if you have native code expecting an array, these will be useless.