Functions & Parameters - Any Improvements?

Hello!

I’m still pretty new to scripting, and this morning I watched some tutorials on functions, parameters, and arguments. For the past hour or so, I’ve been experimenting with the new API I’ve learned, and I wrote the following code, which generates 2 different parts and prints a statement after each:

function generatePart(name, color, transparency, material)
	local part = Instance.new("Part")
	part.Name = name
	part.BrickColor = BrickColor.new(color)
	part.Anchored = true
	part.Transparency = transparency
	part.Material = material
	part.Parent = workspace
end

function printText(text)
	print(text)
end

generatePart("GrassPart", "Shamrock", 0, Enum.Material.Grass)
printText("GrassPart was created.")

wait(5)

generatePart("GlassPart", "Light blue", 0.2, Enum.Material.Glass)
printText("GlassPart was created.")

The code works fine, but I’d like to know if I’m using any practices that aren’t the best, or if there’s a way I can simplify this code or improve it. Thanks!

3 Likes

This is pointless. This is basically* equivalent to just local printText = print, since it takes the same arguments it gives print and it doesn’t do anything other than call it.

(*: Yeah, yeah. print can take multiple arguments while this just takes one.)


Other than that, though, it seems good. Nice job parenting it after setting the other properties—it’s a common mistake to parent first.

7 Likes

Thank you! I do want to clarify something:

A function can have as many parameters as needed, correct? As in, no parameter limits?

I think the limit of 200 locals applies here:


I seriously doubt you’d need to use that many parameters, though.

4 Likes

I heard it’s better if you use local function instead of function. Though there will be situations where function is necessary like ModuleScripts.

1 Like

I think you did good here. You created reusable code functions. You scoped variables appropriately. Only suggestion I would give here is comment your code. It’s ok to be verbose when commenting.

2 Likes

There isn’t really anything to change, it works well! I suppose you should make generatePart return the part that was generated.

Though, I think a clarification would help. A function is treated like any other datatypes (i.e strings, numbers, tables). It isn’t a feature of Roblox’s API. When you’re creating a function, it’s literally doing this:

local add = function(addend1, addend2)
    return addend1 + addend2
end

It also means you can pass functions to functions and return functions as well. Hope it makes sense?

1 Like

Makes sense! So if I were to return the Part, like you said:

function generatePart(name, color, transparency, material)
	local part = Instance.new("Part")
	part.Name = name
	part.BrickColor = BrickColor.new(color)
	part.Anchored = true
	part.Transparency = transparency
	part.Material = material
	part.Parent = workspace
    return part
end

I could use the part variable anywhere in the script? Like:

local part = generatePart("GrassPart", "Shamrock", 0, Enum.Material.Grass)
print(part.Name.." was created.") --using the part variable to get its name

Well, yeah. As long it following scoping.

Keep in mind that parts are technically just tables in Lua. So, you are holding a reference to it in memory. If you ran :Destroy() on it while there is still a reference to it, it’ll stick in memory. Be wary of that!

1 Like

Could you please post a code example of this please? Just trying to understand what you mean.

Sure!

local Part = Instance.new("Part") -- First reference
local Parts = { Part } -- Second reference

Part:Destroy() -- Destroy it!
Part = nil  -- The first reference is now gone

See how there is still a reference in of the destroyed part in the array named “Parts”? Until that reference is gone, the part will stick in memory forever. Additionally, connections can also indirectly leak memory as well!

local Part = Instance.new("Part")
Part.Touched:Connect(function()
    Part.Color = BrickColor.random() -- The reference now exists in this closure!
end)

The function will exist until it’s reference is gone (disconnecting it). Once all of it’s references is gone, it will be removed from memory (garbage collected). Thus, destroying the reference within the function as well.

(PSA: Connections can memory leak Instances!)

2 Likes

One idea that you might find interesting is to pass in arguments as a table. There are a few benefits:

  1. You always know what each parameter means
  2. You can easily add new parameters to a function without worrying about order

Here’s an example:

local params = {
   ["name"] = "GrassPart";
   ["color"] = "Light blue";
   ["transparency"] = 0;
   ["material"] = Enum.Material.Grass;
}

generatePart(params);

This is how you can access the parameters inside the function:

function generatePart(params)
	local part = Instance.new("Part")
	part.Name = params.name
	part.BrickColor = BrickColor.new(params.color)
	part.Anchored = true
	part.Transparency = params.transparency
	part.Material = params.material
	part.Parent = workspace
end

This would make a difference on a larger codebase where if you use a functions with more than 1 parameter and it’s hard to remember what each argument means when all you see is arguments like myFunction(1, 2, 3, 4).

So, it’s self documenting code really.

As mentioned, it also helps if you want to add a new function to the argument because you don’t need to worry about order and again you can easily see what the new argument is.

Hope this helps!

2 Likes

Thank you for providing me with some insight.