Introduction
: and . are both forms of syntactic sugar. Syntactic sugar are pretty much just syntax features which makes writing code more concise and quicker.
. Notation
The . operator allows us to index a table with a valid identifier. This means that the field we want to index must also be a legal variable name, here's an example:
local tab = {
foo = "bar"
}
print(tab.foo)
This indexes tab for foo, and we can also omit the square brackets [] when declaring our key because foo can be used as a variable name, hence its a legal identifier.
print(tab.foo)
is analogous with
print(tab["foo"])
: Notation
The : operator allows us to call a member function of a userdatum/table. A member function is essentially just a function that's a member or element of an object (table/userdata). You can only use : on a member function, hence why you can't index a data member or regular attribute with : since they're not functions. This is why you can't do workspace:Baseplate, because Baseplate is a userdatum not a method.
Sample use
local tab = {}
function tab:foo()
end
tab:foo()
This function definition also makes use of syntax sugar (which we'll cover later). : implicitly passes self as it's first argument, and if it's used in a function definition, the first parameter is implicitly set to self. self is just a reference to the object we're calling the method on.
function tab.foo(self)
print(self)
end
is analogous with
function tab:foo()
print(self)
end
notice how in the second example we don't need to include self in the function signature.
Likewise:
tab.foo(tab)
is the same as
tab:foo()
and we don't need to include self in our argument list.
Function Declaration Sugar
You've probably used this form of sugar before when defining functions. Functions aren't inherently variables, they're a data type. Specifically they're actually "objects" or reference types, just like tables, userdata, strings and threads. Here's an example of it in use:
local function foo()
end
is the same as
local foo
foo = function()
end
Note that foo is just a variable with a reference to a function. We forward declare foo since if we did this:
local foo = function()
end
we wouldn't be able to make a recursive call, since the variable foo hasn't been defined yet.
Table Field Declaration Sugar
When we define a field/key thats a valid identifier, we can omit the square brackets when we define the key value pair, example:
local tab = {
["foo"] = "bar"
}
is the same as
local tab = {
foo = bar
}
Similar to using the . operator, we can't omit the square brackets if the key isn't a valid identifier (starts with a number, uses characters that aren't part of the input locale, etc).
5 comments
You don't actually need any new lines in Lua, and some people are just used to other languages where a semicolon at the end of statements is required
Check the manual or Programming in Lua
I know the how I want to know the why and the whats best
You don't know the how, that's why you should read one of them. a:b(c) == a.b(a, c) and function a:b(c) end == function a(self, c) end.
Most of these are syntactic sugar.