WEBVTT

00:00.150 --> 00:01.860
Hello again! In this video,

00:01.890 --> 00:04.080
we are going to continue looking at unions.

00:05.190 --> 00:09.780
In the last video, we saw that we can use a tagged union to make things a bit safer.

00:10.440 --> 00:15.750
However, this still requires the programmer to check that a member is in use before they access it.

00:16.650 --> 00:21.870
And also, when the programmer brings a member into use, they have to remember to set the type.

00:22.500 --> 00:24.660
So there is still scope for human error.

00:25.590 --> 00:32.640
And besides, this is a very "C language" way of doing things. We are in C++, so why not use C++ features?

00:33.450 --> 00:37.650
And one of the things we could do, is to wrap this tagged union inside a class.

00:39.280 --> 00:42.280
So we have a class where the union is a private member.

00:42.880 --> 00:47.890
There are public member functions of the class, which are the only way to access the union.

00:48.960 --> 00:55.980
These functions will make sure that the tagged member is set and checked correctly, so the right type

00:55.980 --> 00:56.730
is always used.

00:57.810 --> 01:04.020
If we try to do something which is invalid, like accessing a member which is not in use, the member

01:04.020 --> 01:09.030
functions can perform error handling. So they could return a null pointer, for example, or throw an

01:09.030 --> 01:09.570
exception.

01:10.550 --> 01:14.330
And this means that the union can only be used correctly.

01:14.630 --> 01:16.730
It is not possible to use it in the wrong way.

01:18.800 --> 01:20.270
So let's try that out.

01:20.300 --> 01:23.030
We have the same union that we had in the previous video.

01:23.630 --> 01:29.540
This has the member with the token type, which is an enumeration of the allowed types.

01:31.700 --> 01:36.110
We create a class which has an object of this union as a member.

01:36.800 --> 01:40.730
Then we have member functions which set and get the members.

01:41.300 --> 01:45.200
I have not written all of them, but I am sure you can work out how to do it!

01:46.290 --> 01:49.830
For example, with the member function which will set the character member.

01:50.070 --> 01:55.620
This first sets the token type to character, and then it brings the character member into use.

01:57.040 --> 01:59.980
The member function which gets the double member.

02:00.310 --> 02:06.760
This will first check that the double member is in use, and it only returns the double member if it is

02:06.760 --> 02:07.210
in use.

02:07.720 --> 02:09.160
Otherwise it throws an exception.

02:09.490 --> 02:13.390
So this is the standard invalid argument, from the exception hierarchy.

02:15.000 --> 02:19.500
In the main function, we create an object of this class. We call set_character().

02:20.070 --> 02:24.120
So this rule sets the token type to character, and then bring the character member into use.

02:25.940 --> 02:28.490
We then call the get_double() member function.

02:29.210 --> 02:32.030
This will return the double member, if it is in use.

02:32.720 --> 02:34.130
Otherwise, it will throw an exception.

02:34.490 --> 02:37.430
So we have a try-catch block which will handle the exception.

02:39.490 --> 02:40.120
And then we go.

02:40.630 --> 02:43.600
We get an exception, and the double member is not in use.

02:46.680 --> 02:52.170
In C++ 17, there is now a type in the library which will do all this for us.

02:52.560 --> 02:53.670
It is called "variant".

02:54.800 --> 02:58.760
So this will do all the things that a wrapped, tagged union will do.

02:59.360 --> 03:00.380
It is type safe.

03:01.010 --> 03:05.720
You are allowed to have different members, or "alternatives", as they are called, which are the same type.

03:06.230 --> 03:08.180
Which is not possible with a union.

03:09.170 --> 03:14.540
The variant will automatically call the constructors and destructors for the members, which

03:14.840 --> 03:15.980
the union will not do.

03:16.010 --> 03:17.900
You have to call them yourself with a union.

03:18.680 --> 03:21.230
And all in all, it is simpler and safer to use.

