Modifying Math (It can be done, but should it?)

Is there anything wrong with me doing this? It seems to work perfectly fine which is cool but I feel like someone here probably has a good argument for why this shouldn’t be done so hit me with it

I made a module that has some custom functions, and all of the functions from math, and I assign math to = the required module

There’s no errors or warnings or anything and it works almost exactly how I hoped it would.

My method to accomplish this is pretty simple
image

1 Like

Looks fine to me. It does break an expectation for other programmers reading your code. IE if you were going to ask for help on this forum or show off your code, you’d need to include the assignment to math at the top of your code as well. The more lines like this there are, the harder to read and debug the code will likely become.

Another option would be to make a module named VectorMath

Also, how is the current implementation being created? I’d set the module’s __index to math instead of manually moving over functions that you need.

It’s fine (I have all my overrides in a folder called Boilerplate), but your code for math is a bit weird. I’d recommend:

local module = {}

function module.round(number)
    return math.floor(number + 0.5)
end

return setmetatable(module, { __index = math })
1 Like

You can also do…

return number + 0.5 - (number + 0.5) % 1

A bit more efficient.

1 Like

Harder to read though and less standard approach (in my opinion), so unless you need high performance I would probably still use the former.

1 Like

Your method is the cleanest I could think of. There’s nothing wrong with writing code like that because you’re just utilizing ternary operators. Sure, it might look better being spaced out using conditionals, but there’s nothing wrong with how you wrote it.

He’s talking about the idea of overriding the math library.

I wouldn’t do this just because it’s easy to make wrong assumptions or confuse others. Examples:

  • Script gets much larger, someone finds math.round in it, and thinks it’s an official function because they didn’t see the module require
  • Script gets much larger, and someone can’t understand why it works since math doesn’t have a round function and they didn’t see the module require
  • You copy content from that script elsewhere and it breaks because the parent doesn’t also have a math override module

In general, when I have boilerplate utility functions like this, I just add them to shared (Roblox alternative to _G). E.g.: shared.math.round(...). This is the one case where globals are better than the alternatives: you don’t have to add boilerplate modules to every script in your game, it’s clear where the method is coming from, and you can copy it anywhere within the project and it will still work.

I only use this approach for stateless functions that are used by a large number of unrelated scripts. If neither of those are the case, usually localizing them to what needs them is a better alternative.

3 Likes

It should be noted that shared and _G are the exact same in nature. shared is just an artifact of when _G could edit the global namespace.

Oh I was mistaken. Read this and responded without really thinking it through.

I would instead make a math utility/extension/whatever. Basically exactly as you have it, but don’t override math.

For instance, I have a TableUtil module that I use, which I could override table with, but I keep it named as tableUtil instead to avoid confusion and make it clear that it’s my own custom suit of table functions.