blog.oat.zone
λ
cd /isaacscript-3-electric-boogaloo/

IsaacScript: It Only Gets Worse

· by jill

Or, as an alternative title, "how the number 2.4MB slowly drove me insane".


It has been.. it has been, a little over a month since I've last talked about IsaacScript. And somehow, somehow, in that time span, it has only gotten worse.

For those not up to speed - I'm not reiterating the usual mantra. IsaacScript is TypeScript for Isaac modding, etc etc, you know the deal. If you don't, my previous article on it is a good starting point.

So then, what could possibly have happened since then?

IsaacScript in Lua

One evening, I checked up on the Isaac modding Discord, as a usual part of my routine. I checked the resources channel, where code snippets, libraries and similar things are commonly posted, and saw a very peculiar little message:

Zamiel announcing that the IsaacScript standard library is now available in Lua

And, I'll be honest - it looked neat!

local hasSadOnion = isc:anyPlayerHasCollectible(CollectibleType.COLLECTIBLE_SAD_ONION)
if hasSadOnion then
  print("One or more players has a Sad Onion.")
end

It's essentially a large collection of various snippets - grabbed from the IsaacScript standard library - shoved into a Lua library. Now, while I've already went into details about how the standard library is bloated to hell - this is a good starting point, and I appreciate it. I left a single message saying it's neat, and left it at that.

A text message from me that simply says "neat"

The next morning, a particular message is sent to the thread.

A user is asking if there will be autocomplete for the Lua language server; Zamiel responds, saying there already is one

I decided to check upon the library myself to make sure there wasn't just any simple mistake being made. I was at my phone at the time, so I had to use a mobile text editor. I downloaded the 2.4MB Lua file and-- wait, hold on, 2.4MB?!?!

The file is 2.4MB, or 2,442,682 bytes, to be precise

Yeah, so, uhm. This thing was fucking massive????

Now, okay, sure; I gave it the benefit of the doubt there, and looked inside the file, and I found that the filesize was completely justified-- nope, no, it's 56k lines of completely unminified, raw transpiled TS2L code with useless namespacing and no regard for variable name length or any sort of filesize considerations.

What was an even cooler discovery was that-- wait, no, hold on, if we're going through this in chronological order, we have to mention first that my file viewer had issues even displaying the damn file.

My text editor puts a note at the bottom of the file, notifying me that I've exceeded the maximum line count (51,200)

What was an even cooler discovery was that for whatever reason, this file was emulating a filesystem inside of it - every single individual source file had a namespace defined for it and a filepath assigned, and a huge chunk of code at the bottom individually sorted through the namespaces and... shoved them all under the same namespace, anyways.

What was an even COOLER discovery was that it also included the entire Isaac API!!! It included the Isaac TypeScript type definitions, for whatever reason, and the way those work is by redefining every single enum, global, and otherwise static value so TS can pick them up. This is not necessary in Lua, because Lua does not have a good type system. Yet it's done anyways, for whatever reason; and it just ends up writing down every enum in the game in a very inefficient manner.

Okay, okay. Sure, but did the original person ever get their issue solved? The one about autocompletion not being picked up for the Lua language server?

Zamiel replies, saying you need to increase the "max size" in settings.

You had to increase a limit inside the Lua language server in order to get the file to even load. Except - wait - it gets even better! That wasn't even what the person originally asked!

The user is replying, saying that the autocomplete still doesn't work

How did Zamiel respond?

Zamiel responds, saying that annotating types in comments is awful, and you should just use TypeScript if you care

Cool. Wonderful, so now we've just had the whole point of the library being available to Lua users completely removed too.

I brought the filesize concerns up to Zamiel, suggesting minification, considering this is a statically-linked library, and he– wait, what's that? I have a DM from Zamiel?

"please don't respond in any of my threads, i want nothing to do with you"

Turns out I have pissed off the dude so much that he doesn't want me to talk about his work in a public Discord server. And I did this by.. pointing out his library was unreasonably large. Which, mind you, I enjoy the concept of, but oh well.

