Un-deprecate Players.NumPlayers

For some reason the Players.NumPlayers property is deprecated in favor of #Players:GetPlayers(). However, if all I care about is the number of players, and not the Player objects themselves, then the recommended method involves a lot of unnecessary overhead behind the scenes:

  • Instantiating a table
  • Populating the table
  • Counting the elements in the table
  • Throwing away the table to the garbage collector

Whereas Players.NumPlayers just returns a simple number. As such, I should be able to use NumPlayers guilt-free without deprecation.

7 Likes
local Players = game:GetService("Players")
local numPlayers = #Players:GetPlayers()

Players.PlayerAdded:Connect(function()
    numPlayers += 1
end)

Players.PlayerRemoving:Connect(function()
    numPlayers -= 1
end)

Now you only need to populate the table once, and then it’s just simple math after that. We don’t need a deprecated property back just for this!

9 Likes

I suppose that’s too inconvenient due to the boilerplate needed, whereas you can just access the NumPlayers property

1 Like

you could do smth like this:

On any Module script…

local module = {
function module.NumPlayers ()
       local finalNumb = 0
       for i,v in game.Players:GetChildren() do
              if v:IsA("Player") then
                     finalNumb += 1
              end
       end
       return finalNumb
end
}
2 Likes

That’s fair. But then again modules exist to store boilerplated data, so you only have to define it once!

2 Likes

this is worse than #players:GetPlayers()

8 Likes

Can someone educate me here: Would there ever be any occasion where Players.NumPlayers ~= #Players:GetPlayers()? Additionally, is there any significant reason to use one over the other otherwise?

I personally can’t see any objective reason to want Players.NumPlayers back, unless it was noticeably faster/more optimised than just looking up the #Players:GetPlayers() table.

bytecode for #:GetPlayers()

GETIMPORT R1 2 [game.Players]
NAMECALL R1 R1 K3 ['GetPlayers']
CALL R1 1 1
LENGTH R0 R1

bytecode for .NumPlayers

GETIMPORT R1 5 [game.Players.NumPlayers]

noticably shorter, but bytecode length isn’t the determining factor here

OP assumed the overhead is NOT negligible, so I benchmarked it:


this benchmark uses #:GetChildren() with 100 mock instances inside Players, and assuming :GetPlayers() is just a filtered version of :GetChildren():

OP is right. But this is exaggerated, to say the least.

3 Likes

I’ve used numplayers over #Players:GetPlayers() and I think deprecating it was very pointless. It should be undeprecated.

Oh yeah and here is the post that requested to Deprecate Players.NumPlayers

4 Likes

That is not any better. You are still creating a temporary table, and instead of reading the count, you are iterating the table. GetPlayers() already filters out non-player instances.

The cost of everything you described is pretty trivial when it comes to players. There is some elbow grease towards a dedicated :CountChildren() method, but the impact of that is noticed at the scale of thousands of instances, not ~200.

If you find that this is a bottleneck, use @avodey’s snippet, but the answer on this is definitely no.

7 Likes

Just because something is deprecated doesn’t mean it isn’t usable. Honestly, just use it.

2 Likes

I am not really asking for a new :CountChildren() method as use-cases would be limited, I am asking to un-deprecate an already existing feature that there is frankly no reason why that should be deprecated.

3 Likes

oh yeah i forgot about #players:GetPlayers(), you could also do

#game.Players:GetChildren()

although im not sure its better

This does make me wonder, just for curiosity’s sake, why is it deprecated? is it just super old code that no longer fits well with other systems? or perhaps it’s just lacking in use cases?

Already answered in:

^ the impact is only noticable for thousands of players, but that isn’t realistic. even 200 players is still pretty minimal impact

^ basically there’s not that big of a performance impact (negligible)

So? I still see no logical reason to deprecate the property.

Well, in Deprecate Players.NumPlayers, the argument is for consistency sake, you can do Players.NumPlayers but not model.NumChildren. And that checking for the number of players is too niche, so the property is just clutter.

Don’t get me wrong, I’m siding with you here. NumPlayers is the epitome of deprecated naming schemes; it doesn’t feel official, and as many have suggested Players.PlayerCount is better. Lately I’ve been seeing a trend where new APIs tend to use more methods than properties (especially if it’s designed for scripts), one example is attributes, it’s basically the same as ValueBase instances but method-based. Players.PlayerCount should be a property, or at the very least a method.

Let’s address the issues proposed:

  • Consistency
    • Players and Model are not the same, Model is just a generic container, while Players is a specialized service. The API already treats Players as a specialized service:
      • LocalPlayer
      • PlayerAdded and PlayerRemoving
      • :GetPlayerByUserId()
      • MaxPlayers and PreferredPlayers
        Even so if consistency leads to worse usability, it’s dogmatic. Consistency should not override clarity and utility.
    • Naturally, as a first-comer, you’d expect the player count to be easy to access. But no, you’d have to learn about the :GetPlayers() method and then figure out how to count how many players are in that list. Simplifying the API by removing “redundancies” just made it more verbose and less accessible
  • Niche use case
    • Really? Does #Keyframe:GetPoses() have enough uses to get its own Keyframe.NumPoses? I think #team:GetPlayers() deserves team.PlayerCount as well though.
1 Like

If you don’t know very basic things like how to fetch the length of a table or even read the documentation of what you are using, then how are you expecting to get anything meaningful at all done?

Unnecessary properties shouldn’t be getting introduced for something that’s already incredibly simple to do just because “oh but a newcomer needs to have their hands held”. That’s what documentation and proper tutorials/guides are for, which Roblox already has plenty of both.

4 Likes

The main reason I like NumPlayers is not because that is easier to type or more beginner friendly, but because that does not incur the performance overhead of constructing a table with all the players.

1 Like