OFFICIAL GML Consistency in GMS2 v2.2.2

rmanthorp

YoYo Games Staff
Admin
YYG Staff
The following blog was written by Russell for our blog: https://www.yoyogames.com/blog/506/gml-consistency-in-version-2-2-2

INTRO
GML as a language has slowly grown over the last 20 years, and during that time we have added features and addressed inadequacies within the language. Most recently, as of the GameMaker Studio 2 version 2.2.2 release we have been addressing consistency issues between the VM and YYC compilers. We have particularly addressed issues of type-conversion consistency at runtime.

To this end, we have been augmenting our internal test suite, making it easier to create tests, and revised the suite to ensure that it shines lights on some of the darkest corners of the language where users fear to tread. This was most illuminating and helped to uncover some glaring issues within the VM and YYC compilers, and hopefully, everyone will see improvements in compatibility between these versions in the 2.2.2 release. This test suite is run every day against our latest internal builds and has been catching regressions and mistakes since we set it all up. Even as new bugs come in, we have been adding to the suite and ensuring that these issues are fixed as a priority.

CHANGES
The main thrust of this blog post was to draw your attention to changes that may affect how your code executes at runtime. Previously, the runtime was quite inconsistent in how it handled variables which were being used as a number but were actually strings - some functions internally converted them to numbers or just defaulted to the value being 0, while some errored, and others just silently continued with incorrect values.

We have addressed this by revising the runtime to make string-to-number type-conversion consistent and introducing some basic rules:

  1. A string will be converted to a number at runtime IF it starts with a valid number i.e. begins with a digit or ‘+’ or ‘-‘. The number is then parsed up until the last non-number character. NOTE: number conversion is treated as floating point number conversions and follow the rules for the C runtime function “atof”, which is documented as “A valid floating point number for atof using the "C" locale is formed by an optional sign character (+ or -), followed by a sequence of digits, optionally containing a decimal-point character (.), optionally followed by an exponent part (an e or E character followed by an optional sign and a sequence of digits).”
  2. Any non-number characters after the number will be ignored.
  3. Any string that cannot be converted will cause an error to be generated, except in the case where a simple Equals or Not Equals comparison is being done (e.g. “Hello” != 0 would be true).
Any time a number is required by the runtime and a string has been given instead, then an automatic conversion is applied or an error is generated, following those rules above.

This now makes the runtime more consistent (and predictable) and along with our testing suite gives a good basis for addressing other stability and language issues and additions over the coming months.

WRAP UP
I have had discussions with GMS2 developers and several questions have come up that I think stem from confusion around how operations are handled at runtime.

One common observation was that this now makes the + operator non-commutative since 1 + “2” does not equal “2” + 1. Well, the simple answer here is that these are not the same operations, as 1 + “2” is an integer addition with another number (so the runtime requests the string to be converted) while “2” + 1 is a string addition (which is actually a concatenation operation) with a number, which the concatenation operator does not allow and so an error is generated. This is because the type of operation on a binary operator is dictated by the type of the left-hand element in the operation. This has always been the case in GameMaker, and it is not a breaking change as of 2.2.2. This is true for all operators in GameMaker.

I should call out at this time that there is a little-known quirk in GameMaker that the * operator performs a little differently when an integer is multiplied by a string. Then, the string is concatenated to itself times the value of the integer - so 3 * “9” results in “999”. This behaviour has been part of the language for a long time (at least from GM7, which is the first version I was involved in).

Another observation would be that the compiler will also optimise any constant expressions that it can handle, but it will leave constant string conversion to numbers until runtime, as this change for 2.2.2 was focused on runtime conversions and not compile-time. We have also left some string expressions as errors at compile time, for example, constant strings. So ~”6” will generate an error at compile time, as trying to do a bitwise negate with a string is incorrect and should be changed by the user, but at runtime if it was a variable at runtime, then it would successfully convert it, as the user may not realize that the type of the variable had been changed earlier elsewhere in their code. Now, obviously, this conversion at runtime is more expensive when it happens, so I would advise you to profile your code in the debugger to make sure it is not taking more time than it should, and you can also check types of variables at runtime using the typeof() function see: https://docs2.yoyogames.com/source/_build/3_scripting/3_gml_overview/checking_data_types/typeof.html

We look forward to growing GML more with our community in the future. If you want to discuss these changes, feel free to join the 2.2.2 beta discussions here.

Thank you, Game Makers!
 

FrostyCat

Member
Whereever you think we fear to tread, we fear to tread it still because the tests are still behind closed doors.