I wanted to reply to him, telling him it's unreasonable for him to expect I never interact with him ever again (mind you, as a moderator on the server), but he instantly blocked me afterwards.

So, I decided to take this into my own hands. I put the library through a random minifier I found, and I managed to decrease the library filesize by not 20%, not 30%, and not even 40% - a minifier cut the filesize in half.

Before, the library was 2.4MB, and after, it became 1.2MB - achieving a compression ratio of 49.10%

How does Zamiel respond to this?

"re: minification, this is a common error that newer programmers make, read <link>. i have that oatmealine person blocked so I can't read anything they type, but absolutely nothing they say should be trusted and they basically have 0 clue"

He calls splitting the filesize in half a microoptimization and tells people I shouldn't ever be trusted.

You heard it here, folks! Jill Monoids is a pathological liar who hasn't even ever touched a computer! This entire article has been a lie up to this point, and since I've been revealed as a scam, I'm closing this entire blog!

He.. gets warned for this whole ordeal, because, well, why wouldn't he, and I move on with my life. A week later, exactly on the expiration date of his mute, he DMs me once again! Oh boy, is it an apology? Maybe some nice words for once?

Zamiel starts a message, telling me that I've ignored his request to ignore him, and proceeding to start a (cut-off) paragraph with "So here's my attempt to ask you privately once more."

Nope. Not even close. I've omitted the rest of this 3-paragraph message just for the guy's sake as I don't want to embarrass him too hard - but to summarize, he told me that he's asking me nicely to not post messages in reply to him, before proceeding to call me a deceptive liar and a high-schooler.

The original thread eventually gets closed, and the message is cross-posted again, now on the resources forum instead; he asks not to discuss the filesize in the post and proceeds to get horse-reacted 17 times (as of writing).

The IsaacScript Standard Library post. It has 17 horse reactions and 0 comments.

Except - wait, what's this - there's a new section under the documentation!

"If you think that file size matters, please see the "File Size" section in the docs. If you think that minification matters, please see the "Minification" section in the docs."

Oh boy, finally some actual arguments to debunk rather than "microoptimizations bad" and "filesize doesn't affect runtime"? Let's dig in!

File Size

Zamiel goes on to say that the filesize of a mod is mostly irrelevant and the fact that it isn't is a common misconception among beginner programmers.

He brings up 5 main points:

  • Runtime is not affected by filesize because no code is executed when the library is loaded, and upgradeMod is efficient enough to the point that you shouldn't care
  • Load times are largely irrelevant as well, as they don't affect actual performance, and even if they were, it barely affects the load time
  • You should care about download time even less than load time and based on an estimate average speed of 64.7 Mbps, the mod should download in just 0.3s, so who cares
  • Other assets are much heavier anyways, so really, why should you care about the smaller factors in your mod's filesize
  • While minification does split the filesize in half, it shouldn't be used anyways because it makes line numbers for errors unclear

Let's go through them one by one!

Runtime

This is not a point that people make. I appreciate that Zamiel wishes to clear up all sorts of misconception someone could have, but I have never stated that a large filesize would affect the runtime performance of the game. The game on its own weighs approximately 1GB with all the DLCs, and it dynamically loads the assets whenever needed while all mods' Lua files are loaded at loadtime, so even a 3MB library file spread across 100 mods wouldn't affect much.

Load time

This is, also not a point that people make. Again, I appreciate that Zamiel has cleared up all sorts of possible issues, and even went ahead and benchmarked the load time, but it's still not a point anyone's concerned about.

Download time

Oh boy. This is where we get into the meat of things. In short, I ran the numbers, and they're really bad.

Zamiel mentions that the average internet speed nowadays is about 8MB/s, citing an Oberlo article for the statistic. Now, I was already skeptical even upon hearing this claim - my home internet averages around 3.2MB/s on a good day, which is less than half of what's claimed in the article, and yet I'm fine with my internet speed. What's happening here?

MB/s? Mbps? What's the difference? Why use MB/s?