03:22.400 --> 03:23.960
And you do not have to write all that code!

03:26.170 --> 03:29.680
Variant is a templated type. It is defined in the <variant> header.

03:30.610 --> 03:36.310
The parameters are the types of the members, or rather, alternatives. (I must get used to saying that!)

03:37.210 --> 03:42.130
So this variant will have alternatives which are character, int and double.

03:42.550 --> 03:45.010
So that is the same as having the union that we had earlier on.

03:47.430 --> 03:50.040
To use a variant we just assign to it.

03:50.040 --> 03:53.790
We do not need to assign to the members. The compiler

03:53.790 --> 03:55.950
will deduce which alternative we need.

03:56.280 --> 04:01.350
So if we assign to it and give a character argument, then this will bring the character member into use.

04:03.760 --> 04:05.170
To access the data,

04:05.170 --> 04:09.010
we call the get() function, and this works just like it does with tuples.

04:09.850 --> 04:15.160
So we can give the type as the parameter, and then we give the variant as the arguments.

04:16.090 --> 04:22.660
So this will retrieve the character member if it is in use. And if it is not in use, it will throw an exception.

04:24.370 --> 04:29.080
We can also get by index, and that is useful if there are alternatives which have the same type.

04:29.680 --> 04:37.270
So if we put zero as the parameter, that will gets the alternative which has index zero, which is

04:37.270 --> 04:38.110
the character.

04:40.990 --> 04:43.990
If we want to check whether an alternative is in use,

04:44.350 --> 04:46.420
there is the holds_alternative() function.

04:47.260 --> 04:49.480
This takes the type as the parameter.

04:50.110 --> 04:55.420
So if we want to know if double is in use, we put that as the parameter. And this will return true

04:55.420 --> 04:57.820
if it is in use and false if it is not.

04:59.680 --> 05:00.700
So here is an example.

05:00.760 --> 05:02.730
We include the variant header.

05:03.680 --> 05:08.900
We create a variant object which has the type parameters for char, int and double.

05:09.830 --> 05:12.980
We assign to a character, so that will bring the character member into use.

05:14.640 --> 05:20.520
We called holds_alternative() to find out if the double member is in use. And if it is, then we can call get().

05:23.310 --> 05:23.700
Okay.

05:23.700 --> 05:25.320
So the double member is not in use.

05:27.660 --> 05:27.910
Right.

05:27.990 --> 05:29.430
So why is this useful?

05:29.970 --> 05:32.700
What would you use a union or variant for?

05:33.330 --> 05:36.090
One application that we have already mentioned is parsing.

05:36.690 --> 05:40.710
If you are passing source code where a variable could have one of several types.

05:42.120 --> 05:48.510
Also, if you're parsing configuration files such as .INI files on Windows, where the parameters

05:48.510 --> 05:50.760
can only be a string, a number or a Boolean.

05:51.000 --> 05:52.890
That is quite a common way of writing them.

05:53.460 --> 05:56.310
You can also use them for implementing your own language.

05:57.030 --> 06:01.650
There are some languages which have a thing called "duck typing", which means that an object can have

06:01.650 --> 06:05.910
several types, and the type which it has depends on how it is used.

06:08.340 --> 06:12.480
You can also use them for return values, if you want to return different types.

06:12.840 --> 06:17.220
So he could, for example, have a computation which can have outcomes with different types.

06:18.940 --> 06:22.390
You can also use a union or variant for error handling.

06:22.780 --> 06:26.770
So if the operation succeeds, you can return an object which has the result.

06:27.370 --> 06:29.470
And if it fails, you can return an error code.

06:31.370 --> 06:36.710
And finally, this is another way to do polymorphism. And it is actually possible to implement virtual

06:36.710 --> 06:41.170
functions using unions and variant, if you are completely insane!

06:42.560 --> 06:44.000
Okay, so that is it for this video.

06:44.600 --> 06:45.500
I will see you next time.

06:45.500 --> 06:47.810
But until then, keep coding!
