Add Connect, Wait, and other shortcut methods to RemoteEvent and BindableEvent objects

If you want to connect to a RemoteEvent object, you have to connect to its OnServerEvent or OnClientEvent properties instead. Setting aside that these are two of the most badly named properties in the entire engine, it’s strange in the first place that this is necessary.

I ought to be able to call Connect directly on a RemoteEvent object and have the engine suss out whether or not it is running in the Server or Client context. Same goes for all other relevant functions that real Event objects have, such as Wait.

BindableEvent has a similar problem. It has the Fire method, but to connect to it, you don’t call Connect – you call Connect on its Event property. I feel I am justified in saying that event:Connect is better than event.Event:Connect without further explanation.

This change would be easy to implement, incur only a minor maintenance cost (how often do you add functions to the internal Event object?), dramatically improve code cleanliness and intuitiveness, and smooth out the learning curve of Roblox’s API (this quirk is a severe gotch’a).

14 Likes

Support. As someone who’s been programming for quite some time on Roblox, even I forget sometimes that it’s not the remote itself I connect to, but its event property. This would also make explaining things easier to less experienced scripters.

My one small caveat is that this might make ModuleScripts that deal with server and client network functions a bit vaguer at first glance. Still, I think it’d be reasonable to assume that if this were implemented, Roblox would maintain backward compatibility with OnServerEvent and OnClientEvent allowing programmers to use either of those for code clarity if required.

This is intentional because it’s consistent.

There is no Instance:ConnectChildAdded(), nor is there an Instance:ConnectAnything(). This applies to every instance connection. They’re named because they’re properties, and it’s not really hurting anyone to write OnClientEvent or OnServerEvent.

The real kicker here is that OnServerEvent has a Player parameter. How do you suggest circumventing that?

4 Likes

None of the objects you mentioned exist specifically to facilitate callback execution the way that RemoteEvent and BindableEvent do. They ought to act as stand-ins for events, not containers. The comparison is inappropriate.

As for the OnServerEvent “having a Player parameter,” I have no idea what you’re talking about. If I’m calling Connect on the server, on a server script, with server code, I’ll give it a callback that accepts Player. If I’m calling Connect on the client, on a client script, with client code, I won’t. What exactly is the hang-up, there? In what universe are you going to be using the exact same remote signal processing function on both the client and server?

Thanks for your support.

In response to your caveat about ModuleScripts: if you’re writing a module to be client-server agnostic, then it shouldn’t interact with Remote* objects at all, ideally. If it does, you can branch internally. However, I’ve yet to meet a case that I didn’t think was better solved by abstracting the shared functionality elsewhere and leaving any client- or server-specific code to consume it.

1 Like

This would likely cause some issues with both documentation and likely maintenance issues, :Connect is a function of RBXScriptSignal, by allowing a connect to occur directly on the RemoteEvent, you are making the RemoteEvent a RBXScriptSignal which physically cannot happen. Not only is it not backwards compatible but it also becomes a nightmare on the stance of the object itself. Is it just a RBXScriptSignal, can I still call :Fire on it, will I get a permant memory leak if I connect to it since the RBXScriptSignal is never removed?

However, let’s just say you decide to make :Connect (and all other related RBXScriptSignal properties and functions) part of RemoteEvent instead, that would look incredibly confusing to some developers who now see that they can apparently call connect on the object itself? This will also likely become a maintenance issue as RBXScriptSignal would technically be a seperate instance to the Connect events on RemoteEvents so if a bug occurs with one of them, the other one would likely have to be fixed separately.

Currently the type-checker in Studio (which also suggests you properties and events based on the likely return type, which in this case the first return would be Player?) does not account for client / server run context (or at least to the extent of changing an entire return type) iirc.

4 Likes

Your argument about the type-checker is a good point, and one I don’t have an answer for.

As for the first part, I’m not sure the things you’re talking about would happen. I am merely suggesting the addition of shortcut methods. The internal functionality would remain unchanged. Essentially, I’m just saying that the engine should intelligently determine if its on the client or server and return a connection from its signal objects.

I could write this in Lua.

