[size=5]How is it going there, fellow developers?[/size]
Some of you guys may have heard of this concept before in a previous thread, but I don’t think I was clear enough on what I was trying to describe. So, I’m going to give it another go, and explain why I think this idea should be implemented.
[size=4]What is a SharedModule?[/size]
A SharedModule is a subclass of ModuleScript which will inherit the environment of the first caller. This allows developers to easily separate portions of code, while not having to do ugly getfenv/setfenv hacks, or returning a function and passing variables through it. The whole idea is similar to how normal Lua modules work. Additionally, a SharedModule will inherit all of the properties of the calling Script, as if it was never separated from the calling Script.
[size=4]Why should we (ROBLOX Developers) implement this Subclass?[/size]
By implementing this Subclass, developers who take advantage of the feature will reduce performance impact on servers by reducing memory usage, not creating a lot of unnecessary environments, and will overall keep code cleaner. With ModuleScripts, you can easily make your code much cleaner, but there is one issue - Each ModuleScript creates it’s OWN ENVIRONMENT, which in some cases, isn’t even used. If you have a script which uses 20 Modules, and none of them really take advantage of their environment, how effective is that for the server having to handle those tasks? Not very…
This being my second time, I hope you guys will understand my reasoning, because I believe this would help increase performance of Lua Scripts, and resources the server has for operation of the game. Thanks! #ReinitializedOnceMore
You tried to put a lot of emphasis thinking that by reducing ModuleScript environments we would actually increase performance. I doubt we would see any noticeable impact. Many developers has used a TON of ModuleScripts and their game runs fine. On top of this, SharedModules would create their own environment as well and just copy the caller’s environment by how you described it. Basically the same thing as getfenv and setfenv. ModuleScripts create their own environment because the information needs to be stored somewhere. ModuleScripts can even be used for data management.
Overall, I’m not into too much support for this idea because I don’t find performance an issue and I’ve never ran into needing this. If other developers can find reasons supporting it then I’ll probably change my mind. But usually just structuring your data setup makes this not really necessary.
This is extremely bad coding practice and is the one road to spaghetti code, in this case you can’t use your module without the right properties in the current environment, so your code is not portable, and even you will forget how all of your modules interact with each other’s environment after a while.
Encapsulation and getters/setters for variables is a much better way of doing things, I really don’t believe this will improve anyone’s code. If you think it will, you might want to check out how you organize variables between your modules and see if there isn’t a smarter way to do it.
Environments are cheap. They’re simply Lua tables with usually one entry: the key is [tt]“script”[/tt] and the value is the script object associated with the environment. They also have a metatable with its [tt]__index[/tt] metafield pointing to the globals table, which allows global variables like [tt]game[/tt], [tt]print[/tt], and [tt]tostring[/tt] to be resolved.
The point is that the cost of creating a few extra environments is negligible.
But what you’re proposing is a hack. You’re saying that wherever a SharedModule is required, its code would be immediately evaluated in the environment of the caller. You can implement this currently like so:
-- SharedModule
return function()
setfenv(1, getfenv(2))
-- code goes here
end
Does that code look ugly to you? Good, because it is ugly. It means the module can make any changes to variables in the caller’s environment it wants. You should strive to make your code modular, so that the module doesn’t need to know anything the caller other than the arguments passed into the module’s methods. The idea of SharedModules violates the idea of encapsulation because it means the SharedModule and its caller are coupled too tightly.
Sometimes it is nice to make a module which modifies the caller’s environment, so you don’t have to copy a bunch of boilerplate code for every caller. You should make this explicit by passing the caller’s environment as an argument to the module:
local Module = require(game.ServerStorage.Module)
local module = Module.new(getfenv())
Seranok,
And as of right now, that is what I am doing. In my ModuleScripts, this is how I am getting around the issue:
return function(FSCore,Data)
local Module={} do
-- do stuff here
end;
FSCore[script.Name]=Module;
end;
Currently, this situation works well, and resolves the issue. However, I feel that doing such thing is also a hack, and does make a performance difference. Regardless of whether the issue is small or not, if you use a bunch of ModuleScripts, you are creating a bunch of useless environments, even if they leave a small footstep. In games, having the ability to maintain as much resources as possible is important, especially since we can’t just add new hardware to the server/request more resources. I rather have 50 “hacky” SharedModules which inherit the requesters environment than 50 ModuleScripts which have their own isolated environment, and won’t work well without having FSCore/FSServer/FSClient. My code is modular, but only modular to a degree without using FSCore. Mainly, I am using this to organize my code so I don’t get distracted when writing hundreds to thousands of lines of code.
I’ve attempted a hacky version of this, and this would be an interesting idea. However, the concept is to reduce the amount of useless environments, and allow users to separate portions of code to organize into sections. I’ve never really worked with a language which uses include, so I could have used it wrong. However, it may solve my small complaint.
This is in the order of kilobytes of data, in other words this should not affect anything in your game, I don’t think the performance argument holds in any way for your suggested feature.
This is in the order of kilobytes of data, in other words this should not affect anything in your game, I don’t think the performance argument holds in any way for your suggested feature.[/quote]
I will admit to using as a placeholder, because the feature I am requesting is honestly a personal preference of how I organize code. However, doing further research, I’ve noticed that the standard Module system in Lua 5.1+ uses the same idea that I am asking for. How is having a similar system compared to the default Lua module system a bad practice, and considered a “ugly coding hack”? I would like to be informed of such issue, since I don’t see any problems with this other than it being considered a ugly coding hack that causes a spaggehti of code.
ModuleScripts are Module scripts. Thus, it wouldn’t even seem to be proper practice to be porting environments to them. They should be created in a manner that is modular. Of course, sometimes you need to pass certain parameters to them for initialization, but whole environments seems a bit crazy and outside the use for them.
I have never used getfenv or setfenv in any of my Roblox games, nor will I ever have to. You can easily code your game without any need for them, and still get very good module and clean code throughout your game.
Not trying to bash your idea though. It’s an interesting idea, but I’m not sure it really fits with what we should be doing.
This is in the order of kilobytes of data, in other words this should not affect anything in your game, I don’t think the performance argument holds in any way for your suggested feature.[/quote]
I will admit to using as a placeholder, because the feature I am requesting is honestly a personal preference of how I organize code. However, doing further research, I’ve noticed that the standard Module system in Lua 5.1+ uses the same idea that I am asking for. How is having a similar system compared to the default Lua module system a bad practice, and considered a “ugly coding hack”? I would like to be informed of such issue, since I don’t see any problems with this other than it being considered a ugly coding hack that causes a spaggehti of code.[/quote]
The reason the default Lua module system is the way it is is because there’s no global metatable of all fenvs. If it had one, I can guarantee the designers would go with the way ROBLOX did. Just because a different set of circumstances has a different solution doesn’t mean we should have one.
This is a poor idea, and you should write code to avoid having any ties to the parent module; you’re coupling it too tightly.
This is in the order of kilobytes of data, in other words this should not affect anything in your game, I don’t think the performance argument holds in any way for your suggested feature.[/quote]
I will admit to using as a placeholder, because the feature I am requesting is honestly a personal preference of how I organize code. However, doing further research, I’ve noticed that the standard Module system in Lua 5.1+ uses the same idea that I am asking for. How is having a similar system compared to the default Lua module system a bad practice, and considered a “ugly coding hack”? I would like to be informed of such issue, since I don’t see any problems with this other than it being considered a ugly coding hack that causes a spaggehti of code.[/quote]
The reason the default Lua module system is the way it is is because there’s no global metatable of all fenvs. If it had one, I can guarantee the designers would go with the way ROBLOX did. Just because a different set of circumstances has a different solution doesn’t mean we should have one.
This is a poor idea, and you should write code to avoid having any ties to the parent module; you’re coupling it too tightly.[/quote]
Alright. This thread has cleared up some information about how I should use ModuleScripts! However, the design of my product is semi-modular for a reason - I want the program to be modular so it can attempt to unload and reload problem Modules, and so I can separate large sections of code and not get distracted by a piece of code I might consider to be a problem later on. I’ve always ran into issues when I am writing large projects, especially when it comes to trying to setup the foundation. I constantly keep rewriting code because I feel it may cause a big issue in the future, and I don’t want to have to rewrite huge sections of my code since I am using building the code as the foundation. I feel that dividing code into Modules would reduce these chances, since I would only see that section of code. However, I don’t like having the side-effect of creating separate events. In the end, having separated environments is a good thing, since it will assist in debugging issues more effectively.
I’ve attempted a hacky version of this, and this would be an interesting idea. However, the concept is to reduce the amount of useless environments, and allow users to separate portions of code to organize into sections. I’ve never really worked with a language which uses include, so I could have used it wrong. However, it may solve my small complaint.[/quote]Include is very simple and extremely useful. It runs the code on the same thread within the environment that include was called.
-- IncludeScript
print(a)
local a = 5
include(script.IncludeScript)
5
It can also be used for the inverse.
-- IncludeScript
function doubleNumber(x)
return x + x
end
This is in the order of kilobytes of data, in other words this should not affect anything in your game, I don’t think the performance argument holds in any way for your suggested feature.[/quote]
I will admit to using as a placeholder, because the feature I am requesting is honestly a personal preference of how I organize code. However, doing further research, I’ve noticed that the standard Module system in Lua 5.1+ uses the same idea that I am asking for. How is having a similar system compared to the default Lua module system a bad practice, and considered a “ugly coding hack”? I would like to be informed of such issue, since I don’t see any problems with this other than it being considered a ugly coding hack that causes a spaggehti of code.[/quote]
The reason the default Lua module system is the way it is is because there’s no global metatable of all fenvs. If it had one, I can guarantee the designers would go with the way ROBLOX did. Just because a different set of circumstances has a different solution doesn’t mean we should have one.
This is a poor idea, and you should write code to avoid having any ties to the parent module; you’re coupling it too tightly.[/quote]
To add on, I’m pretty sure Lua 5.1’s package system was scrapped in later versions of Lua due to similar reasons.