Practicing Printing, Functions, Returning, Tables, and Loops - Any Improvements?

Hello!

I’m in the process of learning how to script. Every so often, I try and make my own script using what I’ve learned so far. Yesterday, I learned the use of return, and decided to toss it in with the rest of the stuff I know to make a functioning block of code.

While I was doing this, I decided to try my luck at small tables and loops. To my extreme surprise, everything I scripted worked perfectly.

Now, I’m sure that because I’m quite new to this stuff, some of my code isn’t going to be efficient - which is why I’ve come to ask for tips on how to make it better:

-- the following code will instance 6 orange parts (each with a different position and material), which will then turn a shade of blue after 20 seconds

local function generatePart(material,position)
	
	local part = Instance.new("Part")
	part.Name = "Orange"..material.."Part"
	part.BrickColor = BrickColor.new("Neon orange")
	part.Material = material
	part.Anchored = true
	part.Position = position
	part.Parent = workspace
	
	print(part.Name.." was created.")
	
	return part
	
end

-- this looks a bit inefficient to me; not sure
local glassPart = generatePart("Glass",Vector3.new(0,0,0))
local grassPart = generatePart("Grass",Vector3.new(5,0,5))
local slatePart = generatePart("Slate",Vector3.new(10,0,10))
local sandPart = generatePart("Sand",Vector3.new(15,0,15))
local brickPart = generatePart("Brick",Vector3.new(20,0,20))
local neonPart = generatePart("Neon",Vector3.new(25,0,25))

local partTable = {
	glassPart,
	grassPart,
	slatePart,
	sandPart,
	brickPart,
	neonPart
}

for i = 20,0,-1 do
	print(i)
	wait(1)
end

for i, v in pairs(partTable) do
	v.BrickColor = BrickColor.new("Medium blue")
	print(v.Name.."'s BrickColor was changed to Medium blue.")
end
Video of result

If there’s some feedback you’d like to share regarding the tables or loops, I kindly ask for you to explain it thoroughly (because I’m not too experienced with those).

Thanks!

4 Likes

Good so far, you’re on the right track.

For the for loop that you made, it would probably be better to go from 0 to 20. Depending on your case you might want to go backwards which is where you can use a negative step (incrementing) value, thus resulting in that loop counting back from 20 to 0. Most cases though you’ll be doing positive incrementing.

For going through the partTable, use ipairs instead of pairs. The way you’ve created your table is such that it becomes a list (specific name for it is an array). ipairs will count your list in the order that you wrote it in, while pairs doesn’t have that same guarantee.

1 Like

Thank you for the feedback!

So maybe like this?

for i = 0,20,1 do
   print(i)
   wait(1)
end

Would this work?

for i, v in ipairs(partTable) do
    v.BrickColor = BrickColor.new("Medium blue")
    print(v.Name.."'s BrickColor was changed to Medium blue.")
end

And regarding this, a quick clarification:

ipairs is different from pairs in the sense that it loops through a table or whatever incrementally/in order, correct? As in, 1 to 10 rather than it being random (pairs)?

1 Like

I just want to start by saying that it’s really good that you’re willing to make a test project to actually use everything you’ve learned so far.

As for my tip, only do this if you think it makes your code cleaner, it’s kind of based off preference. But you can make the part outside the generatePart function, then inside of the function just set it’s material and position.

As for the difference between ipairs and pairs, here is a little example code.

local t = {
	"ok";
	"ok";
	"ok";
}

local function printTable_ipairs(t)
	print("printing ipairs")
	for index, value in ipairs(t) do
		print(index, value)
	end
end

local function printTable_pairs(t)
	print("printing pairs")
	for index, value in pairs(t) do
		print(index, value)
	end
end

printTable_ipairs(t)
printTable_pairs(t)

t[4] = "yuh"

printTable_ipairs(t)
printTable_pairs(t)

t[8] = "yeehaw"
t.hello = "world"

printTable_ipairs(t)
printTable_pairs(t)