For starters, if you're going to be tackling VM-YYC typecasting inconsistencies, above string-to-number conversions you should really be looking at int32-to-number conversions that break data structure access. This is by far the #1 YYC-only inconsistency that I observe on the Q&A sections, and it happens when data structures are nested or sometimes randomly after their IDs get passed around a few times. I can't tell if you're on the case because the tests are behind closed doors, and if it breaks post-release, we're in no position to prove it.

There's a reason why I keep asking for GMDeath (or whatever you call that test suite now) to be open-sourced. We can't have any confidence until there's transparency in where your confidence is placed. Right now it isn't inspiring our confidence as it should because we can't see it, and it is encouraging an echo chamber of use case assumptions outside the definitions of the language because we can't contribute points that you missed.
 

curato

Member
Maybe I just come from an age of hard casting of data types, but I would expect 1234Hello to throw an error if it was passed as a number instead of just tossing the "Hello" and using the 1234. If you are passing something that can't be cast a number in its entirety when you are expecting a number then something it wrong with your program and you should be notified instead of silently giving unexpected behavior.
 

JeffJ

Member
Maybe I just come from an age of hard casting of data types, but I would expect 1234Hello to throw an error if it was passed as a number instead of just tossing the "Hello" and using the 1234. If you are passing something that can't be cast a number in its entirety when you are expecting a number then something it wrong with your program and you should be notified instead of silently giving unexpected behavior.
I absolutely agree with this.
 

rIKmAN

Member
Maybe I just come from an age of hard casting of data types, but I would expect 1234Hello to throw an error if it was passed as a number instead of just tossing the "Hello" and using the 1234. If you are passing something that can't be cast a number in its entirety when you are expecting a number then something it wrong with your program and you should be notified instead of silently giving unexpected behavior.
This would make more sense to me as well.
 

FrostyCat

Member
This movement towards more forgiveness in GML is troubling, given how YoYo's goal is to expand GML's functionality. The more YoYo tries to tolerate undesirable coding behaviour by hiding it behind poorly defined behaviour, the more exceptions it must make to the language. Every exception is a potential source of unwanted side effects and needless baggage on the runner/compiler that prevent it from accepting new syntax cleanly.

Besides, if YoYo is going to forgive people doing crap like casting "1234Hello" to an integer, why wouldn't YoYo forgive people who enter string names into places that expect resource IDs? I mean, string names are the norm now when referring to layers in instance_create_*() functions, why not follow suit elsewhere?
 

Gradius

Member
I can't think of any examples where this wouldn't just be incredibly broken code. If someone has, with a straight face, made if( "1" > "2") then surely they should just get an error?

GM isn't the only language to allow some strange behaviour when mixing strings and numbers, but I still don't see the justification for allowing it.
 

YellowAfterlife

ᴏɴʟɪɴᴇ ᴍᴜʟᴛɪᴘʟᴀʏᴇʀ
Forum Staff
Moderator
I stated this elsewhere and can reiterate here: I really don't think that when people are asking for GML to be "more akin to JS", they mean the insane type casting rules - people want inline functions, lightweight objects, and maybe prototypes/metatables.

From my just-about-a-decade time working with JS (and then HTML5+JS) for websites/games/web apps, the only places that I've seen type casting behaviours be used were:
  • Code golf
  • Code obfuscation
  • (0|new Date) for timestamps, which is now eliminated in favour of Performance API
  • Small logical mistakes leading to insane bugs, such as numbers silently being cast to strings (via +) and then back (via other operators), costing people hours of time to figure out and/or money paid to me to do so. Some would vow to move the entire codebase to TypeScript once it was discovered what it was all about.
Some people say that JS-style (non-string + string = string) operator behaviour is nice, but even that is less needed with current versions of ES supporting template strings
Code:
console.log(`Score: ${score}`); // non-JS implementations commonly allow $score too
While these changes can be largely reverted on YYC by editing your YYGML.h, it'd be nicer to not have such "pleasures" to begin with.

Edit: Oh, and the fact that if (undefined) at the same time now throws an error will break a lot of code of kind
Code:
if (map_of_bools[?key]) { ...  }
 
Last edited:

curato

Member
I don't think anyone cares if you cast an float to an int or vise versa when it is called for or you say temp = 4; then later say temp = "Howdy"; but then if you later try to say temp = "123Four"; then you assign x=temp; I am just not sure it is a natural assumption that is equivalent to x=123; It just seems like you trading an easy to find syntax error with hard to track down semantic error.