I've used Mbps a few paragraphs ago because I was directly quoting Zamiel - 64.7Mbps is 8.0875MB/s, so if anything, by rounding down, this conversion is biased in his favor. However, I find Mbps a bit unreasonable - all filesizes worldwide are measured in either MB or MiB, even when referring to download amounts; yet for speed, people multiply it by 8 to achieve Mbits for no real reason other than larger numbers, I guess.

You could argue that you get more precision with Mbps, but for this current article, this isn't really necessary, and I'm still going to include a reasonable amount of sigfigs with MB/s and use as many as possible with calculations under the hood.

The linked article cites another article by DataReportal, which then cites the raw data provided monthly by Ookla, who are the people behind Speedtest.net. Now, Ookla's data set is inevitably going to be quite biased - they aren't an ISP or even provide internet to anyone, really, they just run a speed testing website that has data centers practically everywhere. Their Server Network™ page cites a count of 16,000+ global testing servers, and this is largely because volunteers are allowed to host their own servers, if they so wish.

Now, guess what doesn't have 16k global testing servers that are inevitably going to make internet speeds seem a lot more ideal than they really are? Most sites on the web. Cloudflare, which (regrettably) hosts 3,280 out of 10,000 most popular websites, lists only 165 locations on their network page; Akamai, the CDN that powers Steam, cites 1.3k networks on their facts & figures page - it's not hard to see that it's going to be quite hard to reach the widespread server count that Speedtest has.

So, why don't we take a look at some other speed comparisons - for example, cable.co.uk's yearly worldwide internet speed data article.

While cable.co.uk is still not an ISP, they definitely have better practice dealing with them - their website focuses on letting people pick a better ISP, localized specifically to the UK. Personally, I trust them much more, at the very least; and their smaller size actually helps them in regards to avoiding bias.

Their article cites an average download speed of 4.3MB/s. A bit over half of what Ookla reported.

Now, we can argue about the average download speed worldwide all we want, and what sources are trustworthy and which aren't, but in the end, why compare download speeds worldwide if we can limit it to just Steam? After all, Steam is what everyone will be downloading your mod from.

Using Steam's download statistics website, specifically the direct JSON endpoints, I've estimated the average download speed to be 4.6MB/s - and this makes sense, as Steam's average user base tends to be bigger in more wealthy countries where computers are more available and spending money on video games is a lot more justifiable.

So, we've ended up with a download speed of around 4.5MB/s as a result of all of this - let's put those numbers to the test! Downloading just the 2.4MB library itself would take 0.53s - but this number doesn't really mean anything to us because that's only one mod.

Let's assume a typical mod count of 130 (roughly estimated by going through every public general-purpose collection that one of my mods, Dream, is featured in, and averaging the counts out) and a code mod percentage of 61% (estimated by checking the top 250 mods, and filtering by the "Lua" tag in the workshop). This leaves us with 80 code mods, give or take.

Now, if each one of these uses our dear IsaacScript Standard Library (which Zamiel very much advocates for) we're left with an increase of 192MB in filesize. Not good! You can store all of Baba is You in that amount of storage. Heck, you could store the original Flash Binding of Isaac, including the Wrath of the Lamb DLC 5 times.

Okay, but we're talking about download speeds - what's this going to take to download on our before-mentioned 4.5MB/s internet speed?

42 seconds. Hm. Maybe it's actually not a good idea to not do anything about this? Or, with my before-mentioned 3.2MB/s, a full minute.

And that's not even scratching the surface - sampling the average is clean and simple, but that doesn't account for those living in poorer countries. Using the Steam data set we've been using, with a country like Indonesia, we get an average internet speed of 2MB/s, or 1.5 minutes, and as a worst-case scenario, 10 minutes in Afghanistan.

Additionally, Zamiel's statement that the download time will affect a user exactly once isn't even true - updates in Isaac are not done on a delta basis, affecting only the changed files; rather, the entire mod is downloaded a second time. This will affect your users every time you change any single thing in your mod.

So, to summarize, at best, Zamiel's estimate of 0.3s is unintentionally misleading, and at worst, intentionally manipulative.

Other assets

