1 00:00:01,520 --> 00:00:03,713 - [Instructor] Optionals in C++. 2 00:00:06,190 --> 00:00:07,803 Okay. What's our use case? 3 00:00:08,770 --> 00:00:12,040 Soon we're gonna implement hash tables in C++ 4 00:00:12,040 --> 00:00:15,330 and as you recall, our hash table may or may not 5 00:00:15,330 --> 00:00:17,920 have a value stored at any given index. 6 00:00:17,920 --> 00:00:20,053 Some elements may be empty. 7 00:00:21,150 --> 00:00:23,530 Then the question becomes what to do 8 00:00:23,530 --> 00:00:25,293 with empty elements in our vector? 9 00:00:26,320 --> 00:00:29,670 One approach is to initialize the elements of our vector 10 00:00:29,670 --> 00:00:32,940 with some sentinel value, like negative one or something 11 00:00:32,940 --> 00:00:35,503 to indicate that we haven't stored anything yet. 12 00:00:36,620 --> 00:00:39,130 And this is cumbersome and it would complicate 13 00:00:39,130 --> 00:00:41,310 our implementation of hash tables. 14 00:00:41,310 --> 00:00:44,293 So instead, we're going to use C++ optionals. 15 00:00:46,790 --> 00:00:49,923 Now, what is a C++ optional? 16 00:00:49,923 --> 00:00:53,350 A C++ optional is just a wrapper around a value 17 00:00:53,350 --> 00:00:55,170 that can indicate whether or not 18 00:00:55,170 --> 00:00:57,423 there is a value, or if it's just null. 19 00:00:58,890 --> 00:01:00,940 We specify a type as being optional, 20 00:01:00,940 --> 00:01:03,600 for example, we would use optional int 21 00:01:03,600 --> 00:01:04,930 and that would represent something 22 00:01:04,930 --> 00:01:07,030 that could be empty, or an int 23 00:01:08,930 --> 00:01:12,210 and using C++ optionals for the elements of our hash table 24 00:01:12,210 --> 00:01:16,010 will give us a convenient way of handling empty elements. 25 00:01:16,010 --> 00:01:18,160 Now I'll show you how to use C++ optionals. 26 00:01:23,077 --> 00:01:25,010 This might seem a little complicated at first, 27 00:01:25,010 --> 00:01:28,700 so we're gonna create a new file, optionals. 28 00:01:32,800 --> 00:01:36,410 Okay, now so far for this class, 29 00:01:36,410 --> 00:01:39,543 we've been using C++ standard 14. 30 00:01:41,380 --> 00:01:46,233 Optionals were not fully included in C++ standard until 17. 31 00:01:47,490 --> 00:01:52,490 They were made available on an experimental basis in 14 32 00:01:53,300 --> 00:01:55,520 but your particular installation, 33 00:01:55,520 --> 00:02:00,030 your particular compiler may not have the libraries, 34 00:02:00,030 --> 00:02:02,150 the experimental libraries. 35 00:02:02,150 --> 00:02:07,150 So what we're gonna do first is we're going to test 36 00:02:07,520 --> 00:02:12,180 to see if you're using C++ 14 or 17 37 00:02:13,070 --> 00:02:15,800 and then include the appropriate files 38 00:02:15,800 --> 00:02:18,710 based on our standard of C++. 39 00:02:18,710 --> 00:02:20,380 So the first thing we're going to do 40 00:02:20,380 --> 00:02:24,680 is we're going to test the standard of C++ that we're using 41 00:02:24,680 --> 00:02:27,210 and then we're going to include 42 00:02:27,210 --> 00:02:31,280 the appropriate libraries, depending on that version. 43 00:02:31,280 --> 00:02:33,310 And so we have a directive 44 00:02:33,310 --> 00:02:35,760 that you haven't seen before in this class 45 00:02:35,760 --> 00:02:40,760 and that's if underscore underscore C++ less than 17. 46 00:02:48,490 --> 00:02:51,310 So this is testing the version that we're using, 47 00:02:51,310 --> 00:02:53,093 if the version of C++. 48 00:02:53,093 --> 00:02:56,550 This is a variable that the compiler can see 49 00:02:56,550 --> 00:02:58,760 and we're just checking. 50 00:02:58,760 --> 00:03:01,300 Is the version less than 17? 51 00:03:01,300 --> 00:03:04,580 Is the standard less than 17, I should say? 52 00:03:04,580 --> 00:03:06,810 Okay and if that's the case, 53 00:03:06,810 --> 00:03:11,750 we're going to use the libraries that are experimental. 54 00:03:11,750 --> 00:03:16,750 So include experimental, sorry, optional. 55 00:03:25,780 --> 00:03:28,890 Then we're going to use components from that library 56 00:03:29,730 --> 00:03:34,730 using standard experimental, optional. 57 00:03:40,930 --> 00:03:45,240 And you'll recall this is the scope resolution operator, 58 00:03:45,240 --> 00:03:48,100 so we're actually looking in the standard library 59 00:03:48,100 --> 00:03:53,100 in the experimental sub library, the optional element. 60 00:03:53,770 --> 00:03:58,770 Okay and then using standard experimental, nullopt 61 00:04:04,900 --> 00:04:07,840 and that's the value that's returned 62 00:04:07,840 --> 00:04:10,980 when we have an empty element 63 00:04:11,870 --> 00:04:16,870 and then using, just for the sake of completeness, 64 00:04:17,370 --> 00:04:22,370 std experimental make_optional, okay? 65 00:04:30,730 --> 00:04:35,060 Now we have an else and what we put here 66 00:04:37,540 --> 00:04:39,480 will be processed by the compiler 67 00:04:39,480 --> 00:04:43,780 if our standard is 17 or greater. 68 00:04:43,780 --> 00:04:47,503 And so we're going to include optional. 69 00:04:53,480 --> 00:04:58,430 Okay and then using standard optional 70 00:05:01,580 --> 00:05:03,513 using std nullopt opt, 71 00:05:11,520 --> 00:05:15,817 using, sorry, std make_optional. 72 00:05:22,086 --> 00:05:25,800 All right and then we end our if block. 73 00:05:25,800 --> 00:05:26,633 End if. 74 00:05:28,010 --> 00:05:30,690 Okay, so this is a conditional 75 00:05:30,690 --> 00:05:33,880 and when our compiler runs, it's gonna check to see 76 00:05:33,880 --> 00:05:38,880 if our standard that we've specified is less than 17. 77 00:05:39,290 --> 00:05:43,080 If it is, it's going to try to include 78 00:05:43,080 --> 00:05:45,610 our experimental optionals 79 00:05:45,610 --> 00:05:50,610 and then we'll use these components. 80 00:05:50,640 --> 00:05:54,020 Otherwise, it's going to try to use 81 00:05:54,020 --> 00:05:59,020 the optional that's part of the C++ 17 standard, okay? 82 00:06:04,140 --> 00:06:06,290 If this gives you trouble, 83 00:06:06,290 --> 00:06:08,280 if this part gives you trouble 84 00:06:08,280 --> 00:06:11,433 and you can see I'm having a little trouble here 85 00:06:11,433 --> 00:06:16,100 then what you do is you modify, I'm sorry. 86 00:06:16,100 --> 00:06:21,100 You modify your CMAKE list to specify version 17. 87 00:06:24,610 --> 00:06:29,610 Reload those changes and that should make everything happy. 88 00:06:30,370 --> 00:06:32,270 Okay, so that works for me. 89 00:06:32,270 --> 00:06:36,290 So your mileage will vary, depending on your installation 90 00:06:36,290 --> 00:06:40,680 of your compiler or the libraries that you have available. 91 00:06:40,680 --> 00:06:44,880 But the idea is to make these optional nullopt 92 00:06:44,880 --> 00:06:47,740 and make_optional available to you. 93 00:06:47,740 --> 00:06:52,410 And that's also by the way, a reasonable use case 94 00:06:52,410 --> 00:06:57,000 for allowing using standard within a header file 95 00:06:58,720 --> 00:07:02,000 because we want optional null up and make optional 96 00:07:02,000 --> 00:07:07,000 but we don't wanna have to include the full scope operator 97 00:07:07,260 --> 00:07:09,970 within our code, because that may vary, okay? 98 00:07:09,970 --> 00:07:12,330 Here it's standard, here it's standard experimental. 99 00:07:12,330 --> 00:07:15,930 So that's why we're allowing using 100 00:07:15,930 --> 00:07:18,000 or we would allow using a header file 101 00:07:18,000 --> 00:07:20,860 if this were in fact a header file. 102 00:07:20,860 --> 00:07:22,563 We're also gonna include vector. 103 00:07:27,430 --> 00:07:30,667 Include iostream and include string. 104 00:07:38,970 --> 00:07:42,810 Okay, now what we're gonna do is we're going to create 105 00:07:42,810 --> 00:07:46,790 a function that makes use of optional 106 00:07:48,250 --> 00:07:51,675 and like I said in the slides earlier, 107 00:07:51,675 --> 00:07:56,675 we can specify something like this, optional int, 108 00:07:57,500 --> 00:08:00,350 which means it could be an integer, or it could be null. 109 00:08:00,350 --> 00:08:02,610 This function could return an integer 110 00:08:02,610 --> 00:08:04,680 or it could return an empty value 111 00:08:05,681 --> 00:08:07,483 and we'll call that find. 112 00:08:09,230 --> 00:08:12,470 And what we're gonna do is we're going 113 00:08:12,470 --> 00:08:15,180 to be hunting through a vector. 114 00:08:15,180 --> 00:08:17,260 We're just gonna use a simple linear search 115 00:08:17,260 --> 00:08:18,370 for this demo. 116 00:08:18,370 --> 00:08:23,370 So vector of std string. 117 00:08:28,860 --> 00:08:33,327 V and some key that we wanna look for. 118 00:08:33,327 --> 00:08:36,933 std string key. 119 00:08:38,590 --> 00:08:43,470 Okay. So this function is gonna take a vector of strings. 120 00:08:43,470 --> 00:08:46,560 It's gonna look for some key in that vector 121 00:08:46,560 --> 00:08:50,940 and it's going to return the index, 122 00:08:50,940 --> 00:08:55,940 if it finds it, or a nullopt, if it's not found. 123 00:08:56,340 --> 00:08:57,833 Okay, so that's convenient. 124 00:08:58,895 --> 00:09:03,895 For int i = 0 125 00:09:05,890 --> 00:09:09,067 i less than the v.size ++i. 126 00:09:16,030 --> 00:09:16,863 What are we gonna do? 127 00:09:16,863 --> 00:09:18,700 We're just gonna go through our vector. 128 00:09:18,700 --> 00:09:23,700 If the sub-i = key, we're gonna return i. 129 00:09:31,070 --> 00:09:33,780 Otherwise, if we get through the whole vector 130 00:09:34,770 --> 00:09:38,380 and we haven't found our key, we return nullopt, okay? 131 00:09:43,290 --> 00:09:45,830 And now we need a little driver code 132 00:09:45,830 --> 00:09:48,123 to make all this fun stuff happen. 133 00:09:49,020 --> 00:09:54,020 So let's have int main and let's have a standard vector. 134 00:10:01,021 --> 00:10:01,963 Call it strings. 135 00:10:05,260 --> 00:10:08,310 Call it V, as we've been doing all along 136 00:10:09,280 --> 00:10:12,680 and we'll give it the names of the days of the week. 137 00:10:12,680 --> 00:10:17,580 Monday, Tuesday, Wednesday, 138 00:10:23,540 --> 00:10:25,290 Thursday, Friday, 139 00:10:33,360 --> 00:10:37,373 Saturday and Sunday. 140 00:10:39,500 --> 00:10:40,760 One of these days, I'm gonna learn 141 00:10:40,760 --> 00:10:43,263 how to type while I'm talking, sorry. 142 00:10:44,220 --> 00:10:47,610 Okay, so that's our input vector 143 00:10:47,610 --> 00:10:50,900 and then we're going to call find 144 00:10:50,900 --> 00:10:52,850 and what does find return? 145 00:10:52,850 --> 00:10:56,763 It returns an optional int. 146 00:10:57,820 --> 00:11:02,540 Could be an int, it could be a null, i = find v. 147 00:11:05,060 --> 00:11:07,833 Find in v the string Thursday. 148 00:11:10,320 --> 00:11:15,320 Okay? And then we're gonna do a test. 149 00:11:15,670 --> 00:11:19,453 If i, then we're going to print the index 150 00:11:24,310 --> 00:11:26,970 and with the optional wrapper, 151 00:11:26,970 --> 00:11:31,290 what we get is a null value or a pointer to the value. 152 00:11:31,290 --> 00:11:35,633 So cout, we need to de-reference that pointer. 153 00:11:43,040 --> 00:11:46,423 And so when this code runs, when this code executes, 154 00:11:47,260 --> 00:11:51,033 we have indices zero one, two, three, okay? 155 00:11:52,410 --> 00:11:56,280 So when we run find on this input vector, 156 00:11:56,280 --> 00:12:00,460 it's going to return the value three 157 00:12:00,460 --> 00:12:05,000 because that's the index where the value at i 158 00:12:05,000 --> 00:12:08,270 matches the string that we passed in. 159 00:12:08,270 --> 00:12:13,270 And then we get this wrapper back 160 00:12:13,670 --> 00:12:15,760 and we check to see if it's empty 161 00:12:15,760 --> 00:12:18,810 and if it's not, then we know we have a value 162 00:12:18,810 --> 00:12:21,790 and so we wanna de-reference that value 163 00:12:21,790 --> 00:12:24,323 and send it to a standard output. 164 00:12:25,290 --> 00:12:27,460 So that's gonna print three 165 00:12:28,950 --> 00:12:32,010 and now let's do a negative case 166 00:12:32,010 --> 00:12:36,607 where i = find v 167 00:12:38,860 --> 00:12:41,410 and we'll put in a string that's not there, wombat. 168 00:12:42,260 --> 00:12:45,233 Wombat. Okay. 169 00:12:48,070 --> 00:12:52,750 And then if i, then the same thing. 170 00:13:03,230 --> 00:13:04,363 And then return zero. 171 00:13:07,240 --> 00:13:09,150 But let's think about what's gonna happen here. 172 00:13:09,150 --> 00:13:14,150 What's gonna happen is wombat is not in our vector. 173 00:13:14,400 --> 00:13:17,060 And so when we call find on our vector 174 00:13:17,060 --> 00:13:18,600 and the string wombat, 175 00:13:18,600 --> 00:13:20,940 it's gonna iterate through our vector. 176 00:13:20,940 --> 00:13:22,410 It's going to find that it's not there 177 00:13:22,410 --> 00:13:25,440 and it's gonna return nullopt. 178 00:13:25,440 --> 00:13:30,150 So when we test, if i, this is gonna be false, 179 00:13:30,150 --> 00:13:32,020 this is gonna be a falsie thing. 180 00:13:32,020 --> 00:13:34,413 And so this won't print print, 181 00:13:38,460 --> 00:13:43,280 because wombat is not in our vector 182 00:13:50,470 --> 00:13:55,470 and thus find will return nullopt. 183 00:14:00,630 --> 00:14:02,320 So if we run this code 184 00:14:02,320 --> 00:14:05,393 it's gonna print three and nothing else, okay? 185 00:14:07,020 --> 00:14:07,870 And let's run it. 186 00:14:16,730 --> 00:14:20,580 And there we go, we got that integer back 187 00:14:20,580 --> 00:14:24,173 and then this part, as expected, did not print. 188 00:14:25,230 --> 00:14:28,230 And that's how optionals work. 189 00:14:28,230 --> 00:14:31,210 And again, we're gonna use those in our hash tables 190 00:14:31,210 --> 00:14:34,660 to indicate whether a particular index 191 00:14:34,660 --> 00:14:36,943 in our hash table has a value or not. 192 00:14:37,920 --> 00:14:38,870 That's all for now.