EDIT: I would at least say if you going to make radical casting rules like that, a warning should at least be kicked into the debugging window with the where it occurred to make it easier to find if it is undesirable.
 
Last edited:

EvanSki

King of Raccoons
If your getting numbers from a string that has numbers and letters it should give an error

If your getting letters from a string that is just numbers
You should get and error

Just please
Make string replacing
And string combining
Easier to use
 

immortalx

Member
Is optional typing something that YYG team considers for the future? I mean in combination with not allowing such automatic conversions if the type is present in the variable creation. I won't pretend to know the implications of a feature like this, but it seems to me that for those of us that want a stricter language, that would solve problems like this. So unless I'm missing something obvious, would other members want something like this?
 

Dmi7ry

Member
I already wrote a message at GMS2 Version 2.2.2 (BETA RELEASE), but it related with this topic.
I'm sure it's wrong decision to implement such behaviour. I'd say it's a HUGE mistake.
Any operations with different types should throw errors. Otherwise you may get
just silently continued with incorrect values.
I would even deprecate behaviour like
3 * “9” results in “999”
It's useful in some cases but would be better have a special function for this.

If for some reason (thousands of them) you wrongly got string value instead of number value and it was automatically converted to number, you may get a lot of problems.
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
I'd like to just point out to everyone, that this behaviour isn't actually new, and has been a part of GML since very early GM days. The problem was that it was done in an inconsistent manner and THAT is what has been addressed here. It could be "fixed" (ie: no behind-the-scenes casting strings to reals like this), but then that would break far, far more projects than just making it consistent across platforms and functions does. So, this is not a "new feature" but a "fix" to make how things work consistent across the board, so regardless of whether you think it is right or wrong, it is a feature of GML and should at least work properly everywhere and under all conditions.
 

breakmt

Member
Is optional typing something that YYG team considers for the future? I mean in combination with not allowing such automatic conversions if the type is present in the variable creation. I won't pretend to know the implications of a feature like this, but it seems to me that for those of us that want a stricter language, that would solve problems like this. So unless I'm missing something obvious, would other members want something like this?
Yes, sure. This is one of the reason of my transition process to something else.
 

Dmi7ry

Member
I'd like to just point out to everyone, that this behaviour isn't actually new, and has been a part of GML since very early GM days.
Some of this behaviour. Not all of it.

3 * “9”
Yes, it was. But it doesn't mean that it is right and that it should be forever.

Code:
var a = 10;
var b = "100"; // and even var b="1jhewWERrn";
show_message(a + b);
This throws an error in 2.2.1, but shows "110" in 2.2.2. And that is the problem.

The problem was that it was done in an inconsistent manner and THAT is what has been addressed here. It could be "fixed" (ie: no behind-the-scenes casting strings to reals like this), but then that would break far, far more projects
If I see an error I can fix it. If I don't see error then it's a problem. Current (2.2.2) behaviour hides errors from developers.

that would break far, far more projects
Nonsence. Or we're talking about different things.

than just making it consistent across platforms and functions does. So, this is not a "new feature" but a "fix" to make how things work consistent across the board,
No reasons to do something worst when it can be done right.
 

YellowAfterlife

ᴏɴʟɪɴᴇ ᴍᴜʟᴛɪᴘʟᴀʏᴇʀ
Forum Staff
Moderator
I'd like to just point out to everyone, that this behaviour isn't actually new, and has been a part of GML since very early GM days. The problem was that it was done in an inconsistent manner and THAT is what has been addressed here. It could be "fixed" (ie: no behind-the-scenes casting strings to reals like this), but then that would break far, far more projects than just making it consistent across platforms and functions does. So, this is not a "new feature" but a "fix" to make how things work consistent across the board, so regardless of whether you think it is right or wrong, it is a feature of GML and should at least work properly everywhere and under all conditions.
As far as I'm aware, the legacy behaviour was:
  • Assigning a string to a numeric built-in variable (x,y,etc.) would convert it to a number
  • Similarly, providing a string instead of a numeric argument would convert it to a number
  • Providing a number instead of a string argument would convert it to a string (and leak memory)
    This had been broken numerous times (most famously for draw_text, I believe)
  • The mentioned 3*"a"=="aaa" thing