Zamiel's main argument here (and everywhere, really!) is that Fiend Folio is 581MB, so really, why would you care about 2MB compared to that? This argument works on paper; but Zamiel fails to understand that Fiend Folio is, also, one of the biggest, most popular mods out there. If you take one of the biggest content mods, you're not going to be getting average statistics - you're going to get statistics closer to the top statistics of all time.

Zamiel also likes to claim that nobody cares that Fiend Folio is this big - when really, he just tends to ignore those who do.

But, regardless - this is a good point to consider. So I quickly checked the filesize of every mod I had installed on my own setup:

for f in (ls -d ./*_*); if test -e "$f/main.lua"; du -hs "$f"; end; end

The smallest mod I had installed was 12KB, while the largest was 627MB. The average was 7.83MB - but if we ignore mods >400MB (considering them large content expansion mods), we end up with a filesize of 2.8MB - if each one of those had had our beloved 2.4MB library, that would practically double the filesize.

I get where Zamiel is coming from - when you have a massive expansion mod, it's fine to leave a dependency like that in because, at that point, who cares; but most of the mods people make are not massive expansion mods, and Zamiel will push this onto beginners who are making simple tweak mods that take up less than a megabyte.

Minification

Zamiel says that runtime errors will be harder to debug with minified code, and to that I say - have you ever done any work with the web?

Libraries made for the web will almost always offer 2 alternatives of their libraries - one unobfuscated, in its raw source code, for a development environment, and another minified, meant for production use.

The reason I bring this up is, and I shouldn't have to spell this out - just replace the library once you're uploading the mod. Runtime errors aren't impossible to debug once a mod is minified, mind you, if you're thinking of how post-release errors could be solved - they're just more tedious, but you could always map minified code to the source code, with– wait, no. I forgot.

Libraries for the web typically offer 3 downloads. One unobfuscated, one minified, and a source map. With the source map, you can map errors, stack traces, and other line number-dependent things to the source code.

Do you get what I'm hinting at here?

So the downside of not being able to read the source code is a very tiny and easily avoidable one - there's no reason not to minify your code if it's reaching 2.4MB, at this point.

And, besides, Zamiel has many times said that TS2L output should be treated like x86 ASM and not ever considered to be read; so what's up with those double standards?

What Zamiel doesn't mention

Zamiel also forgets to mention another important aspect of this - file size when stored on disk. Using our previous numbers of 80 code mods resulting in 192MB, that is not a small number whatsoever.

For one, you're obviously going to be wasting SSD write cycles - SSDs have a limited amount of data you can write to it before they combust into flames, and having to re-write a 2.4MB file on download and on each update isn't going to be the best thing to contribute to that. Sure, you could argue it's tiny and irrelevant, but it will pile up and it will keep piling up the longer you play Isaac on your machine for.

For two, we really don't want to be going into storage compactness logic that AAA titles have. Again, I'd like to reiterate - you can fit many games in the 192MB that would otherwise be used up by mostly dead code. For some, storage is a lot harder to get by, being limited to 128GB on say, a cheaper laptop, and I'd highly like to avoid contributing to that.

I get that I'm being a little pedantic here, but it's not like Zamiel hasn't done this multiple times in the past; and regardless, it's still an important point to consider.

Summary

So, to summarize, IsaacScript has only gotten worse now that Zamiel can try to force everyone, even Lua users, to have to put up with his awful takes about microoptimizations.

Ever since the creation of this library, Zamiel has only gotten more persistent about getting people to use his work - Zamiel has before said the resources channel is "(mostly) deprecated now that isc works in lua", and he will not ever shut up about it if someone says that they want a feature to be present in the vanilla API, even if it's a tiny shortcut method.

Zamiel himself has only gotten worse, too. We had a cute little love-hate relationship going on, but now he's dumped me and I feel extremely betrayed.

I'm hoping this is the last article I'll write here about IsaacScript. I'm not going to be writing more update posts following IsaacScript's development, else I run the risk of just turning my blog into a blog about IsaacScript. I don't think I care about it that much.

And that's all, folks! And remember: Jill Monoids is not an individual to be trusted! I'll be posting more alt-right propaganda next Tuesday!! :)


published