Void require(Instance module)

In regular Lua, you can have modules that don’t need to return anything, but rather their contents get “injected” into the required environment.

You can put nothing but this in a module:

function Round(num, idp)
	local mult = 10 ^ (idp or 0)
	return floor(num * mult + 0.5) / mult
end

And doing this would work in another script:

require("MathLib")
local n = Round(2.50014)

Why does roblox require modules to return a value? Why is this functionality not available?
Can it be?

Of course someones gonna tell me “omg no you’re polluting the namespace”, but this is incredibly useful if you have a set of functions that you use literally everywhere

2 Likes

There’s actually a way to do this with getfenv, but nonetheless YES YES YES SO MUCH YES.

1 Like

I think you meant this ? (Not sure or correct, currently on mobile)

local module = require(MODULE_PATH);

-- Add it to the enviroment
for i,v in pairs(module) do
getfenv(2)[i] = v;
end
local function f()
  local caller_env = getfenv(2)
  caller_env.test = function() print'a' end
end

--in another script:
f()
test()
--> 'a'

^ Courtesy of @nomer888

But again this requires a lot of extra code and kinda goes against how simple it would be if it was like regular lua

Also it gives you a script editor warning because the editor doesnt catch getfenv() is being used and thinks the variable is undefined. Yay for polluting the very useful warnings window also :)))))))

1 Like

This is the cleanest way to do it.

local myEnv = getfenv()
LEET = Vector3.new(1,3,7)
--
return function ()
	local callingEnv = getfenv(2)
	for k,v in pairs(myEnv) do
		callingEnv[k] = v
	end
end

Then in a script inside of the ModuleScript:

require(script.Parent)()
print(LEET)
3 Likes

Optional implementation that only fetches variables when you request them, instead of dumping them all at once.

local myEnv = getfenv()
--
local coreMeta = 
{
	__index = function (env,k)
		local v = myEnv[k]
		if v then
			rawset(env,k,v)
			return v
		end
	end
}
--
return function ()
	local callingEnv = getfenv(2)
	local newEnv = {}
	newEnv.script = callingEnv.script
	setmetatable(newEnv,coreMeta)
	setfenv(2,newEnv)
end
1 Like

A better name for such a function would be include.

11 Likes

pls

2 Likes

Fun fact: This pattern is discouraged in newer versions of Lua because it’s genuinely awful (look it up).

If you need an example, I have two modules that use this pattern. Both inject the DoThing function. I need to use both functions in my code. But I am screwed because this patterns sucks and you should never use it.

5 Likes

I’m very antsy about having redundant code. I like to avoid it as much as possible, so I can strictly focus on writing the logic code, rather than having to worry about what I actually need to have in the environment.

It’d be nice if we could have something as clean and condensed as a C++ header file to quickly inject several libraries into our script’s environment.

1 Like

In general people typically use namespaces to avoid polluting the global namespace in C++, so it ends up being pretty much the same as using a module. (namespace::hello_world() vs module.helloWorld()). If you don’t use namespaces it will eventually lead to pain when you define something twice.

It might be fine for smaller projects but if you are using other peoples libraries it would be terrible if they polluted the global namespace.

3 Likes

Generally speaking, maintainability and getfenv are mutually exclusive.

This pattern is horrific on many levels. Aside from inheriting every one of the numerous problems of C++'s using namespace, it

  • needs boilerplate in every module
  • disregards organization and separability
  • forces you to use Ctrl-Shift-F just to know where a function is located
4 Likes

Including being encouraged in entry level C++ college courses rip

Personally I want to just be able to return nil from a module without an error, sometimes I want to run some code on a specific thread and wish to use modules to keep the code tidy.

Edit: Apparently you can, thanks @EchoReaper

You can if you manually return nil. If you leave it implicit (meaning you don’t specify anything) it’ll error, but if you explicitly return nil it’ll work.

1 Like

I get that its horrible, but why can’t the option be there anyway?
I’m not straight up dumping hundreds of variables into the environment, I’m just dumping a few libraries and functions (with unique names and purposes) within a namespace that I use a lot.

I just want it to be less of a redundant hassle to set up the logic code in my games.

Current method:

local lib = require(script.Lib)
lib.a()

Proposed change:

require(script.Lib)
a()

I don’t see how this would make it less of a hassle since you still have to manually import/require modules, and god forbid you have to type mathLib.round() instead of round(). If you’re really that set on doing something so silly in order to save on a couple of characters, you can just name your module requires something short and generic like ‘a’

2 Likes

Well it’s not really that much of a change, the functionality exists in vanilla Lua, and you can use either method based on your needs

Regardless of whether it’s in vanilla Lua or not, it’s not in ROBLOX Lua. It’s no different than any other feature request because something has to be changed.

No one has provided compelling evidence that the proposed change is even needed. Vanilla Lua or x language having it is not justification. This isn’t a matter of copying/pasting functions across multiple scripts, managing long lists of imports, or improving readability – the only benefit that has been mentioned is saving lazy people from having to type out a couple extra characters.