If you look at the output, you will notice that ipairs only prints from 1 up until it finds a nil value, which is typical for an array like the part table you made. Using ipairs is like letting your compiler know that there will only be numeric keys from 1 to the number of keys in the table, or at least that’s all your interested in iterating over, which is efficient as it doesn’t have to search for any other keys in the table.

3 Likes

You don’t need the variables to refer to the parts, you’ve got the table for that:

local partTable = {
	generatePart("Glass",Vector3.new(0,0,0)),
	generatePart("Grass",Vector3.new(5,0,5)),
	generatePart("Slate",Vector3.new(10,0,10)),
	generatePart("Sand",Vector3.new(15,0,15)),
	generatePart("Brick",Vector3.new(20,0,20)),
	generatePart("Neon",Vector3.new(25,0,25)),
}

If you feel like calling the same function like this is repetitive and thus “inefficient”, you’re right. But inventing a system to do it with less typing takes time, so you have to consider the cost/benefit of doing so.

1 Like

If you’re doing positive incrementation, you do not need a step value since it will default to 1. This will do i+1 incrementation for you.

for i = 0, 20 do
    print(i)
end

For the clarification piece, yes that is correct. ipairs will basically do that same numeric loop you did above by starting at 1 and counting up, then it returns the position and element at that position in the list. A position is referred to by its term index and in your case, position/index 1 in partTable is glassPart. pairs, on the other hand, doesn’t rely on counting up like that so order isn’t guaranteed when it goes through the table. That’s best for when you explicitly change the index for something else, like:

local partTable = {
    ["Glass"] = Enum.Material.Glass
}

ipairs will not work on a table like this, but pairs will. There’s no longer numbered indexes being used here and its not a list, rather a dictionary. A dictionary is best described as its literal word: giving definition to something. You can find some resources on the net about dictionaries and arrays. Keep it to Lua so you might be able to understand better.

2 Likes

Looks good, atleast for me but there are still improvements to be made.

local glassPart = generatePart("Glass",Vector3.new(0,0,0))

Instead of passing it as a string, it would be better if you use Enums instead.

local glassPart = generatePart(Enum.Material.Glass,Vector3.new(0,0,0))

Your function generatePart seems alright but you don’t check if position is a Vector3 data type as well as the material. This is so you don’t run into errors where you accidentally didn’t pass the parameter right, your function should handle them. Also it would be better if it included more parameters such as brickcolor. The name of the function is ‘Ok’ but better one would be createPart.

You can use assert as it first checks if the first value is true and if not, will error(the string you provided in the second argument)

Using string.format is also something to take in consider, only difference is that it provides a negligible performance boost and looks cleaner.

Also ipairs is used when iterating through an array(table) because it loops definitely.

Here’s how I would write your code:

local function generatePart(material,position)
	
	assert(typeof(material) == "Enum" or "String", string.format("createPart: 'material' enum expected, got %s", tostring(typeof(material))))
	
	assert(typeof(position) == "Vector3", string.format("createPart: 'position' Vector3 Datatype expected, got %s", tostring(typeof(position))))
		
		local part = Instance.new("Part")
		part.Name = string.format("Orange %s %s", material, "Part")
		part.BrickColor = BrickColor.new("Neon orange")
		part.Material = material
		part.Anchored = true
		part.Position = position
		part.Parent = workspace
		
		print(string.format("Created %s", part.Name))
		
		return part
		
end

local partTable = {
	generatePart("Glass",Vector3.new(0,0,0)),
	generatePart("Grass",Vector3.new(5,0,5)),
	generatePart("Slate",Vector3.new(10,0,10)),
	generatePart("Sand",Vector3.new(15,0,15)),
	generatePart("Brick",Vector3.new(20,0,20)),
	generatePart("Neon",Vector3.new(25,0,25)),
}

for i = 20, 0,-1 do
	print(i)
	wait(1)
end

for _, part in ipairs(partTable) do
	part.BrickColor = BrickColor.new("Medium blue")
	print(string.format(part.Name.."%s %s", "'s brickcolor changed to", part.BrickColor))
end
1 Like