I can get it working fine with no parameters (the equivalent of Messenger.Broadcast(“prop collected”)) but once those <> get involved I start getting errors. What exactly am I supposed to put there? It looks like it’s Messenger.Broadcast<Parameter type> , but then in the AddListener example:
… what does “Prop” stand for? Prop seems to be the name of the script the parameter’s coming from, but when I do that in my own code it doesn’t work. My error messages are talking about Callbacks, but I don’t know. Specifically:
Assets/Scripts/Character Scripts/Enemies/Enemy.cs(74,27): error CS0123: A method or delegate `Enemy.OnSound(UnityEngine.Vector3)' parameters do not match delegate `Callback<RollingObject>(RollingObject)' parameters
So how am I supposed to write it? Go easy on me… I’m 100% new to events and all this jazz.
What goes between the < > are one (or more) parameter types. They are the signature of the parameters that will be passed to your registered method. For example:
if your event is passing an int, then you would write
Okay, I got it working, thanks. Their example threw me off because the AddListener had a different type in its arrows.
Another thing, it’s giving errors when I broadcast an event that there are no listeners to. In my case these are sound events, and there were no listeners because I already defeated all the enemies who would be listening. Should I be manually checking that there are still enemies in the scene, or is there another option? The error mentions Messenger.MarkAsPermanent but I’m not sure what exactly that does, the wiki page says it’s used for messages that should survive a cleanup.
BroadcastException: Broadcasting message "sound event" but no listener found. Try marking the message with Messenger.MarkAsPermanent.
if no listener is registered for some event, that exception is thrown.
You’re removing a listener that isn’t added. Make sure not to remove a listener twice in a row, or before adding it.
Hrm, I’m looking over this messenger thing. I actually have something similar I wrote, but I prefer a more object oriented and type safe system. I hate magic strings, they’re hard to keep track of. With mine I call it a ‘Notification’, and each unique Notification type inherits from the Notification class. Any parameters that come with the Notification are members of that class, and all Notifications have a sender. You can register to listen to a specific sender for a notification, or listen globally. When posting notifications you can also have the root notified as well, a root is a parent gameObject tagged to be the base of a group of gameObjects.
Use would be like:
//custom notification
public class LandedNotification : Notification
{
public Vector3 GroundNormal;
}
...
//registering listener
Notification.RegisterObserver<LandedNotification>(gameObjectObserving, OnLandedNotification);
...
//listender
public void OnLandedNotification(LandedNotification n)
{
//do stuff on landed
}
...
//dispatching
var n = new LandedNotification();
n.GroundNormal = grndNormal;
Notification.PostNotification<LandedNotification>(this, n);
I don’t use that Messenger framework, but I’m pretty sure there is a flag that starts with “DONT_REQUIRE_…” that you include in the Broadcast call. That flag will do enable a check to see if anything is listening for that event in the framework.
The Messenger.MarkAsPermanent is specific to Advanced CSharp Messenger. Since that framework clears out the listeners on a scene load, you need to mark any events that can’t be cleared by using that flag. For example if you have a GameObject that has DontDestroyOnLoad set, you need to mark any event listeners on that GameObject with the MarkAsPermanent flag or else on a scene load it loses the listener and (probably) won’t call the code to re-listen.
Those Messenger frameworks are type safe, but yes they all use magic strings. If you don’t want magic strings, you can use a public static Events class with public const strings. You can either add to that manually, or have a script that scans through and removes them.
Currently I’m tinkering with a Sublime Text plugin where I highlight one of the string events, press a key combo and have the editor check if the string exists then add it the Events class then replace the highlighted string with the new Events.blahblah const string. One could probably write a Monodevelop plugin to do the same thing.
You contradicted yourself right there. My point by saying type safe, is that I don’t like magic strings, because magic strings aren’t type safe.
Example… the .Net event system uses a special delegate type to define the event. The event becomes a member of the object that dispatches the event. The event itself is type safe and is not represented by a magic string.
Public const strings are STILL magic strings. All you’ve done is create a constant for it. Which when I have to use strings, I do.
And if I want an event system that is type safe, and isn’t the .net/mono event system, I can roll my own. Which I did. Which was the point of my post.
Because the system uses generics to define the parameters of the event handler doesn’t necessarily make it type safe. Example… when you go add the listener to the messaging system, can it test if your delegate matches the required parameters? No, it does not, because it doesn’t have any information about the event and what it is shaped like. Where as in my system, all events are defined by a class definition, which specifically describes the shape of the event. This way, I can ensure at compile time that any notification listener attached is shaped appropriately and will receive the message with out error (the body of the handler can still throw an error of course). That’s what type safety is.
String based keys lead to fragility and a high maintenance burden. If you look at mature, productive frameworks outside of the gaming industry, nobody purposefully uses Strings for hooking things up anymore.
Strings are obviously better than directly using method names as keys (!), but that’s like saying pushing a car with a dead battery is better than pushing a car with a dead battery and four flat tires.
Edit: To continue the analogy, waiting until runtime to perform necessary type checks would be like pushing the aforementioned car with no brakes or steering.
@lordofduct
Again, type safety doesn’t not mean compile time type checking. With those Messenger frameworks you can not pass an instance of TypeA to an event that takes a TypeB. I can only use the variable passed to me as a TypeB. The fact that this check is done at runtime does not mean it is not type safe. That is all I’m saying.
@SmoothP
Having spent many years working with dynamic strongly typed languages (ie lots of Python, lots of Groovy, some Javascript, pinch of Ruby) I find working with statically typed languages to be a chore. With all the unit testing frameworks, compile time checking really just gets in the way. Give me duck typing or give me death!
As an aside, python’s class implementation are just dictionaries. One instance dictionary for instance attributes and methods, one class dictionary for class attributes and methods.
But we’re starting to swerve into Holy War™ territory and it has nothing to do with the OP’s question, nor Unity in general.
bigdaddy - there is type safety from the generics of passing in parameters. I get that. I understand. You don’t have repeat yourself.
That’s not what I was talking about. I was talking about the lack of type safety by using magic strings in place of strongly typed objects to identify the signature of a message/notification/event.
Furthermore that type safety really is just being used to tether the parameter signature to a message name. And it’s poorly implemented… specifically, looking at the ‘AddListener(…)’ method, if I did:
well… an exception would throw up because the first delegate passed in wouldn’t have the same signature, so when we combined the second, mono would throw an exception.
Really… I wouldn’t consider this much for type safe. I’d say it’s using mechanisms in C# that allow to write type safe code, and abusing them.
And I’m not sure your point in this sentence:
Well, if we assume you meant the double negative, the again is false, because you’re changing your previous statement, and repeating me.
Or I can assume you mistyped the double negative, in which case, YES compile time type checking is a kind of type safety!
This isn’t holy war territory, this is you not understanding the words being typed by us, so you just declare you’re correct.
Your argument seems to be that because 1 of its parts uses what you consider to be type safe mechanisms. That despite all the other parts that aren’t type safe, we can call the whole thing type safe.
Where as I’m saying, I don’t care about the whole, I care about type safety in the message/notification signature. And I want that part to be type safe. And I created my own notification system that grants that.
There are two places to check and enforce type safety that I am aware of: compile time (static type checking) and run time (dynamic type checking).
Statically typed languages (Ada, Pascal, Java, C#, etc) do use static type checking to check for type safety. However, any language that has type casting, whether explicit or implicit, cannot rely nor guarantee type safety via static type checking.
For example:
IEnumerable transforms = new Vector3[] {Vector3.zero, Vector3.one, Vector3.up};
foreach (Transform x in transforms) {
Debug.Log("X position is "+x.position);
}
That code will compile. That code passes static type checking. But is it type safe? If that was all the checking done, then no it is not type safe.
But to really find the answer, we need to look at run time type checking.
Dynamically typed languages (Python, Groovy, Ruby, Objective-C(?)) and statically typed languages (Java, C#) use run time type checking to enforce type safety. Here at run time the reference to a given type is checked that it is being accessed in an allowable way as that type (or that type can, at this point in time, allow access in that way).
Running the code in the example above will, in fact, give us an InvalidCastException, ergo that code in C# is type safe.
This is all I am saying when I say code is type safe.
Static type checking can provide benefits unrelated to the above stated definition type safety. You may catch typos/goofs at compile time. You may be more explicit in code intention. The compiler may be able to do certain optimizations. These are all good things. But it doesn’t guarantee type safety.
[sic: presumed mistype with the double negative because otherwise the sentence doesn’t make sense in its context as explained earlier… otherwise, these two statements are direct example of you changing your position]
now you say:
I said:
What’s that again? Oh… you’re demonstrating you were wrong by changing your statement and pretending you were right all along by saying what I said.
My entire claim is that yes there are various ways to enforce type safety. And I don’t like this messenger system because it lacks a type contract for the various message/notification typest. This system lacks that as it uses magic strings to represent the message/event/notification types. I prefer a method that has a type that defines each message/event/notification. Just like how delegates (a type) are used by .net/mono event system, or classes are used by my notification system.
As you can see in my explanation:
Note I said “more”, and I was referring to both object oriented and type safety.
I don’t know why you’re going on about what is and isn’t type safe, changing your position each time, and basically ending by AGREEING with what I said the entire time. All to argue against what? That I prefer NOT to use magic strings?
The first sentence is very true… It takes care by the developer to make sure you don’t have any problems. However, implementing good standards can help with this, such as requiring all of the keys to be stored in global constants making them easy to change down the road as they are only changed in one place.
As for the second sentence, this is not always the case. Sometimes you have to choose between ease of use and robustness. I actually have my own message bus system that I’m in the process of rewriting, but it has some similar semantics. It uses strings as message keys. The reason for this decision was how it was used… it maintains an internal pool of message contracts. At the top level it has objects based on type so it’s a essentially:
Dictionary<Type, Subscriptions>
Then Subscriptions has a Dictionary<string, SubsriberList>
So, the messages are filtered by Type, then by key… this allows multiple message types to have the same key. For example, you can have a Vector3 type with a key of “SomeEvent” and you can also have a DateTime event with a key of “SomeEvent”… Every subscriber has a typed “Subscription” or in the case of GameObjects can have a receiver and it uses an event system to handle incoming messages.
This is vastly oversimplified as it’s more configurable and allows messages to be pruned, delivered immediately, delievered on fixed / late update (in the case of the receivers), and have a max number of messages stored at a given time. I’m rewriting to implement custom collections because iterating the dictionaries allocates.
Now, I could have allowed the message key to be any type as well… but here’s a difference when I talk about ease of use… If I want to subscribe to a message now I say:
If those particular pools don’t exist, it creates them and wires up the subscriptions (and also uses WeakReferences to allow cleanup and no hanging references).
If I wanted the “key” to be type save, I would have to do something more along the lines of:
While this is perfectly acceptable, it does create a bit more difficulty in implementation. Personally I prefer not to use the magic strings but sometimes it’s easier for end users to digest.
And on one final note, as to your last sentence… If you actually start doing a lot of work outside of the gaming industry you’ll find lots of mature libraries using magic strings for things… For example, Microsoft’s own MVVM property change notification (INotifyPropertyChanged, etc.) which uses a string version of the method name… I don’t like it, but it is what it is. Also, libraries like PetaPoco that use magic strings in attributes, etc. And anything that needs to access a connection string by key (especially with tools such as Entity Framework).
People coming from dynamic language backgrounds tend not to have the same revulsion of strings that people who come from java/c# have.
At the end of the day, once you lose compile time checking, using string identifiers almost makes no difference. It’s worth looking at backbone - one of the most popular javascript libraries, which uses string based property keys for literally everything (but js is a mess of a language, so…).
With regard the type safety argument. I think that ‘type safety’ isn’t actually as well defined as perhaps we’d like it to be. Type safety is not so much a binary as a gradient. The lowest form of type safety is memory safety: basically preventing unbounded reads from memory. The highest form is probably static strong typing.
Despite programming being a very precise practice, a lot of the terminology we use is far less precise than we’d like. The huge range of environments, languages, and approaches used means that the terminology we use tends to evolve. MVC is another great example, with the original implementation being very very different from what many programmers now consider mvc.
At the end of the day, invoking a method by string name is the least type safe operation one can perform in C#. If one considers it ‘type safe’ or not is in all honesty, somewhat subjective - although I would tend to give the argument to Big - in that I consider memory safe to be the minimal requirement for type safety.
I get an error: “BroadcastException: Broadcasting message “test” but no listener found.”
Has the listener to be inside the same class? If yes, then i do not see any reason using a eventlistener…
please help.