GML as a language

Posted by ludamad on Aug. 12, 2012, 2:44 p.m.

Been into language design recently, and I was recently reflecting on how glad I am that I have gone on to use languages other than GML. It has really broadened my horizons as a programmer.

From the point of view of language design, I hope to give an objective summary of GML's strengths and weaknesses. I have not used GML in a while so forgive me for any inaccuracies.

GML can get stuff done. GML, by virtue of its close integration with GM, makes arguably the most daunting part of making a game rather easy - getting started. This is by far GM's greatest strength. It is an excellent prototyping tool, as a result.

Let's size up GML:

- It is a procedural language. GML scripts consist of a series of function calls, with very little possibility for object oriented type control flow.

- It is dynamically typed, variables can be reassigned as strings or numbers at run time.

- It is weakly typed, it is entirely possible to use the number 1 as an object, as a data structure reference, and as a sprite, all by accident.

- It is integrated in an event-based framework. This event based framework is rather convenient, and provides a more or less logical way to divide up functionality.

- Arrays exist only as local to a script, or part of an object. There is no way to use an array as a value passed eg to a script.

- Data structure support is limited to built in constructs.

- Object orientation is limited to heavyweight objects with a physical presence (a hackish solution is to hide the physical presence of abstract objects, eg for a monster controller object).

Strengths:

- It is integrated in a convenient game development framework. It has an adequate standard set of functions.

- It encourages separation of code into events

- It is dynamically typed and does not force users to worry about type declarations

Weaknesses:

- It really only has two types - numbers and strings.

- Arrays exist - but not as a type. They exist only as a part of the local context, or of an object. They therefore are not appropriate for building abstractions on top of. You cannot, for example, have a standard set of scripts for treating an array as an inventory, as you cannot pass the array to those scripts.

- Scripts can only return a single value, and it can only be a number of a string. This severely limits the ability to build abstractions using scripts. This severely limits the ability to do useful things in scripts without directly modifying objects using the script. This breaks encapsulation badly.

- The data structures that do exist must be manually freed, and are awkward to use.

Did I mention it is almost impossible to make meaningful abstractions in this language ? It is, however, not entirely impossible.

Consider a very standard scenario where you want abstraction:

You are creating an inventory, and want to be able to have multiple, unrelated parts of the code to use this in a consistent way. You want to be able to pass an inventory from one object to another.

This is very hard to do in GML. What you can do:

- Create a set of scripts:

inventory_create(ds_index)

inventory_add(ds_index, name, amount)

inventory_get_amount(ds_index, name)

inventory_destroy(ds_index)

Now, as the implementation, have inventory_create make a ds_map. Then, each script will call a ds_map function that does the appropriate action. You will be able to change the internal structure of the inventory, eg make it a grid of nested structures instead of a map, without touching the places where the inventory is actually used. This goes for any other concept that needs some sort of data structure as its implementation.

Overall, this is not an entirely satisfying scheme, and scripting languages can do far better. I believe unless you code with many many small scripts GML will be promoting rather bad programming habits.

Comments

Rob 12 years, 4 months ago

Quote:
- It really only has two types - numbers and strings.
Quote:
- Data structure support is limited to built in constructs.

I could make my own custom list or binary tree or quadtree, using objects for nodes/quads if I wanted to.

Quote:
- Scripts can only return a single value, and it can only be a number of a string. This severely limits the ability to build abstractions using scripts. This severely limits the ability to do useful things in scripts without directly modifying objects using the script. This breaks encapsulation badly.

// in your script
retval = instance_create(0, 0, data_holder);
retval.blah = derp;
reval.herp = blah;
retval.derp = herp;
return retval;

pointers, yo'

ludamad 12 years, 4 months ago

Quote:
- Object orientation is limited to heavyweight objects with a physical presence (a hackish solution is to hide the physical presence of abstract objects, eg for a monster controller object).

Also, retval is a number there, technically. You can do retval + 1 and get a nonsense result.

Its far less heavyweight but pretty unwieldy to use maps for this as I mentioned you can do.

Rob 12 years, 4 months ago

Quote:
Also, retval is a number there, technically. You can do retval + 1 and get a nonsense result.

And how does that make them any different from C pointers? You can do pointer arithmetic in other languages too. How is GML any different from Java, since you can't really have non-primitives stored on the heap, so really all your variables are primitives or "numbers" (references to a point in memory).

ludamad 12 years, 4 months ago

I was responding to your response to : It really only has two types - numbers and strings.

It does. Pointers are a different type in C. Also pointer arithmetic is actually useful for arrays, far from the dubiously useful retval+1.

GML is quite different from Java. GML only has heavyweight objects and built in datastructures. GML cannot return its arrays from functions ('scripts'). GML's type system is too unwieldy to perform general purpose object orientated coding. GML makes you manually free your referenced objects / datastructures.

Josea 12 years, 4 months ago

GML is very simple, I guess that's because it is both very easy to implement and easy to understand for the target audience of GM (which is game making for newbies without prior programming experience, right?)

ludamad 12 years, 4 months ago

It really wouldn't take much work to make the language a lot better, in my opinion. Issue now is backwards compatibility

Josea 12 years, 4 months ago

What would you do to improve the language?

ludamad 12 years, 4 months ago

Adding lightweight objects would be a serious improvement. They would be objects with no physical presence, none of the upkeep needed for objects involved in event handling, drawing, collisions, etc. They would just carry attributes.

So code could reasonably be done using a style like:

retval = object_create()

retval.blah = derp;

reval.herp = blah;

retval.derp = herp;

return retval

As rob had stated. Code like this is very common in other scripting languages. The caveat is the object would still need to be explicitly destroyed, but they could be optimized for frequent creation/deletion.

Instances technically have all that is needed to do this, but they really have way too much going on to be eg created and destroyed 1000s of time in a single step. With this you could split up the state of a single, complex instance into many lightweight objects.

This would be a very seamless changed.

A less seamless improvement would be distinguishing sprite/object/data structure references so they cannot easily be misused as numbers, or references to other types. Having arrays as a distinguished type would be very useful, to allow for eg putting arrays in other arrays. Most of the syntax could remain the same, except for the quirk that a variable name implicitly accesses the first array index.