Lecture thumbnail 0:00 / 0:00 Now you’re probably thinking I’m just pulling things out of thin air.

But there is a combination of the proxy and composite design patterns that I want to show you.

And this is a composite proxy which allows you to implement a pattern or a construct which is quite

often called an array of structures, structures of array paradox.

So let me first of all explain why this exists.

And it’s particularly something that’s present in game development, but it will also be relevant to

anyone who is processing any kind of large volumes of structured data.

So let’s consider the game development example.

Let’s suppose you have a game and a game has a large number of creatures which participate in the game.

So each creature might have certain traits, like for example, they might have an age.

So I would have that as a byte and they might also have some sort of position on the game map.

So they might have a X and Y coordinates, for example, and maybe they have something else.

Now, this data structure, this class, as you can see, I’m using a byte here, so that would be a

single byte and this would be typically four bytes.

It’s somewhat uneven structure.

We don’t really know exactly how it’s going to be stored.

Maybe what comes after the byte will be padded so that it fits into the word size of the CPU.

Who knows?

So we have this creature.

Let’s suppose that we have, let’s say 100 creatures participating in the game.

So you might do something like the following.

You might have an array of creatures equals new creature 100.

Now obviously you would initialize each of the creatures.

I’m going to sort of skip that part.

But then what you might want to do is you might want to take, for example, every single creature and

increase their x coordinate.

So move them all to the right by one cell or whatever.

So you would write something like the following for each var C in creatures and you would say C dot

x plus plus.

This code looks very innocent.

It looks very well.

It’s correct code.

It will in fact work.

But the problem with this is that this approach is not memory efficient.

Modern CPUs really like data to be sort of next to one another.

They really like data to be in a predictable sequence so that you know how many bytes to move from one

location to another.

Now obviously in this particular case, the compiler and the CPU, they will collectively figure out

how to access the x coordinate of each of the creatures.

But if you think about the memory layout, if you think about the way these creatures are laid out without

all the net trappings and so on, so you have the layout is like this, you have age x, Y, and then

the other creature age x, y, and then age x, Y.

So essentially when it comes to actually changing the x coordinate, it has to go here and then it has

to jump to here and then it has to jump to here.

Well, guess what?

The CPU would be much more efficient if you were to change the way things are laid out so that first

of all, you have an array with all the age values and then you have an array with all the X values,

and then you have an array with all the Y values.

Because then if you were to change all the X’s, you would just go through this part of the array.

You would go nicely from one cell to another and it would be much faster in on a modern CPU.

So the question is how can we actually implement this?

How can we get this to perform better on modern hardware without really changing anything in terms of,

you know, fundamentally reworking the creature class?

Well, the only way you can do this is if you actually implement what I would call a composite proxy,

or you would, in other words, implement a collection of creatures where the internal storage is completely

different, but the API is more or less the same because the only kind of API that we really want in

this case is we want to be able to enumerate something.

So we want something that’s enumerable and that stores the creature data but stores it in a very kind

of bunched up order.

So first of all, you have all the ages, then you have all the X’s, then you have all the Y’s.

So let’s try to build such a class.

So you would have a class called Creatures.

So in the class you would have the size, so you would specify how many elements there are.

So I would have private read only int size like this.

And this is something you would actually provide in the constructor, but in addition you would actually

store the age as the X’s and the Y’s.

And once again, we can use arrays to store all of this data.

So here I can have private byte array for age and I can have a private integer arrays for X and Y.

And then what I can do is I can initialize it here in the constructor so I can say that age is going

to be a new byte array with a particular size.

And the same goes for the X’s and the Y’s.

So x equals new int array of size and let’s just duplicate this and do the same for Y.

So this is how you would allocate the data.

And now you notice that the data is nicely aligned, so to speak, in the sense that first of all,

you have all the ages and then you have all the Xs and then you have all the Y’s.

But the question is how can we actually access any element of this array and actually get an API which

looks like a creature.

Now I’m not even going to bother extracting the interface from creature.

I’m just going to give you an identical interface, which is what the proxy pattern is all about.

