This video is a Redo for the MOOC. Redo means do it yourself, watch the video and do what is shown step by step. It is also an invitation to look at how we program. I won't follow a precise script, I will try to do it, but if I encounter bugs or things like that, I'm gonna handle them as I go along. In this video, the idea is to program a little language that you can find in role-playing games like "Dungeons and Dragons". For example, for the ones who have this expression, what does this expression mean? It means: you must throw 2 20-sided dice and 1 4-sided. You'll see it can be a Pharo expression. So in this video we're going to implement a class representing a die and a class representing a handful of dice. So let's begin. We begin with defining a package. We call this package "Dice". I don't really want to see other things. So in this video I won't code in the debugger, you've seen it in another video, I will do it on a case-by-case basis, in an opportunistic way. Here I define the "Die" class which has a certain number of "faces". I compile. I add a class comment. For the moment, not much thing because it is very very simple. We are starting to enable our object to be initialized. I will do it like this. I call for an initialization of the super-class, by default I assign 6 faces to my die because it is the most common die. Now I'm starting to develop a tests class, to be sure that what we do doesn't break what has already been done. Tests classes are sub-classes of the TestCase class. We call it "DieTest". I have my tests class. One of the first tests to do, you don't have always to do it like this, but in any case I want to begin with a test that works well. As for the moment we don't have many things, I say that initialization is ok. This is also a way to show you how you can test that you can catch exceptions or that exceptions mustn't occur. Here I am saying: "Die new should not raise error". What does it mean? It means that when I execute this bit of code "Die new", no error must occur. I'm gonna classify my test and execute it. It's green. All right. So now, I'd like to define the method that makes a die roll. I know that in Pharo there must be a method called "at Random". At Random, what does it do? It enables to have... Ok... So now I look at the implementation to be sure it's ok. AtRandom, what does it do? It returns an integer at random from 1 to self, so it's perfect. So I'm gonna define a new method in Operations. What will it do? Roll. I say: "you return faces atRandom". So I write a test for this. TestRolling. What do we do now? We create a die. d:= die new And now I write "1000 timesRepeat". What? "d roll". And I want this to be between 1 and 6. "Between: and:", it's ok. "Between 1 and 6". It is not very good because here we created a test only for 6-sided dice, we could have said it works depending on the number of sides of the die. We will do it later. So I compile. I get an error. Here it is... It is ok, I have my test. Now it's time to save. Here I have my "Dice" package, I save it locally, "Save". I had created others before to train a little so I create a new one "New version with rolling and test". All right. Ok, it is saved. Now I'd like to change the creation interface. First we rearrange categories. If we want to change a little the creation interface. We say: "to create a die use die faces". On this expression you must see that faces is a message sent to the die class and not to an instance of die class, as it is the case in the roll method or in others methods coded until now. I will do this for you to understand when you have to use and go to the class level or not. Let's begin by writing a test. "betterInterface". If I go on with the same logic, "TestbetterCreationInterface", Here I'd like to do something like this for instance, and this to be faces. I will do it slowly. I go there and I type "instance creation", faces: , anInteger. I could write it in a short way but here I do it in a calm way. I create a die. I write "self new", as self here is the die class itself. I tell: "create an instance". And now with this instance I use an accessor to assign it the value passed as an argument. Obviously, I return the die that has just been created. When the code will be executed, it won't work because faces doesn't exist, so don't worry. You see that the test isn't ok, but it's normal, if I execute this for example, if I do debug to see... And I click on Over, here it says: "I don't know the faces message." Here we will do it calmly, I won't do it in the debugger. I say: "that's true, I have to add an accessor here. So I write faces: anInteger. And there I write : faces := anInteger. And while I'm at it, I create the read accessor. I return this one. And here my test is green. So we save, "save" "better die creation method with tests". All right. Now we can start to define what we want for diceHandle. Basically if we look, diceHandle, how would we like to write it? We would like to write diceHandle new addDie. So now we are going to create a new die, "die faces 6, addDie". "Die faces 10". We start to write a test class, this time. So a new class which inherits from TestCase. All right. I have my new tests class. And I define a test. The idea is to create a handful and to check there are the right dice in it. I write "testAdding", I want to reuse my code, there is no reason otherwise. So I have my handle; yourself , because I want to get the message receiver, it is to say the handle and not the argument that is here. Now what should I do? I write "self assert h diceNumber equals 2". I compile. Obviously the system says: "I don't know the DiceHandle variable. Do you want it to be a class?" Yes. It must be a class. Here it will define it. As I know that I have to stop the dice anyway I take this opportunity to put an instance variable. I compile all this. Now it's red because "Add die" hasn't been defined. So we will do it. Before doing this, it will be nice to initialise the handle, so we do it like this, it will prevent to have a bug later. dice : = OrderedCollection new. Recategorize. And now, I must be able to run my test, which will crash. Ok, very well. I create Add die. Adding. It says: "You should implement this method." Yes, it makes sense. I write "Dice add aDie". Ok, very good. My test won't still work because I still don't have defined the diceNumber method, let's do it. Yes, diceNumber, we will create it, in accessing this time. And diceNumber, what will it do? It must return dice size. I compile again, proceed. And my test should be green so, the tests are green and I save. "With addDie and test". We could improve the test because here it checks that we add 2 numbers, I'd like to check that when we add twice the same die we don't lose it. I write "TestAddingTwiceTheSame DieisOK". Here what do I do? I add 6 and 6 and I want to get 2 I do this I run my test, it's green, super. Now, it will be nice to be able to define what it is to do add 2 dice. But before this, let's do something. If you look, what I don't like, when I inspect this for example, if I do "Inspect" here, I don't see the dice values and it's not practical to debug. In the debugger, we don't see this. So before going on, I want to improve this. I'm going to add a method in the Printing protocol. The "PrintOn" method is defined on all the objects of the system and it will convert an object to a textual representation and pass a stream. We will only precise the representation we want inside it. If I do this, I've done nothing in fact. If I do super PrintOn, in fact I've done nothing. Now I will do "aStreamnextPut", so I will put characters in the stream, but what will I put first? I will write a parenthesis with a space, maybe it will be nicer, a parenthesis. Then I will consider faces and convert them in numbers, in strings, and concatenate all this with a closing parenthesis. If I do this... I closed the debugger, so I open it again. I have the debugger. Now I have a 6-sided die and a 10-sided die. So it is much nicer, you will see, if we encounter bugs, it will help. So here I didn't do anything special, my tests are running. I save again, it doesn't cost much, "With printing". We write "with die printOn". All right. Now we create the test, we won't do it, we will go directly there. We select "add protocol", "roll", "operations". So, there are several ways to define this. I propose you one, this is not the nicest but at least it is probably the clearest for you. There is a compact way, I could do it in one line, but using iterators like "Injected to", here I'm gonna use a loop. So what do I do? I take a value that I initialize to zero. Then I do a loop on all the dice, and for each loop step I get a die, and what am I going to do with this die? I ask it to get a die roll and to add the result to my variable. Nothing very special but at least it is very very explicit. Now if I do "Inspect" and there "Roll", 5, it doesn't prove it is working. Let's try once more. 11. Ok, it's working. We are gonna try to write a test, there is no reason, so we do "Test", I want to see this one and I call it rolling. So how do we have to do to test this? It has to be between one and the maximum of the number of dice. So we will do this. We could define a method doing this. Let's create a method defining the maximum. "Operation maxValue". What is maxValue ? It is very close to this. Here instead of doing roll, I will ask for the faces. Let's check. If I do "Inspect", there I do "maxValue", "16". Yes, it's right 10 and 6. So we write a test for "maxValue". So I have this, I do "maxValue equal 16". So here you see, I could have coded something very dirty in my test, but finally, it is better to create a method in the class and to use it. So now, we can test the roll method works well. Let's do "roll", and say it must be comprised between... "Roll between 1 and h maxValue. If I do this, ok it works. This is not very statistical, so here we could do something like 1 000 timesRepeat. Ok. And there, we have our 1000 tests. Now we save. All right. We save once more. "save" added maxValue and roll with tests. We've almost finished, what we want to express now, is instead of having "die faces 6", I'd like to have "1 D6". And what you see at the end is that it means "send the message 6 to a small integer". So we go and look at the integer class. What we are going to do is to define a class extension. What is a class extension? I'm gonna package my methods with the same name as my package. So you will see, what do I do? I add a protocol, I put *, it must start with *dice which is my package's name, automatically this is put in grey, and it means the method will be packaged at the same time as this package. So let's do it. Let's imagine we do... What is D6? A D6... I have to think a little about it... We first create a handle because it could be 2 D6 finally. So "handle", we do "diceHandle new", ok, so I have created my thing. Now for each receiver, I will do "self", this is my integer, "timesRepeat". We will have really used a lot the timesRepeat, it's rare. "TimesRepeat handle addDie", of what? Of "die faces". And there, we know it's 6. And indeed, it would maybe be good to return the handle. So does it work? We're going to test like this and we write a test. But if I do 2 D6, Inspect, look, I do have 2 D6. So that's cool. Let's write the test. We will categorize those tests after all. We write "testNewSyntax". Here for the moment we only have D6, we will generalize later. We want to do exactly the same thing than this, so we will have an handle, let's say 2 D6. And there, we do "selfAssert". What could we test? That diceNumber equals 2 for instance. So you've noticed sometimes I use diceHandle, I could have also used = 2 here. In general, it is nicer to use assert equal because like this, when there is an error, the system says: "I've received this and got this value instead of..." If I write =, it will say: "I've got a wrong expression." Here for the final user, who is yourself, as a developer, it is better to use assert equals because it will say: "I've received 3 whereas I was expecting 2", for instance. So here, I do this. Ok, it works. Could we have a smarter version of this test? For the moment, it suits us. You see that now in the package, I have an extension called D6. We will generalize this with "aNumberOfFaces" So "aNumberOfFaces", we put it there. And we rewrite D6 because it would be better. We write D6 like this. We do returns self D6. We do all the other ones. We do 4, 2. It's more a coin than a die, but 2, 10 and 20. You've understood the principle. So let's run the tests, as we've changed the implementation. 2 D6... it means it works. So let's save. What is there still to do? In fact, we have still to be able to add the handles. What tests do I want? For instance, I want to be sure if I do "addingHandles", (I can use the new syntax, so it's nice) I want to test that if I write 2 D20 + 3 D5 or 3 D6 instead (don't start to complicate things). How much should I get ? diceNumber should be equal to 5. So here you see that we have to define the + operator. In Pharo + isn't an operator, it's just a message. So we define a message on the DiceHandle class. We write +. So "aDiceHandle". Now we can wonder if we modify the receiver or either if we use a functional approach. I prefer to use a functional approach in which we create a new handle. So I'm gonna create a new handle, I write "handle self class new". Here I avoided to write diceHandle and later there will be a lesson explaining why. I prefer, it's closer. In general you don't hard-code the classes' name. You will see it in week 7 or something like this, there is a complete explanation. If I do "self dice do", I iterate on my dice and I add them in handle. So I do "handle addDie each", and I do the same... Here I don't need self and in fact I don't know the message, that's what it was telling me, and it makes me notice that, indeed, I haven't defined it and it hasn't worked for "diceHandle", but no matter, let's compile first and we'll fix it later. So here, what does it mean? It means it lacks an accessor, dice. So we add dice here, dice returns the collection of my dice. Now I'm gonna test, see if my test is ok. My test is ok, it's super, it means I have almost finished, I save, "with handles additions". Ok, all right. It means now we can write 2 D4 and we can do "Roll", and it returns a number. Now you are ready to play "Dungeons and Dragons". What you have to know: we defined our methods, we defined our tests, we run them, we extended a system class, the integer class, with extensions linked to our package, which will only be visible when our package will be loaded. We also overloaded operators, but in fact we only defined a new + message, because in Pharo the addition is just another message, this enabled us to express quite easily a nice DSL. So now it's your turn to code!