Instance access restrictions [rewrite]

Rewriting this with a new structure that will hopefully help people better understand what it suggests.

This is a feature request to introduce access modifiers to Roblox at the engine level.

What is an access modifier?

Access modifiers are a feature of many programming languages, such as C#, and many game engines, such as Unreal. An access modifier allows developers to restrict the access of certain content, such as reading a value of an object, to a certain context, such as a particular object or file.

Why are access modifiers useful?

Access modifiers catch bugs fast and early. Consider a custom NPC object that has a best friend for life, and an NPC’s best friend will only change if the NPC wants it to. Now, another script wants to know that NPC’s best friend, but how should it be exposed? There are two main options, both with significant issues:

Option 1: Use the instance hierarchy

You can expose the Best Friend through an ObjectValue or some similar interface. By doing this you expose an easy access point for reading the value, but you also incidentally expose a setter in the form of NPC.BestFriend.Value = x. If anything were to set this value, it would create unexpected behavior that may be difficult to track down.

Option 2: Use a lua structure

You can expose the Best Friend through a lua-based interface like a ModuleScript or a BindableFunction. By doing this you can enforce that nothing external can set the value, but now you have to set up an internal setter, a custom changed signal, and custom replication. You end up spending an inordinate amount of time and energy on constructing, maintaining, and onboarding for this system.

Option 3: Use access modifiers

In an ideal world, you can use access modifiers for this. Simply set up an ObjectValue like in Option 1, and then restrict its Value property to only be settable from within the NPC. You have your external getter, you have free replication, you have a free changed signal, and you have an internal setter, all in only two steps.

User Stories

As the owner of a particular segment of code, you’ll want to set access specifiers to assist your team in using your feature.

As a team lead, you’ll want to use access modifiers to help your team write the right code in the right place.

As a junior developer, you’ll want access modifiers to exist in the code you’re working on so that you can instantly know what APIs you should be using.

As quality assurance, you’ll want access modifiers to throw verbose errors to assist you in assigning bugs to the relevant programmers.

Interface Proposal

I propose that access can be modified for the following content:

  • Any access to a specific instance
  • Any write to a specific property on an instance
  • Any call to a specific function on an instance

And each case should be attached to a context composed of:

  • Which scripts should be affected by the modifier
  • Whether the server, the client, or both should be affected by the modifier

Whenever a script tries to perform a restricted action, an error should be thrown that explains what happened and why it wasn’t allowed.

9 Likes

Access modifiers at the engine API level will definitely be useful.

Access modifiers in terms of catching bugs at the scripting level has been made redundant thanks to metatables and the implementation of type annotations. You can use proxies to discriminate read/write requests. You can use type annotations to declare the types of variables, formal parameters, and table structures and the IDE will warn you (not error) of potential violations. If you want runtime readonly tables, there’s the table.freeze function. But about the concept of constant variables, it’s a no for now:

1 Like

God forbid you document your own code to relay such information.

It’s almost like documentation is intended to solve this exact problem.

1 Like

Comments aren’t a substitute for encapsulation. This is a pretty standard feature.