To point out, none of these were documented or promised to the end user in any way whatsoever.
For all previous occasions of legacy behaviour being something terrible, such as
  • Absence of short-circuiting
  • "v=array" evaluating as "v=array[0,0]"
  • "array=v" evaluating as "array[0,0]=v"
  • Creation event order specifically relying on variable_ functions
  • "var a b c" (no commas)
  • "var a
    b = 1
    c = 1" evaluating as "var a, b = 1, c = 1" (GM8.1 exclusive)
  • "for (i=0i<4i+=1){...}" (no semicolons)
  • local.v being same as "var v"
  • Whatever the magic object -6 was supposed to mean (which was same as local, but also not - I'd be surprised if anyone remembers at this point)
  • -1, -2 consistently evaluating to self.id/other.id no matter where they are used (leading to a plethora of bugs related to using -1 as an ID somewhere)
  • Everything else
Old poorly written code was allowed to break, or a short-term workaround (like the short-circuiting checkbox in GM:S) was introduced. So what makes this different and worthy of forcing everyone into inferior legacy approaches instead?
 
Last edited:

curato

Member
I'd like to just point out to everyone, that this behaviour isn't actually new, and has been a part of GML since very early GM days. The problem was that it was done in an inconsistent manner and THAT is what has been addressed here. It could be "fixed" (ie: no behind-the-scenes casting strings to reals like this), but then that would break far, far more projects than just making it consistent across platforms and functions does. So, this is not a "new feature" but a "fix" to make how things work consistent across the board, so regardless of whether you think it is right or wrong, it is a feature of GML and should at least work properly everywhere and under all conditions.
I don't disagree that dynamic casting should stay a lot languages do that these days. My point was casting strings with letters in them to numbers is still broken. I can't imagine a use case here where that would make sense to me.
 

thaaks

Member
I think arguing that legacy behavior should stay but only trying to improve it is completely wrong. This will never help to make GML a mature and reliable language.
Having variables that can change their type is one thing but having tons of builtin compiler/interpreter assumptions what the user could have meant is only error prone. And auto casting is such a beast.
There are proper casting functions in GML (string(), real()) - why not use them or even force to use them?

Also all this legacy behavior causes problems (and Compiler errors) when exporting to other platforms - all platforms (except HTML5) require strict typing with their "native" languages (XCode, Java, C/C++/C#). So why insist on this lazy legacy behavior?

And look at the forums: they are full of questions of "My code doesn't work!" and oh so many times it's because the GML compiler tries to interpret bad code in any senseful manner and doesn't throw a helpful error message.

You modified so much with GMS2 (workspace, room editor, image editor, introduction of layers and breaking the depth stuff somewhat, introduction of cameras affecting many games) but you don't dare to clean up the GML mess - that's a really bad decision IMHO, for beginners and even more for experienced developers.

Why not at least consider some strict mode for GML where the compiler is throwing errors for way more stuff, forbidding all the legacy stuff @YellowAfterlife lists in his post.

But currently I doubt that GML will evolve in a professional direction but allow even more DWIM style ("Do what I mean")...
 

JeffJ

Member
It seems rather evident from the feedback in this topic that this is very much the wrong direction for GML. I seriously hope that you will reconsider this decision.
 

11clock

Member
GML has always been GameMaker's biggest weakness, and now they made it even worse. Yaaay.

Wake me up when they replace GML with C# or Python or something else more sensible.
 

Dmi7ry

Member
Wake me up when they replace GML with C# or Python or something else more sensible.
This might be better for pros (although minus performance), but I doubt that it would be better for beginners. Any language has + and -. C# and Python too.
 

11clock

Member
This might be better for pros (although minus performance), but I doubt that it would be better for beginners. Any language has + and -. C# and Python too.
Them focusing so much on beginners has probably what has led me to feeling like I have "outgrown" the engine, if it wasn't for the lack of good alternatives for 2D games. Other 2D engines are even worse about it without any option to program whatsoever in favor of horrid drag n drop tools, like Contruct and Clickteam Fusion.

I get that GameMaker's demographic falls out of my scope, but I feel that they should open the doors for more advanced software engineers and not sacrifice so much control for usability. I remember asking for static typing once but it was declined because it wasn't "friendly to beginners," despite how powerful this feature could be to more advanced programmers.

I do like seeing inline functions, proper data structures, and so on in the roadmap as potential features, which would be amazing for us. But I really hope they aren't dropped just because they make the engine "harder to learn." GameMaker has some of the best 2D tools out there, especially for pixel art tile-based games, but I don't like the engine forcing us to use a very primitive scripting language in order to use them, and they are making it even worse by adding ridiculous type conversions. 1 + "4 apples" should not equate to 5. Make it behave like literally every other programming language and stop encouraging bad habits!

Also please for the love of god let us convert objects to tabs and disable the workspace entirely. The workspace is something that really only appeals to artists and non-programmers. We can already convert most everything else to tabs via settings, objects too, please!
 

Cpaz

Member
BTW, have you tried GMEdit?
It's such a good editor, but sadly i'd say it's still in it's infancy seeing as it's just for code. I encourage people to check out the git for it if they want to contribute.

But anyway. I do generally have to agree with the majority here- I can't see why we should be more forgiving, creating bad habits in up and coming developers, and just not introduce more strict type management in GML
I get it, GML is supposed to be easy to learn, but type management is it's own beast in basically any other language. Also, don't we have functions to convert types for us? Why not just enforce that?
 

8BitWarrior

Member
I agree that this seems like the wrong direction for GML. I have used GameMaker for 15 years and never knew that some of these bad practices were allowed. I've been waiting for GameMaker to break projects that should be broken, so that the language can mature and promote consistent practices. I assumed that GMS2 would do this, as it would be the perfect time, but it really didn't.

I have found that "noob-friendly" features lead to more headaches. A prime example is the built-in health variable. How many posts have we seen about it confusing new users because it is global?

Another example, (though a bit off topic) is the DnD actions. Buffer actions are included for DnD. Why? Once you need to use buffers, you are 98% not likely to be using DnD. This, to me, shows a bit of foundational misdirection in "user-friendly" stuff.

I really like GML. It is super easy to use when it isn't being silently "forgiving". If we want to help new users, error-reporting should be improved to clarify why errors are happening. Gently educate the learning user. Don't coddle them.
 
Last edited:

Pfap

Member
I agree that this seems like the wrong direction for GML. I have used GameMaker for 15 years and never knew that some of these bad practices were allowed. I've been waiting for GameMaker to break projects that should be broken, so that the language can mature and promote consistent practices. I assumed that GMS2 would do this, as it would be the perfect time, but it really didn't.

I have found that "noob-friendly" features lead to more headaches. A prime example is the built-in health variable. How many posts have we seen about it confusing new users because it is global?

Another example, (though a bit off topic) is the DnD actions. Buffer actions are included for DnD. Why? Once you need to use buffers, you are 98% not likely to be using DnD. This, to me, shows a bit of foundational misdirection in "user-friendly" stuff.

I really like GML. It is super easy to use when it isn't being silently "forgiving". If we want to help new users, error-reporting should be improved to clarify why errors are happening. Gently educate the learning user. Don't coddle them.

It is better to make someone strong than to make someone dependent. ( I'm sure I'm "stealing" this, but not sure who I am quoting lol. )
 

jonjons

Member
There is an error in GM2 that show the message "Failed to compile" it doesnt tell in witch object the error is coming from nor the line number.
the error is simple missing a bracket " } "
if ( something )
{
if ( anotherthing )
{
a = b;
}
//} //--bracket out "Failed to compile"

the error is so simple that is almost not worthy to send it to the help desk... but the 1st time this happened to me it took me about 2 hours to know were the error was coming from...
 

jonjons

Member
I think GM focuses to much on comunity, and "we like to work with our comunity to improve GM" has a way of advertising GM..
Working with comunity on a game engine is the same thing has messing with fire... 2 or 3 persons want somenthing all of the sudden its like everyone wants the same thing. The improvement is moving back and foward and sometimes not getting out of the same place... Because another group of 2 or 3 people will come and ask for a diferent thing that will mess the previous one.

GM doesnt need to work with the comunity for opinions about what to do in the engine. They just need to look at other engines, and try to compete with each other, like video games compete with each other.

I think GM has the easiest coding ive ever seen, and they should focus more on the visual, small windows to would pop up for particles design, small windows to try various GPU set blend modes, even a shader designer would be nice, and materials that would make any crappy pixel art like ( undertale ) look nice.

I think GM starts in a point were you can do everything in GM the particles are the same has in Unreal, Unity and godot, but if you want visual its there in those engines, the same thing for draw_set_blend_mode_ext it does what the others do but visual editing is there in those engines.

When it comes to comunity the people who are in Unity dream about going into Unreal or GM, the people who are in GM dream about going into Unity or Godot, the people who are Godot dream about going into GM... In GM they want to go to construct 2, in construct 2 to GM... i dont know.

All i know is that all this engines take a very long time to learn the 1st you are there.
So its a waste of time everytime...

GM just need to look at other engines has a way to improve GM... look at Unity and Unreal they have amazing effects every crappy pixel art looks amazing... but when it comes to game mechanics they have to Hide the code under a carpet... Unreal does this very well with the blue prints... GM doesnt need this...
But making particles, gpu blend modes, and level effects without visual and only code its a big headache.
 

rIKmAN

Member
But making particles, gpu blend modes, and level effects without visual and only code its a big headache.
Around 2yrs ago all it apparently needed was the documentation updating, but if they ever get around to releasing the IDE Extension API then a lot of these tools will be built by the community in much the same way as they are with marketplace assets now.

This will leave YYG free to concentrate on core features, GML changes and more important things and leave editors like those you mention to be made by users, with the advantage now being that everything could be built into and an be an extension of the IDE.

With regards to these typecasting changes, the more I think about it the more ridiculous it becomes.
 

jonjons

Member
GML changes and more important things and leave editors like those you mention to be made by users, with the advantage now being that everything could be built into and an be an extension of the IDE
Yes i think thats what was going on in Unity... I rebember the 1st time i was using the engine a few year ago, they didnt had a tileset system, and everyone was using this free tileset app made by a user... later on they started to release tilesets in updates and today they have tiles with all types of weird collisions... they even have a free shader editor same for godot3...
And GM is still here trying to decide if a user should be allowed to use ints and strings together with int X = "ABC123", or X = "ABC" && 123
 
I was just gonna ask, isn't this whole thing the entire point of the string() and real() functions?

Sure, this might've been GML behavior before in some places, but if I had known about before I still would've thought it was stupid. I mean, at least this was an opportunity for me to be informed about this behavior. But also, consistency is better than the hidden behavior appearing in only some places.
 

Cpaz

Member
I think GM focuses to much on comunity, and "we like to work with our comunity to improve GM" has a way of advertising GM..
Working with comunity on a game engine is the same thing has messing with fire... 2 or 3 persons want somenthing all of the sudden its like everyone wants the same thing. The improvement is moving back and foward and sometimes not getting out of the same place... Because another group of 2 or 3 people will come and ask for a diferent thing that will mess the previous one.
This ties back into the identity crisis I've heard a couple of people say YOYOGames has had with GM for a while, since GMS2s announcement.
They're trying to please everyone, when they clearly cannot. Personally, this is why I feel they need to have a "Professional" and "beginner" sort of system instead of just DND and GML with the "professional' mode actually follow industry standards (proper type management and required semicolons as an example), while also allowing for more flexibility on the part of the developer. While the Beginner mode could simply do that under the hood while also stripping away a bit of that flexibility.

I think GM has the easiest coding ive ever seen, and they should focus more on the visual, small windows to would pop up for particles design, small windows to try various GPU set blend modes, even a shader designer would be nice, and materials that would make any crappy pixel art like ( undertale ) look nice.
That's actually a good point. But also ties in to what I mentioned above. I guess you could argue that they sort of already do have a "professional mode" with there being features like particles, shaders, and even 3D development that are on a whole different level from most of the rest of GML, with shaders using their language that's interfaced with GML.

I was just gonna ask, isn't this whole thing the entire point of the string() and real() functions?

Sure, this might've been GML behavior before in some places, but if I had known about before I still would've thought it was stupid. I mean, at least this was an opportunity for me to be informed about this behavior. But also, consistency is better than the hidden behavior appearing in only some places.
Maybe I'm still inexperienced with this sort of thing- but that were my thoughts exactly.

Somewhat related still, can I just say how I hope IDE plugins allow for GML modifications?
 
A

Andy

Guest
I would much rather backwards compatibility be preserved, and GML to remain consistently forgiving.
 

8BitWarrior

Member
I would much rather backwards compatibility be preserved, and GML to remain consistently forgiving.
An issue is that this "forgiving" behavior is potentially pushing problems further down the line. You think everything is fine, but your code has "walking pneumonia".

To put another spin on this topic... There are no jobs for GameMaker in my city of Vancouver. There is tons of game development going on here, but GameMaker is still looked upon as a hobbyist tool. The only reason I have a job with it is because I am teaching it part-time at a college. I upfront tell my students that GameMaker can help them get work in the industry, but that they won't actually use it in the industry. Studios still don't want to touch it. As soon as you have more than one coder on a single project, you really don't want forgiving code.

Us on this forum already know that GameMaker is an amazing tool for 2d game development (possibly the best), but its standards will likely have to mature before it is adopted by the broader industry.
 
Last edited:

kraifpatrik

Member
I think that fixing inconsistencies in behaviour is much more important than removing actual features from a language. Why shouldn't 3 * "9" result in "999" if that's an actual feature? Python has that I do use it there since it's just handy. Same for "2" + 1 resulting in "21", which also works in JavaScript and it's an expected behaviour there. Although I must say that if this post didn't exist, I wouldn't know that stuff like that was possible in GML. I don't know if I'm just too lazy to read the docs or if it's just not stated there, but if the latter is the case and people just don't have a way to learn about them, then that's something that YoYo should fix, but definitely not by removing them from GML just because they're not that common that every language ever has them.
 
Last edited:

kraifpatrik

Member
Because if I wanted to do real operations I would have set the value to 9 instead of "9", or I would have used the real() function on "9". That's what it's there for.
Well if you wanted to do 3 * 9 then you would. But if you wanted to get "999" then why not use 3 * "9" instead of string_repeat if that's shorter and you know that that works that way.
 

kraifpatrik

Member
Because it's not an int. Hence, if I want to treat it as such, I should convert - or get an error.
I'm lost. I think that if you wanted to treat it as an int, then you would surely cast it using real and then the result would be 27 as expected, but we are talking about concatenation of string "9" three times together to get "999". Those are two different operations and that's not a string being treated as an int since the results are different. If that's a feature of GML, then you have to remember it and either use it in your favor or just avoid it and use string_repeat instead if you find it confusing.
 

Dmi7ry

Member
I'm lost. I think that if you wanted to treat it as an int, then you would surely cast it using real and then the result would be 27 as expected, but we are talking about concatenation of string "9" three times together to get "999". Those are two different operations and that's not a string being treated as an int since the results are different. If that's a feature of GML, then you have to remember it and either use it in your favor or just avoid it and use string_repeat instead if you find it confusing.
Don't worry. You will understand it, when you work on big projects and, for example, get data from outside sources (from database, from server, etc). Once, when you will got string instead of number for some reason. And you will even don't know that your code works wrong.

Recently I got such situation. Problem with payment system on multiplayer project with 10000 players per day, exactly because of such problem (type was suddenly changed from number to string). It was very cost for us. We lost money and we lost a lot of time to eliminate the consequences of the problem.
 

YellowAfterlife

ᴏɴʟɪɴᴇ ᴍᴜʟᴛɪᴘʟᴀʏᴇʀ
Forum Staff
Moderator
Well if you wanted to do 3 * 9 then you would. But if you wanted to get "999" then why not use 3 * "9" instead of string_repeat if that's shorter and you know that that works that way.
Why stop there?
Let's make it so that "123" / 3 becomes an array with numbers 1, 2, and 3.
-"123" becomes "321". Sure, this will might lead to hundreds of errors, but you know that it works that way, and history seen no evidence of you ever making any mistakes.
And ~"123" should be "Ɛᘔ⇂"! Such a little neat trick, this would be so smart
In fact, why throw errors at all? So unproffesional! If anything bad happens, the game should restart immediately. Since no one makes any mistakes ever, you could use x+="no" as a shorthand for game_restart!





Well, let's talk about that backwards compatibility huh

So I've been trying to get a large-ish project to work with beta for sake of gif functions (which, as it turns out, don't work well enough for specific case), and it's been hours straight of running the game, getting another crash, and fixing another innocent-looking line of code like
Code:
if (string_variable) {...}
(which were completely valid before and would compare to "", so were used)

But also there are things like this
Code:
DoConv :1: illegal undefined/null use
 at gml_Object_... (line 26) -               if (phy_dynamic) {
of course, the manual ceases to mention that all of the physics variables might return who-knows-what if the instance in question is not physics-enabled, and now it's also illegal to check undefined for being bool, and bool() will not cast undefined to false, so I'm in for some unexciting refactoring

At this rate my next asset will be a static type analysis tool
 

kraifpatrik

Member
Don't worry. You will understand it, when you work on big projects and, for example, get data from outside sources (from database, from server, etc). Once, when you will got string instead of number for some reason. And you will even don't know that your code works wrong.

Recently I got such situation. Problem with payment system on multiplayer project with 10000 players per day, exactly because of such problem (type was suddenly changed from number to string). It was very cost for us. We lost money and we lost a lot of time to eliminate the consequences of the problem.
Well that's a mistake on the programmers' side rather than the language's fault. You have to write and pass tests before deploying something, especially in projects like that. Having those features is not a problem, problem is lack of knowledge of the language and writing unsafe and untested code.
 

rIKmAN

Member
Why stop there?
Let's make it so that "123" / 3 becomes an array with numbers 1, 2, and 3.
-"123" becomes "321". Sure, this will might lead to hundreds of errors, but you know that it works that way, and history seen no evidence of you ever making any mistakes.
And ~"123" should be "Ɛᘔ⇂"! Such a little neat trick, this would be so smart
In fact, why throw errors at all? So unproffesional! If anything bad happens, the game should restart immediately. Since no one makes any mistakes ever, you could use x+="no" as a shorthand for game_restart!
Those "out of bounds" errors are pretty annoying too, let's just silently expand the datastructure with 0s if someone attempts that so we don't have to see those ugly error messages either.

But if you wanted to get "999" then why not use 3 * "9"
Why not use "999" or string(999), remove the need for an arithmetic operation and maintain code readabilty?
 
Last edited:

Dmi7ry

Member
Well that's a mistake on the programmers' side rather than the language's fault.
It is exactly the language's problem, because the language hides errors from developers.

You have to write and pass tests before deploying something, especially in projects like that.
1. The problem is that with such behaviour you have no idea where the problem can appear.
2. So, I should rewrite a lot of code to add tests and rewrite a lot of third-party assets to add tests. And not only add tests but also fix all it to take into account the new behaviour. Great idea.

Having those features is not a problem, problem is lack of knowledge of the language and writing unsafe and untested code.
https://forum.yoyogames.com/index.php?threads/gml-consistency-in-gms2-v2-2-2.59856/#post-363021
You can control code you wrote yourself (even this case you may make errors/misprints/etc which leads to incorrect behaviour without crashes), but you can't control third-party assets (because you can't control what happens inside of them).
The case I wrote about is exactly third-party code. So we couldn't control it. But it's only an one case. There are thousands of them where you may have problems from such behaviour.
 
Last edited:

kraifpatrik

Member
Why not use "999" or string(999), remove the need for an arithmetic operation and maintain code readabilty?
Yeah I can agree with that. In a language where both 3 * "Hello " + "World" and string_repeat("Hello ", 3) + "World" result in "Hello Hello Hello World", I would and I do go with the string_repeat for extra clarity. I just don't think that makes the other way wrong. There are languages that support only the 3 * "Hello " way and no one complains there.

1. The problem is that with such behaviour you have no idea where the problem can appear.
2. So, I should rewrite a lot of code to add tests and rewrite a lot of third-party assets to add tests. And not only add tests but also fix all it to take into account the new behaviour. Great idea.
1. So while knowing the behaviour, you don't know where the behaviour can appear? Is that supposed to make any sense?
2. There is no need to go over the top with this. But yes, writing tests and robust code is generally a great idea. If you're using a third party asset that happens to have errors, then obviously it's not your mistake but the author's (EDIT: Oops, that's poorly written. I of course mean that the errors are author's fault, not that you use the asset). But saying that the language is poop because it allows for errors to occur does not help anyone, what could help though is letting the author know about the errors so he can fix it. Or I guess you could just switch to a strongly, statically typed language if weakly, dynamically typed languages cause you problems.
 
Last edited:

Dmi7ry

Member
1. So while knowing the behaviour, you don't know where the behaviour can appear? Is that supposed to make any sense?
You know only if you write new code. But you can't know what exactly may be broken in projects you written some years ago (or someone else from your team, or especially in third-party code).

2. There is no need to go over the top with this. But yes, writing tests and robust code is generally a great idea.
Any checks have cost. And not always is possible/reasonable to do any extra checks because of performance overhead. And you can't cover 100% of code by tests. Even if you have made some tests, it's not mean that it won't be broken after a new "GML Consistency" change.

But saying that the language is poop because it allows for errors to occur does not help anyone,
Silent convertion strings to numbers certain does not help anyone.
And not "allows for errors" but
Russel Kay said:
just silently continued with incorrect values
what could help though is letting the author know about the errors so he can fix it.
1. You can report an error only if you know about the error. But you may not know that your code was broken for some reason for days, months and even years (and all this time you will get a wrong result).
2. The author may not support the asset anymore (no time, no license for a new version of GMS, passed away, you can't contact the author, etc)

Or I guess you could just switch to a strongly, statically typed language if weakly, dynamically typed languages cause you problems.
I used more than 20 languages. About the last 7 years I mostly use D, C#, Lua, and GML. And I always use a language which better solves my current tasks. But obviously that with GMS it's not the case. You just have no choice with GMS. I can use another engine (and I did/do it, if needed). I even can write my own similar engine (and I did it some times). But I paid for GMS1.x and for GMS2 not to throw it away. I want GMS and GML became better, not worse.
 
Top