1 00:00:00,520 --> 00:00:03,800 Hi. During this class I'll be showing you exceptions, 2 00:00:03,960 --> 00:00:06,400 which are really powerful in Pharo. I'll give you an overview. 3 00:00:06,600 --> 00:00:09,160 What can we do with exceptions? We can resume them, 4 00:00:09,520 --> 00:00:11,840 restart them, signal them as new exceptions. 5 00:00:12,000 --> 00:00:16,240 I'm only going to show you things that will be useful in a practical way 6 00:00:16,400 --> 00:00:17,840 when first using exceptions, 7 00:00:18,000 --> 00:00:20,840 but it's important that you know that this isn't everything. 8 00:00:21,000 --> 00:00:24,600 There are 2 kinds of exceptions, "Errors", which are often fatal 9 00:00:24,760 --> 00:00:27,680 and "notifications" which we can say we don't need, 10 00:00:27,840 --> 00:00:29,160 they're just for reference. 11 00:00:30,320 --> 00:00:32,800 So, if you're interested in reading 12 00:00:32,960 --> 00:00:35,800 a complete reference on exceptions 13 00:00:35,960 --> 00:00:39,640 there's a whole chapter in the book, "Deep Into Pharo", 14 00:00:39,800 --> 00:00:45,040 which is on the MOOC website and available free online. 15 00:00:45,600 --> 00:00:50,640 So, what are you going to learn? To raise and trap exceptions, 16 00:00:50,800 --> 00:00:54,400 and some nice helper methods we can use every day. 17 00:00:54,960 --> 00:00:55,800 So basically, 18 00:00:56,000 --> 00:00:58,440 everything about this class is on this page. 19 00:00:58,800 --> 00:01:02,360 You're going to install a handler to trap an exception, 20 00:01:02,520 --> 00:01:03,480 you'll signal them, 21 00:01:03,640 --> 00:01:08,280 and we'll have 2 nice messages, which are "ensure" and "ifCurtailed" 22 00:01:09,400 --> 00:01:11,280 So, let's take a look. 23 00:01:11,840 --> 00:01:14,680 Imagine that I wanted to trap an exception. 24 00:01:14,840 --> 00:01:16,880 It's the "on: do" message. 25 00:01:17,040 --> 00:01:20,120 I make a block, if I've an action, when I have an action, 26 00:01:20,280 --> 00:01:23,160 if ever I have an exception, what do I do? 27 00:01:23,320 --> 00:01:27,280 "Something" and here is the exception, which is passed in argument. 28 00:01:27,920 --> 00:01:31,520 If we look at an example of zero division, 29 00:01:31,680 --> 00:01:34,960 if I do 7 divided by 0... 30 00:01:35,600 --> 00:01:38,120 when I have a zero divide, what do I have to do? 31 00:01:38,280 --> 00:01:41,640 I'll write, "Watch out, there's a zero divide." 32 00:01:41,800 --> 00:01:47,160 The thing to notice here is that an instance of the Exception class 33 00:01:48,360 --> 00:01:49,840 has been passed as an argument, 34 00:01:50,000 --> 00:01:52,600 and I'll be able to question it and send it messages, 35 00:01:52,760 --> 00:01:54,680 because exceptions are objects in Pharo. 36 00:01:54,840 --> 00:01:56,600 I'll send messages in my exceptions 37 00:01:56,760 --> 00:02:00,400 to do something and it will show me 0. 38 00:02:00,800 --> 00:02:02,920 So how do we raise an exception? 39 00:02:03,240 --> 00:02:07,400 Basically, we create an exception and we send it the signal message. 40 00:02:07,560 --> 00:02:10,840 So here, when we want to give a warning I do, "Warning new". 41 00:02:11,000 --> 00:02:15,240 I create an exception, customise it, I put the message I want inside, 42 00:02:15,400 --> 00:02:16,760 and send the Signal message. 43 00:02:16,920 --> 00:02:21,000 When I've an exception to be able to ask the author, 44 00:02:21,160 --> 00:02:23,000 writing the method, 45 00:02:23,160 --> 00:02:24,720 then you'll have another API, 46 00:02:24,880 --> 00:02:28,240 because it's "AuthorNameRequest" that defines this API, 47 00:02:28,400 --> 00:02:30,440 so I've passed "Stef" then I'll do "signal". 48 00:02:30,600 --> 00:02:33,080 What usually happens is that the classes 49 00:02:33,240 --> 00:02:38,040 propose shortcuts to avoid having to create, so I'm sending 50 00:02:38,200 --> 00:02:41,640 "OutOfMemory", that's the class. I send the signal message to the class. 51 00:02:41,800 --> 00:02:44,800 Normally, with warnings, I don't do "Warning new, blah, blah..." 52 00:02:44,960 --> 00:02:48,840 I do "Warning signal" with the text, because it's shorter, 53 00:02:49,000 --> 00:02:51,160 but that depends on your exceptions. 54 00:02:51,720 --> 00:02:56,800 So, since we like agile programming with unit tests, 55 00:02:57,000 --> 00:03:00,080 and test-driven programming, 56 00:03:00,240 --> 00:03:04,440 how can we test that an exception is raised in SUnit? 57 00:03:04,600 --> 00:03:08,840 We're going to use "shouldn't raise" and "should raise". 58 00:03:09,000 --> 00:03:10,440 Let's read this together. 59 00:03:10,600 --> 00:03:13,640 I want to say here, "Look out, I don't want 60 00:03:13,800 --> 00:03:15,840 "an exception to be raised, 61 00:03:16,000 --> 00:03:18,240 "for it to be a SubscriptOutOfBounds. 62 00:03:18,400 --> 00:03:21,640 "if I create a date in February". 63 00:03:21,800 --> 00:03:25,200 Now, if I want to test that I should have an error 64 00:03:25,360 --> 00:03:29,040 when I create a date in the 13th month, 65 00:03:29,200 --> 00:03:32,240 something you don't usually get, in your pay, 66 00:03:32,400 --> 00:03:35,560 then I'll use "should raise", 67 00:03:35,720 --> 00:03:37,080 which means, "Watch out, 68 00:03:37,240 --> 00:03:40,960 "if you create a date in a 13th month, I'll raise an error". 69 00:03:41,120 --> 00:03:44,000 That allows you to create the unit test, 70 00:03:44,160 --> 00:03:46,280 while controlling exceptions. 71 00:03:46,440 --> 00:03:48,400 It's a digression, but it's important 72 00:03:48,560 --> 00:03:51,120 to know there are these 2 little helper methods. 73 00:03:52,120 --> 00:03:54,360 So, what are exceptions in Pharo? 74 00:03:54,560 --> 00:03:56,040 There are errors: 75 00:03:56,200 --> 00:03:59,360 "message not understood", "subscript", "division by zero", 76 00:03:59,520 --> 00:04:03,280 you have "halt", which we'll look at when we come to debugging. 77 00:04:03,440 --> 00:04:04,840 You can put a break point, 78 00:04:05,000 --> 00:04:07,480 which will stop execution of the system. 79 00:04:07,640 --> 00:04:10,760 You have notifications, everything non fatal, 80 00:04:10,920 --> 00:04:15,400 so a deprecation, "don't use this method, use another", 81 00:04:15,560 --> 00:04:16,880 warnings and timedout. 82 00:04:17,040 --> 00:04:19,760 One nice thing is, you have an error message 83 00:04:19,920 --> 00:04:22,240 which describes unhandled errors. 84 00:04:22,400 --> 00:04:25,240 This is what raises the debugger. 85 00:04:25,400 --> 00:04:28,680 We don't normally use it, but it's just to tell you 86 00:04:28,840 --> 00:04:31,360 that unhandled errors are also a class of error. 87 00:04:32,080 --> 00:04:34,720 Exceptions are real objects. 88 00:04:34,920 --> 00:04:37,920 If we look at how the "doesNotUnderstand" message 89 00:04:38,120 --> 00:04:41,600 is defined, you can see it in ProtoObject with your Pharo browser, 90 00:04:41,760 --> 00:04:43,920 you do, "messageNotUnderstood new", 91 00:04:44,080 --> 00:04:48,960 I send a message to the receiver, which is the object, and give a signal. 92 00:04:49,120 --> 00:04:53,480 You get this signal when you send "point new strangeAndBizarre". 93 00:04:53,640 --> 00:04:56,160 It's not known as a message, "strangeAndBizarre" 94 00:04:56,320 --> 00:04:57,920 so it will create this exception. 95 00:04:59,440 --> 00:05:01,880 We have deprecation, for example, which means, 96 00:05:02,040 --> 00:05:05,040 if you use an API which evolves over time 97 00:05:05,200 --> 00:05:08,200 and which Pharo has decided is no longer valid, 98 00:05:08,360 --> 00:05:09,520 in fact... 99 00:05:09,680 --> 00:05:15,000 How do we do that in Pharo? We say, "deprecated: on: in" 100 00:05:15,160 --> 00:05:17,360 Here, I've chosen a clear example, 101 00:05:17,520 --> 00:05:19,680 "menu, item, title" and what does it say? 102 00:05:19,840 --> 00:05:23,880 "Use the method addTitle instead of "title". 103 00:05:25,200 --> 00:05:26,960 How is it implemented? 104 00:05:27,120 --> 00:05:30,480 It's implemented in the following way: "deprecated", 105 00:05:30,640 --> 00:05:33,960 this, "create an exception", 106 00:05:34,120 --> 00:05:35,280 which is called "deprecation" 107 00:05:35,440 --> 00:05:39,960 within which I'll pass it "method, explanation, on, in", 108 00:05:40,120 --> 00:05:42,680 which will give a signal. So it's just to show you that 109 00:05:42,840 --> 00:05:46,800 "deprecation", "messageNotUnderstood", are exceptions we create and raise. 110 00:05:48,320 --> 00:05:52,080 So this is just a detail, you can have exception sets. 111 00:05:52,240 --> 00:05:54,960 You can say, "If I have ZeroDivide, and I have Warning, 112 00:05:55,120 --> 00:05:59,080 or I have Warning, you're going to be able, 113 00:05:59,240 --> 00:06:02,800 to contain the exceptions with a comma", which will create an exception set, 114 00:06:02,960 --> 00:06:06,200 allowing you to say, "I want to react to all these exceptions". 115 00:06:06,360 --> 00:06:11,000 It's very rarely used, it's just for completeness. 116 00:06:11,720 --> 00:06:14,840 Now we're going to look at some very handy methods, 117 00:06:15,520 --> 00:06:17,320 which we often use. 118 00:06:17,480 --> 00:06:20,680 How can I ensure that an expression is always executed, 119 00:06:20,840 --> 00:06:24,360 even if the program fails beforehand? 120 00:06:24,520 --> 00:06:27,320 So the idea is "ensure". What does "ensure" do? 121 00:06:27,480 --> 00:06:29,120 You do something, 122 00:06:29,280 --> 00:06:33,520 and I guarantee that the other block will be executed. 123 00:06:33,680 --> 00:06:38,800 It's very powerful, it lets you to close files automatically. 124 00:06:39,400 --> 00:06:43,160 That's what we see in SpyOn, for the Pharo profiler. 125 00:06:43,320 --> 00:06:46,680 There's a class on it. I say, " I'm starting profiling", 126 00:06:46,840 --> 00:06:49,640 I execute the block I want to profile 127 00:06:49,800 --> 00:06:52,160 and I guarantee myself I'll stop profiling, 128 00:06:52,320 --> 00:06:55,200 even if you've passed me a block with an error. 129 00:06:55,400 --> 00:06:57,480 There's another helper 130 00:06:57,680 --> 00:07:00,000 which is really nice, which is how can I ensure 131 00:07:00,160 --> 00:07:04,680 an expression is executed only if the program fails? 132 00:07:05,440 --> 00:07:09,320 What I'll do is I'll say, "You do something if ever 133 00:07:09,480 --> 00:07:13,880 "something strange happens, I want you to execute this code". 134 00:07:14,040 --> 00:07:16,680 Here I've taken an example in "wait", which is really 135 00:07:16,840 --> 00:07:20,800 very low level, which allows you to change the processor scheduling. 136 00:07:21,520 --> 00:07:26,800 I say, "There's the system, schedule a semaphore," 137 00:07:26,960 --> 00:07:30,320 I do an operation and if ever something doesn't work, 138 00:07:30,480 --> 00:07:32,520 the system guarantees 139 00:07:32,680 --> 00:07:36,160 that I'll remove it from the scheduler. 140 00:07:36,320 --> 00:07:40,080 These methods are really handy, because they're very powerful. 141 00:07:40,480 --> 00:07:45,280 I've given you a slide to explain how the method lookup works, 142 00:07:45,440 --> 00:07:47,120 in addition to the book. 143 00:07:47,320 --> 00:07:48,480 Now... 144 00:07:48,680 --> 00:07:50,440 just for your information, 145 00:07:50,600 --> 00:07:53,600 the things we can do with exceptions in Pharo, 146 00:07:53,760 --> 00:07:59,160 you can return an alternative result, you can retry, in fact. 147 00:07:59,320 --> 00:08:01,320 You can change the execution of the program and say, 148 00:08:01,480 --> 00:08:05,320 "Act as though the exception didn't happen". 149 00:08:05,480 --> 00:08:07,800 I can resume, 150 00:08:07,960 --> 00:08:11,600 I can say, "No, I don't want to deal with this exception at this level, 151 00:08:11,760 --> 00:08:13,280 "I want to deal with it higher up". 152 00:08:13,440 --> 00:08:14,920 I can resignal an exception, 153 00:08:15,080 --> 00:08:18,840 "No, you raised this exception but it's old, I want a new one" 154 00:08:19,000 --> 00:08:19,880 with resignal. 155 00:08:20,040 --> 00:08:23,520 When you need this it means you know what you're doing, 156 00:08:23,680 --> 00:08:28,400 and you've read the chapter, so just be aware that it exists. 157 00:08:28,600 --> 00:08:30,520 This was just to show you. 158 00:08:30,720 --> 00:08:33,600 I want to return another value from an exception, I do "return", 159 00:08:33,760 --> 00:08:38,160 and you can see that here, I had my block which gave me this value. 160 00:08:38,320 --> 00:08:41,400 I raised an exception, and in the end, 161 00:08:41,560 --> 00:08:45,400 it's this value that was returned. That's with "return". 162 00:08:45,560 --> 00:08:48,400 Now, with "resume", what you're going to have, 163 00:08:48,560 --> 00:08:50,920 "resume" is... 164 00:08:51,080 --> 00:08:54,240 I've my exception which is raised here, 165 00:08:54,400 --> 00:08:58,560 and what I see is that, in my exception, when I do "resume", 166 00:08:58,720 --> 00:09:02,120 it's not this value that's returned, it's the next value, so I say, 167 00:09:02,280 --> 00:09:07,360 "Continue after the exception point", so start again from here, 168 00:09:07,520 --> 00:09:10,120 and that will give me this value. 169 00:09:11,240 --> 00:09:14,000 So now if we look at what you should know: 170 00:09:14,200 --> 00:09:16,960 exceptions are powerful in Pharo, OK, great. 171 00:09:17,120 --> 00:09:20,840 There's a very simple API, it's "signal" to raise an exception, 172 00:09:21,000 --> 00:09:22,720 "on: do" to trap them, 173 00:09:22,880 --> 00:09:27,880 and you have "ensure" to guarantee that this expression is always executed, 174 00:09:28,040 --> 00:09:30,280 if I have a problem here or not, 175 00:09:30,440 --> 00:09:32,720 and there's this expression, with "ifCurtailed", 176 00:09:32,880 --> 00:09:35,720 which will execute "onProblem" if I've a problem in "doSomething". 177 00:09:35,880 --> 00:09:38,760 That's all you need to know to get started with exceptions.