 This one is going to build up a little bit on what we talked about last time. Properties are very useful in implementing another feature, a considerably more advanced feature. Not required for it by any means. There are definitely ways of going about it that rely on other approaches, but this is definitely one of the more common ones. So, what are we talking about? Concurrency and the different approaches to accomplishing concurrency. AIDA uses a single model. Everything has to fit that model. Now, conveniently, that model CSP or communicating sequential processes is a formally defined Calculi. So, considering it is formally defined, you've got a bunch of mathematicians who've worked out how to do a lot of shit in it. That's convenient, definitely. And being said, as you can probably expect, considering we're talking about formally defined academic kind of thing with mathematicians especially. Simple depends on how you look at it. Everything in CSP is done through one concept. The CSP, the communicating sequential process. In AIDA, this is known as a task, but everything is done through that. Everything. This does mean it's simple in that there's one construct you use. Everything fits that construct. But this is where I say it depends on how you look at it. Sure, it's simple in how much things you need to keep track of, but it's not simple in that you have to be aware of how to implement every single thing using that. And only that, because it's the only tool in your box. Similarly, this would be like saying, hey, it's simple to only have one type of hammer and use that to pound in everything. That's true to some extent, but... then you'll have to master different techniques for using the same exact hammer for relatively straightforward things like nails, except it's very handy to have the notch magnet in the hammer for aligning that better. You'll have to come up with how to do a very delicate approach to pounding in materials that will mar, pounding in a dowel. You're probably going to mar and deform that, if not outright split it. Could it be done, potentially? You'll have to come up with an entirely other technique that is radically different in how the force is applied to do things like painting. You start to see the point. It's simple in the way as mathematicians like to be simple, but is it really simple from a practical standpoint? I'm not so sure. I think this is a big failing of that. And this is a huge area where I think .NET gets it right. In the .NET world, you don't have any formally defined calculator. You don't have CSP or anything else. You can still get that if that's what it makes the most sense to work in. Instead, what you have is individual primitives, which you can use on their own for what they're specifically good for, or you can put them together. These primitives, you've got not directly related because it's useful for other things, but the delegate. It is essentially just an access to a function. It's a concept most people understand. A little bit extra going on with the delegate, but part. That's what it is. The extra stuff is strictly going on under the hood. Then you've got the event. This is where properties come into play. Events are a rather simple and straightforward concurrency model. This thing happens. You fire the event. Any attached handlers go and do their thing. Then you go back to normal execution. Depending, those events can then spawn additional threads. Or if your language is set up this way, those event handlers may be run immediately in other threads. Take some time, spawn those threads. Continue on with your regular execution. The event handlers finish up whenever they finish up. Attaching and removing event handlers is typically done through a property-like interface. That's where properties become useful. When you define an event using the specific language syntax, what you get effectively is a backing field of the handlers that are registered. Firing the event, simply going through and calling those handlers. But the whole thing looks immensely simpler than this. Granted, it's not particularly complicated anyways. You might even have created that kind of system on your own. And if it's a single event handler, guaranteed you're only going to call a single event ever, you've probably implemented this already with callbacks. Callbacks are single events. Then we've got another important primitive, tasks. Tasks in the .NET world are very different from tasks in IDA. Although not immensely different. They're not full CSP, but they do still spawn that independent process. Tasks in the .NET world are just a simple type container with its payload. Payload is an independent process to run. Not a whole lot of special there. You can use that for things like thread pools. That's a tasking model in and of itself. You can use them for async and await. Asynchronous functions in .NET are required to return a task or something with a task interface. That's not formally defined through an actual interface vtable, but rather just a specific contract that the compiler looks for. So you can have non-task types that actually provide task functionality and still get asynchronous function out of that. I have to remember that. I completely forgot about that the last time I was working on something. I need to remember that. That's how that works. These videos are useful for me too. You can effectively create a CSP in the .NET world by hooking together a system of event handlers and tasks. Because now you have a sequential process. That's what a task is. That is communicating through events. Although, and I'm not certain, that might actually be the actor model. I'm not super up to date on my formal definitions for these things. That might be actor model. That might not be CSP. The other one that we need to talk about is the use of pipes. Now, pipes come in two-formed, named and anonymous. Anonymous pipes can only be used for communicating inside of your own system. Named pipes can potentially be used to communicate across network boundaries. That is pretty significant because that is how we get into distributed computing, which is also a form of concurrent programming. But this isn't going to delve into specific nuances between each of those. We're just going to be talking about pipes. Pipes open up a channel between two processes so that those two processes can communicate with each other. This can potentially mean two completely independent programs that were written that really have very little to do with each other other than sharing that pipe that they communicate through. Hey, you guy. Now, pipes, of course, can be used to communicate between different threads within the same process, but they're a little more powerful than events, obviously enough. That's the other way we can do a full-edit-task kind of thing. By using pipes instead of events, you now have another sequential process that has a different method of communicating. That different method poses its own semantics, and that's why I can't remember which one's CSP and which one's actor model, but that's another approach. There's yet even more approaches that you can create in that there's things like the observer pattern, which can be used for concurrent programming as well, although not necessarily, that is based, at least in the .NET world, on a contract between two interfaces, Iobservable and Iobserver. You may notice the level of sophistication that exists in the .NET world as far as these things go. You have a bunch of individual primitives, each of which is very simple but very limited in scope, that you can combine in the exact way you need. In ADDA, you get one model for everything, and you have no choice. Let's say you need events, because events happen to be the exact ideal model for what you're doing. How do you get them, ADDA? Well, you have to take an ADDA task and specifically write it as an event handler, because ADDA wants everything very strictly constrained. This means you have to write a unique task type for each event type. You're now doing a lot of code, whereas in the .NET world, you write a delegate for the contract that your event handlers have to have. You write your event. Both of those are single lines of code, just declarations, no execution stuff actually happening. Then boom, you have your events. Attach your handlers, you're good. Simple as that. A clear winner here. While some people will like to bring up the fact that through the, what is it called, it's been so long, distributed systems annex. The part of the ADDA reference manual that dictates how distributed systems are written. Because that's part of the formal standard, you can rather easily write distributed programs in ADDA. This includes distributed tasks. Yeah, that's useful. But, but, it's not like that's unique. Again, remember the whole thing about pipes. Named pipes can communicate across network boundaries. I would much rather work in an environment where each type has an obvious purpose. Following good guidelines for programming. Solid, you know, even if you're not an object-oriented programmer or not working strictly with an object-oriented thing, some of those principles are still very obviously beneficial. Single responsibility, the first part of solid. The task objects in CSP don't have a single responsibility. The individual primitives in the .NET world do have single responsibilities. This makes them much easier to understand, much easier to reason about, and you can compose the functionality you need, exactly as you need it. Now this being said, I don't want to completely shit on ADDA. Tasks are remarkably good for what they are meant for. If I were working in a system where CSP is the single best approach for addressing the problem space that I have, I would rather have IDA task types. The reason for this is that what these CSP tasks are is essentially modeling of independent components using embedded programming as an example. Let's say we have a microprocessor attached to... Well, that's controlling a mill. So you need... I mean, you can get creative, but let's go simple and say that you need three total motors. One motor? Four total motors? Maybe four. You can simplify the hell out of this, but we're trying to show an example dealing with programming, not good engineering design. So you have one controlling the x-axis, one controlling the y-axis, one controlling the z-axis, and one controlling the actual milling bit. So yes, four. Assuming you have no idea how to multi-purpose a motor. Each of those, using CSP, would be represented as an independent task, and they would communicate with each other about things like whether they were spinning or not, if that's something that needs to be communicated. Depending on exactly what kind of mill we're talking about, you may not want to actually move the bit. Move the... Yeah, you may not want to move the bit around while it's spinning. You may want to, but again, that entirely depends on the type of mill you've got, that's something that matters. You may want to communicate that. Something that may matter, you may want to communicate that rather. By representing each of those as tasks, you have unique objects to represent each motor. Each of those encapsulates specific values about it, say specific pins, specific specifications, whatever. For this, you can add a task type and instantiate four of these. One for the actual mill bit, and three for the positional motors. If they're unique enough components, you may not do a task type and just do a single task instance, but either way, you have the facilities there. Each of those represents not just the individual process, but the individual component. That's significant. Now, if you had watched the very first part of this series, and I certainly hope you did, you don't have to watch everything in order, but you definitely have watched that before this. You know what I feel about AIDA, that it is very clearly and obviously specialized for embedded programming. It makes sense. It's quite literally what it was designed for. Now, think about this. AIDA's tasking model is very specialized for embedded programming. They're right down to the point of being ideal to representing the individual components that hardware is controlling, that the software is controlling. I think a lot of people would have a much easier time understanding what AIDA tasks are and what they're not. It was described in terms of that, not indescribed in terms of the remarkably abstract things that they tend to teach when you're studying process calculi. Describing these as terms of three shoppers that are going around and doing their shopping and eventually rendezvous back together is less than ideal. But describing them in terms of controlling the individual hardware components that a microprocessor is hooked up to becomes pretty damn easy to reason about, because that's also what the language specializes in and is what most AIDA programmers would be programming with. There's clear winners here. Winners. I've only talked about two languages, so that means both of them win out. In general programming, however, the way .NET approaches this is very much the clear winner for the majority of programmers. The approach .NET takes of individual primitives that can be composed. That's what you really want. So tell the next video. Have a good one, guys. Bye.