local function SmartConnect(remote, callback)
  if RunService:IsServer()
    return remote.OnServerEvent:Connect(callback)
  else
    return remote.OnClientEvent:Connect(callback)
  end
end

Surely you would not suggest that this function as I’ve written it would cause something as dramatic as a memory leak. I’m suggesting merely that this function should exist on the C++ side.

Also, I see no reason why these objects could not or should not be made to implement the same interface as that which RBXScriptSignal objects do. Is that any more confusing to document or understand than inheritance, which is already so ubiquitous in Roblox’s API?

if the function MessagingService:SubscribeAsync literally acts like if you were calling Connect on a RBXScriptSignal which returns to you an RBXScriptConnection. I don’t see a problem with it in my opinion, as many people claimed to be in this post. (The ones replying to the owner of it)

if the event ValueBase.Changed was totally modified to only trigger when the property value changes and not all properties (this is really old and not new), which can cause confusion and “would likely cause some issues with documentation”. It just wasn’t taken into consideration that it could cause confusion knowing that its behavior differs from all the other Instances.


That said, though I like to follow patterns, I believe having those shortcuts will really be great since when we create BindableEvents and RemoteEvents we are kinda expecting something like RbxScriptSignal if you get what I mean. Most of the time you will always be accessing that Event property and calling Connect or Wait.

You will rarely be checking any other property on BindableEvents and RemoteEvents. (From my experience I have never found the occasion where I would access any other property)


This is just my opinion on the feature and it doesn’t mean it’s the right decision, thank you. (Don’t want to get attacked back)

Do not deprecate the Event property however, if Roblox decides to make this addition.

1 Like

I understand the convenience of being able to hook onto the connection directly, but there’s a reason it’s laid out as it is, and that’s consistency.

Direct method calls are for something you want to do to an instance Destroy, SubscribeAsync, Clone, etc.. On the other hand, indexing to get to a method is for receiving something from the instance, such as properties, Changed, ChildAdded, etc.. In other words, one is a method, one is an event.

A RBXScriptSignal is a class, and unless I’m wrong, means that you’d have to either create a new class each time, copy and paste the same code for a new method, or use a dirty workaround to directly create the connection. There are many supported functionalities of this class:

  • Connect
  • ConnectParallel
  • Once
  • Wait

This means that with each remote, you’d have to create a method to replace each one of these methods. This will cause confusion as a remote isn’t a RBXScriptSignal nor does it inherit from it.

cc: @focasds @Davidii

2 Likes

I mentioned SubscribeAsync because is kinda like a shortcut to me, in my mind, if it were to be a lua version it would be something like:

function MessagingService:SubscribeAsync(Topic, Callback)
      local Bindable = Instance.new("BindableEvent")
      --- Some code here that will trigger the event ---
      --- If there are no Connections in the Bindable it will unsubscribe (no way to detect that from our end however) ---
      return Bindable:Connect(Callback)
end

That’s how I imagine it (if it were to be in Lua), of course is nothing like that, but you know what I mean. That’s why I mentioned it, is out of the ordinary per say.


Shouldn’t telling the user that those are shortcuts functions be fine? Also can’t Roblox automatically assign functions to an Instance and make those automatically do a wrapper for us, similar to when we use self? (I understand they are using either C or C++, but I am just wondering since I see function calls that edit properties of an Instance)

Lua Code: (They could achieve something like this in my opinion, of course it won’t be in Lua)

function Instance:Connect(Callback)
     return self.Event:Connect(Callback)
end

I do agree with the fact that a RBXScriptSignal contain many methods and who knows how many others can be added later on the in the future, which means every time something new is added they will have to create a function for the new method too to wrap it.


Other:

Unrelated, I found something really weird when testing if the functions of an RbxScriptSignal are equal to functions of another RbxScriptSignal and the result was false. I wonder what Roblox does in the back that they cannot have equal functions. (Some objects are not even being reused, like Color3)

1 Like

SubscribeAsync is not a shortcut. It’s a direct method to MessagingService. This is similar to GetAttributeChangedSignal. It’s not a shortcut, but a built in method for the instance.

This is very hacky. You’re making a new connection instance each time. There’s no point of making a shortcut for a single index.