So you would have something like a creature proxy, a creature proxy.

Now notice I’m using a struct here because it’s not actually going to store any any significant values.

The only thing that we need to store is the index of the creature to access and a reference to the overall

set of creatures.

So let me show you how this will work.

We’re going to start by building a constructor.

So the constructor is going to take two things.

It’s going to take a reference to all the creatures, and then it’s going to take a reference to the

index of the creature we’re actually interested in.

And so what I’m going to do is I’m actually going to have fields for both of these.

So let’s initialize creatures, let’s initialize the index as well.

And then what we really want to be able to do is to give out a reference which actually refers to an

age of a particular creature or their X or Y coordinates.

Here is the interesting thing.

Here is how you would define it.

You would say public ref byte age and here you return ref creatures dot age at a particular index.

So what’s going on here?

Well, whenever somebody accesses this proxy, they can start working with things like age as well as

the X and Y coordinates as well.

Let me actually just drop these down here below.

So you have the age, the X and the Y, But all these really are is they are references into the arrays

that we’ve defined up here.

So they’re not real.

They’re not just ordinary fields of this particular struct.

Instead, this struct is just a placeholder.

It’s just something that allows you to access the particular element.

All that’s changeable in the struct is the index.

So the index tells you where exactly you are looking into.

Now, theoretically you could expose the index as public so that people could modify it, but I’m just

going to keep it here as private.

So another question is, well, how can we how can we have a for each on creatures?

That’s not exactly difficult.

We don’t even need to explicitly implement getenumerator.

We just need to write it.

What I mean is we don’t need to implement enumerable or anything.

I can just say public I enumerator.

Creature proxy.

So here, notice I’m going to be giving out these proxies as opposed to actual creatures.

And so I enumerated creature proxy getenumerator.

Okay.

And here is what we do.

So for every single position from zero to size, we return a new creature proxy.

So here I’m going to say for int paws equals zero paws less than size plus plus paws.

What we’re going to do is we’re going to return or yield.

Return rather yield return a new creature proxy where this gets passed into the actual proxy and the

index is paws.

Okay.

So what what we can do with this setup is we can use almost the same API as up here, but get all the

performance benefits.

So essentially you’ll say something like var creatures too, and instead of using an array you would

say new creatures passing in the value 100.

So here you would create 100 creatures.

And obviously if you look at the actual constructor here for creatures, we are automatically allocating

all the memory that those creatures actually require.

So there is no need to then go through every single one of them and call a constructor on it like we

would here, because this is just a placeholder for 100 nulls basically.

So here, once you have creatures too, you can say for each var in creatures two and here you would

say C dot x plus plus.

So this is how you would actually modify every single one of the creatures.

But this time around is completely different.

We can actually replace this var by specifying the type explicitly and you can see that the type here

is creatures dot creature proxy.

So we’re essentially modifying something on the proxy.

So when you say C dot x plus plus what you’re really getting when you’re saying C dot x is you’re referencing

into creatures, dot dot x at a particular index.

So at the index that you’ve specified for that particular creature, you’re going into it, you’re getting

that reference and then using that reference to increment that particular value.

So the takeaway from this example and it’s sufficiently complicated example is that sometimes you build

proxies for purposes of performance improvements.

So in this case, we want all the data related to a particular well, all the data of a particular data

type in actual fact, being put together in an array of essentially a contiguous chunk of memory that’s

easier and more efficient to traverse than having to jump between the elements.

So we’ve put this all together and we now are able to to go through this.

So just to explain you the terminology behind all of this.

So this thing is essentially an array of structures, A, s, and what we’ve done here is we’ve made

a structure of arrays.

And what we talk about is we talk about this as so duality.

So we talk about the way that you can represent things one way or another.

If you look at programming languages such as J, for example, that’s where this is implemented implicitly

in the language.

You can just say this is this struct is going to be an so-a struct and then it gets automatically converted.

We don’t have that kind of automation here in C sharp, but we are able to build proxies which do pretty

much the same thing.

Play Play Play Play Stop Play Play Play Play Start Play Play information alert