Why "?" or ":" following arguments?

  1. **What do you want to achieve?
    Would someone mind explaining the differentiation and usage of using “?” and/or “:” in the arguments of functions and such

  2. What is the issue?
    A lot of advanced scripts I see use them.

3 Likes

Pretext

You’re not seeing this appear in function arguments, but the parameters of the function signature and the function signature itself. If you were not already aware, Lua is by default a duck-typed language. This means the interpreter largely determines what datatype the values you’re working with really are, not you. It does this through the following reasoning: “If it walks like a duck and it quacks like a duck, then it must be a duck”. Luau, however, was fitted with a gradual typing system that allows developers to specify datatypes in an otherwise duck-typed language. This is achieved through inference and annotation

Annotation

What you’re describing in your post is type annotation. The colon is how we set a type, similar to how = is used to set a value. The question mark is a type modifier that allows us to shorthand the following annotation “type | nil”, meaning something is either that type or nothing at all. It appears as “type?”.

Why

At some point, yourself, or someone, will make a mistake with yours or Roblox’s API. Luau still lacks real type enforcement, and some of these mistakes can go unnoticed with potential polymorphic relationships with the faulty data and the code. These mistakes can cause deep-rooted bugs which are difficult and tedious to resolve. Typechecking can catch this nature of mistake before you even hit play. Even if the mistakes are trivial, it still saves you and others time. The annotations used can also enable extremely powerful technologies like IntelliSense (auto-completion). Annotations can help say more with less code and comments, which is very powerful in team and solo contexts

1 Like

Things are used to help tell the developer what they can expect from x function.

for example:


local function foo(bar: string): string | nil
   if type(bar) ~= "string" then print("Bad type") end
  return bar
end

print(foo("test"))
print(foo(123))

This tells us in our IDE/editor that the foo function will return only a string and takes one argument which is of string type.

Within the function were type checking the input to make sure it is truly a string and to prevent unintentional issues.

1 Like

The ? can also be used as a typecast or check that isn’t guaranteed. If you use !strict lua environment at the top of your scripts it will help you understand why it comes in handy, especially if you typecheck consistently. The " : " is used as a typecasting/checking variable. If you already reference something like: local Remote = ReplicatedStorage.Remotes:FindFirstChild(“RemoteName”) and use two " : " 's it will be used to type cast to the object and use the properties for intellisense in studio to help autocomplete lines.

1 Like

Your question regarding the “?” type modifier was already answered, though it looks like the one about the “.” hasn’t been. I think that you were refering to the three dots (“…”). Explaining it briefly, it represents a number of arguments passed to the function. For example, let’s suppose you have a function AddNumbers() and you want to make it possible that you pass a large amount of numbers and an addition should happen between all numbers, but you don’t want to make a reference variable for each argument (which would be very confusing).

Instead of:

local function AddNumbers(number1, number2, number3, number4, number5)
    return number1 + number2 + number3 + number4 + number5
end

You can do:

local function AddNumbers(...)
   local passedNumbers = {...}
   local value = 0
   for _, number in passedNumbers do
      value += number
   end
   return value
end

print(AddNumbers(1, 2, 3, 4, 5))

This would print “15” in the output and you could pass an infinite (?) amount of numbers as an argument to the function and it would do the operation normally without you needing to change your code every time you want to support a new argument.

One case in which the three dots are very useful are for client effects. Usually we use a RemoteEvent or UnrealiableRemoteEvent to fire client effects events to the client so it would do them, but for some effects we need to pass different arguments and different amount of arguments to the event in order for the effect to happen. For example, event x could need a character and a part, while event y could need a color and a number.

In this situation, you could have this:

RemoteEvent.OnClientEvent:Connect(function(eventName: string, ...)
    local args = {...}

    -- And finally, you can make variables to reference to different possible
    -- arguments according to each event name. For example:
    -- local character = args{1} (the first argument passed to the function
    -- after eventName).
end)
1 Like

I think you mistook the colon for a period in OP’s title

1 Like

The ? and . have no use in the arguments of function, both would be syntax errors.

Thank you everyone for the replies. The annotations make much more sense now. :))

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.