This isn’t good design. It’s like saying a sign that’s a small octagon is also a stop sign. It’s simpler, but it will cause confusion. There is no point of overcomplicating something already simple.

Again, what’s the point? You’re going to have to add even more code depending on client or server context, and for each of those you’re running a unique event (one with and without player argument).

This is a big no-no. If something can be achieved without, there really isn’t a reason not to keep it that way.

You’re not understanding how these events work. You’re creating a new RBXScriptConnection if you call a method from RBXScriptSignal. This is how you can get unique connections (which means disconnecting one won’t disconnect all of them). The RBXScriptSignal itself is congruent.

local Part = Instance.new("Part")
print(Part.Changed == Part.Changed) --> true

You also don’t understand the concept of userdata. Color3 is a userdata. No two userdata is the same, despite having the same values. Two empty tables, despite having the same content, is not equal.

Based on your blind allegiance to wrong information, appeals to opinion, and general condescension, I can only conclude that you’re arguing in bad faith, presumably because you have a contrarian personality.

Your insistence that a “new connection instance” is made each time is nonsense – a remote object has a signal internally. A theoretical RemoteEvent:Connect would create no more or less data than the existing RemoteEvent.OnServerEvent:Connect.

This API suggestion is to make things more simple. I ought to be able to think about these objects as events in and of themselves, not containers that hold events. The design of the object is literally to act as an event for the game in the same way that Touched acts as an event for a BasePart object. From my perspective, the fact that these objects don’t work this way makes them inconsistent.

Just because something can be achieved without a new feature doesn’t invalidate the feature. Following that line of reasoning, game engines, high-level programming langauges, and, hell, even microchip factories wouldn’t have been made. Convenience is worthy, and again, I can only conclude that you are resistant to it because it makes you feel superior to be content doing annoying things that others would rather do without.

1 Like

Hooking a RemoteEvent is an extreme pain sometimes, especially with laggy clients.

Adding to the functionalities of RemoteEvents, by implicating RbxScriptSignals, we’d would probably help traffic the flow of data for future games, it almost seems paramount this becomes a feature!!

I am basing my view on having a method Connect on the Bindable and Remote. Since SubscribeAsync returns directly a RbxScriptConnection instead of an RbxScriptSignal to connect to. No other function does that as I know in Roblox (I am not saying this function is an issue, I am just using it as a support).


This is why the owner of this post requested those functions. That way you wouldn’t need to do:

-- Server:
RemoteEvent.OnServerEvent:Connect()
-- Client:
RemoteEvent.OnClientEvent:Connect()

-- Feature Requested:
RemoteEvent:Connect() --> The engine automatically assumes which to connect to.

I have made myself a similar object to a BindableEvent using Lua. All my connections have a metatable which’s index has functions like Connect, Wait, and Once. Since I am using self and the data stored in it, I am able to know where to disconnect and connect. (Everything can be achieved on their side or are you forgetting that Lua’s interpreter is literally written in C)


Unrelated: (Staff don't need to read this)

I think you totally misunderstood me, look at this: (Vector3 is now considered an official type in Luau though “vector”, don’t know if that has an impact)

They are not re-using those objects like they do for Vector3, noting that those objects cannot even mutate at all.

If you want an optimisation here, why not store the value of IsServer in a variable so you can use it again, it wont change unless a script can magically teleport over VM boundaries (which it cant)

If you want a hyper optimisation thats probably hacky, do this

local IsServer = RunService:IsServer()
local e = if IsServer then remote.OnServerEvent else remote.OnClientEvent

I will agree this supports a single-remote workflow, however my networking library does this and it provides a performance gain (and anyway, scraping out an if branch is a micro-optimisation)

As for Wait, it yields for at least one tick anyway so whats the gain here?

No. It will be hell porting all my remote stuff to this feature if this ever happened. No way. Two, An RBXeventSignal is useful instead of a :Connect method on all instances as you can diffrenciate all events e.g. child.AncestryChanged, ancestry.ChildAdded. A connect will not seperate those events unless you make it look ugly.

I’m not suggesting the removal of existing things. Roblox never does that anyway.