WEBVTT 00:00.000 --> 00:11.000 Hello Kitty, so Kitty will explain some particularities of Python and because Python was based 00:11.000 --> 00:13.000 on some other languages and maybe... 00:13.000 --> 00:15.000 There's my Python in this talk. 00:15.000 --> 00:18.000 OK, it's for a spell or something like that. 00:18.000 --> 00:19.000 Oh my gosh. 00:19.000 --> 00:22.000 I'm not in the good room, sorry, bye. 00:22.000 --> 00:25.000 OK, hello everyone, let's talk about JavaScript. 00:26.000 --> 00:30.000 In, I think I have 25 minutes. 00:30.000 --> 00:33.000 In JavaScript, what is 4 plus 2? 00:33.000 --> 00:36.000 It's 6, what is 4 minus 2? 00:36.000 --> 00:40.000 It's 2, what is 4 minus the string 2? 00:40.000 --> 00:44.000 It's 2, so of course, 4 plus the string 2 is 42. 00:44.000 --> 00:49.000 Let's talk about JavaScript in JavaScript is 1 equal to the string 1. 00:49.000 --> 00:52.000 Hands up for true, hands up for false. 00:52.000 --> 00:56.000 It's true, but if you add an extra equals, it's true, it's false. 00:56.000 --> 00:58.000 It's fine, everything's fine. 00:58.000 --> 01:00.000 Let's talk about JavaScript in JavaScript. 01:00.000 --> 01:02.000 What is the sum of 2 empty arrays? 01:02.000 --> 01:07.000 It's an empty string, what's the sum of an empty array and an empty object? 01:07.000 --> 01:11.000 Object objects, what about the sum of an empty object and an empty array? 01:11.000 --> 01:14.000 Zero, what about the sum of 2 empty objects? 01:14.000 --> 01:17.000 Not a number! 01:17.000 --> 01:21.000 Ah, I see you have seen this talk before. 01:22.000 --> 01:24.000 Oh, Gary Bernhardz, what's talk? 01:24.000 --> 01:27.000 Which is now over a decade old? 01:27.000 --> 01:28.000 I'm sorry. 01:28.000 --> 01:30.000 It was from 2012. 01:30.000 --> 01:33.000 That talk goes on the wats. 01:33.000 --> 01:35.000 I want to do something more. 01:35.000 --> 01:37.000 I want to talk about the wats. 01:37.000 --> 01:40.000 We're going to focus on the wide during this talk and work out. 01:40.000 --> 01:41.000 What the heck was all that? 01:41.000 --> 01:46.000 But well, specifically, does Python have the same problems? 01:46.000 --> 01:50.000 Woo! 01:50.000 --> 01:53.000 In this example, it's an issue of overloaded operators. 01:53.000 --> 01:55.000 The first one we have implicit coercion. 01:55.000 --> 01:58.000 Subtraction is only defined for numerics. 01:58.000 --> 02:00.000 So it coerses the string into a number. 02:00.000 --> 02:04.000 The second one, it's the plus operator that is overloaded. 02:04.000 --> 02:09.000 It can act as both numeric addition or in this case, string concatenation. 02:09.000 --> 02:15.000 In JavaScript, double equals will only compare the values after it coerses it into the same type. 02:15.000 --> 02:21.000 That triple equals will also confirm that the types it equal and exit early if they're not. 02:21.000 --> 02:26.000 And our third case is a little bit more complicated than this. 02:26.000 --> 02:30.000 So to explain this, we're going to have to dive more into the addition operator. 02:30.000 --> 02:31.000 What is it exactly? 02:31.000 --> 02:35.000 Well, thankfully, we have a way to know exactly what the plus does in JavaScript. 02:35.000 --> 02:41.000 Thanks to AgmasScript 2024 standard specification as defined by ECMA262. 02:41.000 --> 02:45.000 This is a standard that defines the JavaScript you use in the browser today, 02:45.000 --> 02:48.000 and it covers JScript as well as actionscript. 02:48.000 --> 02:51.000 And within that standard, we can go into section 138.1, 02:51.000 --> 02:54.000 which denotes the week and then go into the runtime semantics, 02:54.000 --> 02:56.000 which then denotes the week and go into a value, 02:56.000 --> 02:58.000 it's string on numeric binary expression. 02:58.000 --> 03:01.000 If we go there, it says apply string on numeric binary expression. 03:01.000 --> 03:04.000 And from there, it says exactly what we need to do. 03:04.000 --> 03:07.000 Just that. 03:07.000 --> 03:16.000 Now, if a language has a standard, you probably won't learn how to use the language by trying to read this. 03:16.000 --> 03:20.000 So, but for our purposes, it's useful to see like what a standard looks like, 03:20.000 --> 03:22.000 but let me simplify this down. 03:22.000 --> 03:26.000 Consider the addition of two placeholder values A and B. 03:26.000 --> 03:30.000 Step one, convert A and B to primitives. 03:30.000 --> 03:36.000 If after converting A or B are a string, then can cadinate them together. 03:36.000 --> 03:42.000 Otherwise, convert both to numbers and then return the operation in this case plus, 03:42.000 --> 03:45.000 who can see where the problem starts. 03:45.000 --> 03:49.000 To primitive is also its own separate defined method, 03:49.000 --> 03:54.000 where if it is an object, then first try to get the value of that object. 03:54.000 --> 03:58.000 And if that itself is not an object, then return it. 03:58.000 --> 04:01.000 Otherwise, can't the object to a string. 04:01.000 --> 04:04.000 And then return it, and if it wasn't an object in the first place, 04:04.000 --> 04:06.000 then you'll find you're already in a primitive. 04:06.000 --> 04:10.000 So, let's try one of our examples, empty array and empty object. 04:10.000 --> 04:14.000 According to our algorithm, the first thing we need to do is convert both to primitives. 04:14.000 --> 04:19.000 So, bringing up that algorithm, we start by converting the empty array into a primitive. 04:19.000 --> 04:24.000 So, we try the type of, which is an object, so we have to go further, 04:24.000 --> 04:25.000 and so we check the value of. 04:25.000 --> 04:29.000 And the value of an empty list is an empty list, 04:29.000 --> 04:32.000 and if we cast that to a string, it's an empty string. 04:32.000 --> 04:34.000 Well, how does that work? 04:34.000 --> 04:39.000 Well, this is defined because if you take an array and you go to string on it, 04:39.000 --> 04:43.000 it calls the join of all the elements in that string. 04:43.000 --> 04:47.000 So, if we join the array 1, 2, 3, we'll get 1, 2, 3, 04:47.000 --> 04:51.000 and if it's an empty string, empty list, it will be an empty string. 04:51.000 --> 04:53.000 This makes sense. 04:53.000 --> 04:55.000 So, we can do the exact same thing to object. 04:55.000 --> 04:58.000 We first check what's the type of an object, it's an object, 04:58.000 --> 05:00.000 and what is the value of that? 05:00.000 --> 05:03.000 Well, it's still the same squiggly brackets, hello again, 05:03.000 --> 05:06.000 and then if we try to cast that to a string, of course, we get object object. 05:06.000 --> 05:08.000 Well, how does that happen? 05:08.000 --> 05:10.000 Well, again, it's defined. 05:10.000 --> 05:13.000 If you call two string from an object, 05:13.000 --> 05:17.000 the method will return the string object tag, 05:17.000 --> 05:20.000 where tag is determined by the object type, 05:20.000 --> 05:23.000 or in this case, literally, the string object. 05:23.000 --> 05:27.000 So, in JavaScript, any time you try to do a two string on an object, 05:27.000 --> 05:30.000 and you get this, mostly in your console error logs, 05:30.000 --> 05:33.000 that is what is supposed to happen. 05:33.000 --> 05:37.000 A lot of programming languages will instead have this type of method, 05:37.000 --> 05:41.000 give a string-based representation of the contents of the object, 05:41.000 --> 05:44.000 but here, it's hopefully telling you, yes, I am object. 05:44.000 --> 05:49.000 You can use Core JavaScript to get the contents of an object 05:49.000 --> 05:51.000 by using stringify. 05:51.000 --> 05:54.000 Instead, JSON.stringify will give you a stringy representation 05:54.000 --> 05:56.000 of the contents of an object. 05:56.000 --> 06:00.000 So, we know what the primitive types for our two objects are, 06:00.000 --> 06:03.000 and so we can start putting them together. 06:03.000 --> 06:05.000 We can concatenate an empty string, an empty object, 06:05.000 --> 06:08.000 and so we know that the concatenation of an empty list, 06:08.000 --> 06:10.000 an empty object, is object object. 06:10.000 --> 06:12.000 Great, and we can do the same thing for two empty lists. 06:12.000 --> 06:15.000 We can concatenate their two primitive together, 06:15.000 --> 06:17.000 and we know that it's an empty string. 06:17.000 --> 06:20.000 But what about the other permutations? 06:20.000 --> 06:22.000 Because we know that they don't match, 06:22.000 --> 06:24.000 and we would presume that, in JavaScript, 06:24.000 --> 06:26.000 addition would be commutative, A and B 06:26.000 --> 06:28.000 as the same as B plus A. 06:28.000 --> 06:31.000 So, based on our knowledge, we know that something's not right here. 06:31.000 --> 06:32.000 But guess what? 06:32.000 --> 06:34.000 That's defined in this specification. 06:34.000 --> 06:37.000 Well, because in the runtime semantics, 06:37.000 --> 06:40.000 it says what to do if you have an empty object, 06:40.000 --> 06:44.000 or in this case an empty block, is to return empty. 06:44.000 --> 06:48.000 So, when we have an empty object here, 06:48.000 --> 06:51.000 that's actually being interpreted as an empty block. 06:51.000 --> 06:55.000 So, when we try to do anything with an empty block, 06:55.000 --> 06:58.000 it actually does unary addition, 06:58.000 --> 07:02.000 which tries to then, as per the specifications, 07:02.000 --> 07:04.000 cast it to a number. 07:04.000 --> 07:06.000 And in this case, we know that the primitive, 07:06.000 --> 07:08.000 this is an empty string, an empty string, is falsely, 07:08.000 --> 07:10.000 and so it's zero. 07:10.000 --> 07:14.000 And that is actually defined as what happens 07:14.000 --> 07:17.000 when you have a white space, this term is zero. 07:17.000 --> 07:20.000 So, if we try to do the same thing with our objects, 07:20.000 --> 07:23.000 we're trying to add together two objects, 07:23.000 --> 07:24.000 which is actually an empty block, 07:24.000 --> 07:26.000 and a unary addition of an object, 07:26.000 --> 07:28.000 and we know that the primitive of the object 07:28.000 --> 07:32.000 starts with a bracket, which is not a number. 07:32.000 --> 07:35.000 And therefore, we have our entire collection of things 07:35.000 --> 07:38.000 that we know exactly what's going on, except I cheated. 07:38.000 --> 07:42.000 Earlier, I was wrapping the objects in parentheses 07:42.000 --> 07:46.000 to make sure that I could actually get the value of an empty object, 07:46.000 --> 07:48.000 as a switch to an empty block. 07:48.000 --> 07:52.000 And so, this original example will run correctly 07:52.000 --> 07:54.000 if you actually use variables, 07:54.000 --> 07:56.000 and not just throw this in a repel, 07:56.000 --> 08:00.000 because those last two examples are doing strange things. 08:00.000 --> 08:03.000 So, you can actually preserve community 08:03.000 --> 08:05.000 if you use parentheses. 08:05.000 --> 08:06.000 Ta-da! 08:06.000 --> 08:08.000 Ta-da! 08:08.000 --> 08:09.000 Ta-da! 08:09.000 --> 08:11.000 Ta-da! 08:11.000 --> 08:13.000 Ta-da! 08:13.000 --> 08:15.000 So, now's the question. 08:16.000 --> 08:19.000 Does Python have this particular peculiarity? 08:19.000 --> 08:23.000 Is Python prone to the same potential problem, perhaps? 08:23.000 --> 08:29.000 Well, in Python, what is the concatenation of two empty lists? 08:29.000 --> 08:31.000 It's an empty list. 08:31.000 --> 08:35.000 What about the concatenation of an empty list, an empty dictionary? 08:35.000 --> 08:36.000 It's a typo. 08:36.000 --> 08:40.000 What about the concatenation of an empty dictionary, an empty list? 08:40.000 --> 08:41.000 It's a typo. 08:41.000 --> 08:44.000 What about the concatenation of two empty dictionaries? 08:44.000 --> 08:47.000 It's a typo. 08:47.000 --> 08:49.000 But different typoers. 08:49.000 --> 08:51.000 So, to see what's going on here, 08:51.000 --> 08:54.000 we're going to have to look at the Python standard. 08:54.000 --> 09:05.000 Now, Python, like a few modern programming languages, 09:05.000 --> 09:07.000 doesn't have a capital S standard. 09:07.000 --> 09:10.000 Some languages have standards, held by bodies like ISO, 09:10.000 --> 09:12.000 ECMA, I tribally, etc. 09:12.000 --> 09:14.000 But some have defector standards. 09:14.000 --> 09:16.000 In PHP, we have Python enhancement proposals, 09:16.000 --> 09:18.000 and we have the defector standard, 09:18.000 --> 09:21.000 which is the C-Python implementation of Python, 09:21.000 --> 09:23.000 which we can reference. 09:23.000 --> 09:26.000 And in C-Python, there is the Python standard library. 09:26.000 --> 09:29.000 And within that, there is documentation for sequence types, 09:29.000 --> 09:31.000 that being list, tuple, and range. 09:31.000 --> 09:34.000 And within that, it includes that the plus parameter 09:34.000 --> 09:37.000 does concatenation of two types. 09:37.000 --> 09:40.000 And if we were to search the source code for this error, 09:40.000 --> 09:42.000 can only concatenate list. 09:42.000 --> 09:46.000 We would get the C-Python C implementation of 09:46.000 --> 09:48.000 what list concatenation does. 09:48.000 --> 09:52.000 And the first thing it does is goes, if B is not a list, 09:52.000 --> 09:56.000 and we can also see this within Python itself 09:56.000 --> 09:59.000 in a roundabout way, because the Python language 09:59.000 --> 10:01.000 refers to special method names, 10:01.000 --> 10:04.000 also known as double underscores, 10:04.000 --> 10:08.000 真的, Australia. 10:08.000 --> 10:09.000 Nothing. 10:09.000 --> 10:12.000 So these double underscore methods in this case, 10:12.000 --> 10:15.000 we have Dunder add, which is defined for all the other 10:15.000 --> 10:17.000 influx operators as well. 10:17.000 --> 10:19.000 Multiplications, attraction, et cetera. 10:19.000 --> 10:24.000 We can check, well, this is a type of list, 10:24.000 --> 10:27.000 and what we can do, is instead of having the influx operator 10:27.000 --> 10:28.000 between our two lists. 10:28.000 --> 10:30.540 We can go list. caveats.at.at 10:30.540 --> 10:32.500 and get the same result. 10:32.500 --> 10:34.420 And there are many other Dunder methods implemented 10:34.420 --> 10:36.900 in Python, including the doc string, which 10:36.900 --> 10:41.220 will give you what the doc string of the concatenation method 10:41.220 --> 10:45.100 Dunder add is in the Python implementation, 10:45.100 --> 10:48.060 which is overloaded by other things. 10:48.060 --> 10:50.980 For shadowing is a literary device where we can also 10:50.980 --> 10:54.100 use the same logic to check our other concatenation methods. 10:54.100 --> 10:57.100 In this case, we can see that this is a dict. 10:57.100 --> 10:59.380 And if we go Dunder add on a dict, 10:59.380 --> 11:02.740 we can see that it's attribute error. 11:02.740 --> 11:05.220 This is not implemented. 11:05.220 --> 11:07.540 This also explains why the different type errors 11:07.540 --> 11:08.780 were getting different descriptions, 11:08.780 --> 11:11.860 depending on whether we were list forward or dict forward. 11:14.500 --> 11:15.780 Take a drink of water, K. 11:17.380 --> 11:20.260 All right, let's talk about Java. 11:20.260 --> 11:23.260 In Java, if I declare an integer A as 127, 11:23.260 --> 11:26.380 an integer B as 127 is A equal to B. 11:26.380 --> 11:29.300 Hands up the tree, hands up the false. 11:29.780 --> 11:30.940 There we go. 11:30.940 --> 11:32.940 We're learning. 11:32.940 --> 11:34.940 So let's talk about Java. 11:34.940 --> 11:36.980 When you're running Java, you're probably running something 11:36.980 --> 11:38.180 like Open JDK. 11:38.180 --> 11:40.620 And in Open JDK, there is an optimization to create 11:40.620 --> 11:44.780 a list of integers for you from negative 128 to 127. 11:44.780 --> 11:47.580 And if you define it, you can see that it's a little bit of a 11:47.580 --> 11:51.020 value, and you can see that it's a little bit of a value. 11:51.020 --> 11:54.300 And if you define it, you can see that it's a little bit of a value. 11:54.300 --> 11:58.940 And if you define it, you can see that it's a little bit of a value. 11:58.940 --> 12:01.060 And if you define an integer within this cache, 12:01.060 --> 12:03.700 it points to that part of memory. 12:03.700 --> 12:08.380 But in this case, we're using integers and double equals 12:08.380 --> 12:13.500 for capital I integers is identity checking. 12:13.500 --> 12:16.180 And if you declare your integers outside of this case, 12:16.180 --> 12:19.060 you will actually point to other parts of memory. 12:19.060 --> 12:20.860 And these are not the same object and so 12:20.860 --> 12:22.820 and identity check fails. 12:22.820 --> 12:29.740 If you're working with capital I integers in Java, 12:29.740 --> 12:32.260 you need to use dot equals to check for a quality. 12:32.260 --> 12:36.020 But if you drop down to ints, you can actually do double 12:36.020 --> 12:39.660 equals as being a quality. 12:39.660 --> 12:43.340 So Python doesn't have this issue, right? 12:43.340 --> 12:47.020 If I declare in Python, the variable A, as one, 12:47.020 --> 12:51.180 says 256 and B is 256 is AB. 12:51.180 --> 12:54.420 Hands up the true, hands up the false. 12:54.420 --> 12:57.980 It's true, oh my god, there's no trick questions. 12:57.980 --> 13:02.100 If I declare in Python, variable A is 256 and B is 256, 13:02.100 --> 13:03.540 is AB. 13:03.540 --> 13:06.860 Hands up the true, hands up the false. 13:06.860 --> 13:08.900 Great, but if I declare it on the same line 13:08.900 --> 13:10.020 and then check again, they are. 13:13.020 --> 13:15.820 Let's talk about Python. 13:15.820 --> 13:17.660 In Python, when you load the interpreter, 13:17.660 --> 13:20.740 you're probably using C Python and an optimization of C Python 13:20.740 --> 13:26.140 is to create a list of integers from negative 5 to 256 for you. 13:26.140 --> 13:27.460 And when you assign that variable, 13:27.460 --> 13:30.020 it can point to that part of memory. 13:30.020 --> 13:32.420 So when we declare A and B is 256, where 13:32.420 --> 13:34.380 point is you're that same part of memory. 13:34.380 --> 13:37.460 And if we ask for is, it's an identity check. 13:37.460 --> 13:38.700 These actually are the same thing, 13:38.700 --> 13:41.180 not that they're represented values are equal. 13:41.180 --> 13:42.980 Is this the same thing? 13:42.980 --> 13:44.620 And in this case, they are. 13:44.620 --> 13:48.260 But if we declare our variables outside of this interjudication 13:48.260 --> 13:50.620 range, we're assigning them to different parts of memory. 13:50.620 --> 13:54.060 And so they are not the same object except if you define them 13:54.060 --> 13:57.860 on the same line and optimization only allocates the memory 13:57.860 --> 13:58.660 once. 13:58.660 --> 14:04.100 And so when identity checks exceeds, the way to avoid this 14:04.100 --> 14:05.380 in Python is simple. 14:05.380 --> 14:08.460 Don't use is, is equals? 14:08.460 --> 14:11.300 If you want to check it for a quality use of quality, 14:11.300 --> 14:14.580 a quality double equals, a quality is the same in every language 14:14.580 --> 14:15.460 right. 14:15.460 --> 14:18.980 Let's talk about Pell. 14:18.980 --> 14:21.780 In Pell, if I want to check if the string A is equal 14:21.780 --> 14:23.900 to string B, I can do a print statement 14:23.900 --> 14:25.620 and tell me if they match or not. 14:25.620 --> 14:28.260 So who thinks that this will print match? 14:28.260 --> 14:30.380 Who thinks that this won't print anything? 14:30.380 --> 14:31.380 What do you mean A is equal to B? 14:34.660 --> 14:39.220 In Pell, if we want to check for numeric equality, 14:39.220 --> 14:40.860 then we use double equals. 14:40.860 --> 14:46.260 And in this case in Pell, it will cast both sides to numbers. 14:46.260 --> 14:48.460 So if we actually want to do string equality in Pell, 14:48.460 --> 14:50.140 we should use EQ to make sure 14:50.140 --> 14:54.180 that we're actually working in the type we meant. 14:54.180 --> 14:56.540 Let's talk about Bash. 14:56.540 --> 14:59.780 In Bash, I can use conditions to test values. 14:59.780 --> 15:03.940 So I can do if A is equal to B, then print match, 15:03.940 --> 15:05.300 otherwise print nothing. 15:05.300 --> 15:07.540 Who thinks this will print match? 15:07.540 --> 15:09.180 Who thinks this won't? 15:09.180 --> 15:12.300 What do you mean by match? 15:12.300 --> 15:18.420 Because in Bash, EQ and N E are arithmetic binary operators. 15:18.420 --> 15:21.860 Because they will cost the things as if they were numbers. 15:21.860 --> 15:24.300 And in this case, A and B both cost 10 to 0 15:24.300 --> 15:25.500 and so they're the same. 15:25.500 --> 15:30.540 So in Bash, you should use double equals for string equality. 15:30.540 --> 15:34.780 Double equals this is the same everywhere, y'all. 15:34.780 --> 15:38.180 So does Python have this particular issue? 15:38.180 --> 15:42.020 Well, at the very least, double equals and done the EQ. 15:42.020 --> 15:42.940 They're the same. 15:42.940 --> 15:44.220 They're the exact same thing. 15:44.220 --> 15:46.700 So we don't have to worry about that. 15:46.700 --> 15:48.500 But what does this actually do? 15:48.500 --> 15:55.580 Well, by default, object implements done to EQ as an identity check. 15:55.580 --> 16:03.220 It's on to the lower level of objects to define what EQ means for them. 16:03.220 --> 16:06.820 Different standard types will override this implementation, 16:06.820 --> 16:08.780 depending on what's logical. 16:08.780 --> 16:11.620 So maybe for some complex class that you've had 16:11.620 --> 16:13.500 you'd implement your own words like check 16:13.500 --> 16:15.340 that the first and last name of the same 16:15.340 --> 16:17.740 and then this is the same person or something like that. 16:17.740 --> 16:20.260 You can override this. 16:20.260 --> 16:25.460 But we had overriding with just using the standard language. 16:25.460 --> 16:26.740 We had some problems. 16:26.740 --> 16:31.620 Thankfully, had let's talk about Python 2. 16:31.620 --> 16:36.980 In Python 2 is 4 less than 2. 16:36.980 --> 16:39.660 No, okay, so Python 2 knows math, great. 16:39.660 --> 16:41.860 So we know that 4 is greater than 2. 16:41.860 --> 16:43.900 Yes, okay, excellent. 16:43.900 --> 16:48.100 So it's 4 greater than the string 2. 16:48.100 --> 16:50.060 No. 16:50.060 --> 16:54.100 So the string 4 is that greater than 2? 16:54.100 --> 16:56.500 Well, yes, let's keep going. 16:56.500 --> 17:00.100 Is 4 less than a list of just 4? 17:00.140 --> 17:03.540 Yes, is it also less than a string of 4? 17:03.540 --> 17:07.780 Yes, is it also less than a two pull of just 4? 17:07.780 --> 17:09.660 Yes. 17:09.660 --> 17:13.180 Let's talk about Python 2. 17:13.180 --> 17:15.940 Python 2 7 defines comparisons thusly. 17:15.940 --> 17:18.700 Objects are different types, except different numeric types 17:18.700 --> 17:21.540 and different string types never compare equal. 17:21.540 --> 17:25.300 Subjects are ordered consistently, but arbitrarily, 17:25.300 --> 17:30.420 so that sorting a heterogeneous array yields a consistent result. 17:30.420 --> 17:34.300 A C Python implementation detail of that. 17:34.300 --> 17:37.540 Different types, except numbers are ordered by their type names. 17:41.220 --> 17:49.180 An integer comes before a list, comes before a string, comes before a two pull. 17:49.180 --> 17:53.180 Now, I think we all understand that the way to avoid this 17:53.180 --> 17:54.020 is good. 17:54.020 --> 17:55.020 God, it's been five years. 17:55.020 --> 17:57.500 Please stop using Python 2. 17:57.500 --> 17:59.060 Yes, agreed. 17:59.060 --> 18:00.060 OK, great. 18:00.060 --> 18:00.780 Good. 18:00.780 --> 18:03.260 Yes, OK, great. 18:03.260 --> 18:07.780 If you've only ever had to use Python 3, great. 18:07.780 --> 18:08.300 That's great. 18:08.300 --> 18:10.580 You've never had to deal with this. 18:10.580 --> 18:13.500 Particularly because if you try to do the same thing in Python 3, 18:13.500 --> 18:19.020 you get a type error saying that the less than is not supported 18:19.020 --> 18:22.580 between instances of int and list. 18:22.580 --> 18:26.860 And very helpfully, the Python 3 tutorial says in the data structure 18:26.860 --> 18:30.660 section, rather than providing an arbitrary ordering the interpretable 18:30.660 --> 18:37.180 raise a type error, amazing, excellent, one-less bug bear to worry about. 18:37.180 --> 18:40.100 Let's talk about elixir. 18:40.100 --> 18:44.780 In elixir, if I want to map over a range, and in this case, 18:44.780 --> 18:48.180 for every element in this range, I want to get the square number. 18:48.180 --> 18:51.260 I'd get a list of the first five square numbers. 18:51.260 --> 18:52.860 Yeah, cool. 18:52.860 --> 18:59.220 I did the same thing, but changed the range from 1 to 5 to be 6 to 10. 18:59.220 --> 19:02.620 I guess, wearing. 19:02.620 --> 19:03.740 Well, something's going on here. 19:03.740 --> 19:05.420 Let's investigate further. 19:05.420 --> 19:10.540 If instead, I was to assign the result of this mapping 19:10.540 --> 19:15.980 into a variable, and then iterate over that variable and use IO.puts. 19:15.980 --> 19:19.660 I would get the expected list of numbers. 19:19.660 --> 19:21.940 So what did our first example break in our second one 19:21.940 --> 19:22.620 didn't? 19:22.620 --> 19:24.620 Well, let's try a different range. 19:24.620 --> 19:29.420 Let's say random numbers off the top of my head, 65 to 90, 19:29.420 --> 19:31.340 and we'll just return as is. 19:37.740 --> 19:42.820 For those who aren't familiar with different encoding standards, 19:42.820 --> 19:45.900 good, but also let me teach you that in 8-bit, 19:45.900 --> 19:52.180 variable encoding ASCII, ASCII starts at sequence capital A is 65. 19:52.180 --> 19:54.300 I haven't available 255 characters. 19:54.300 --> 19:59.460 So we get the alphabet, because ASCII is cool. 19:59.460 --> 20:04.460 Alexa was built on top of O-lang, and O-lang dates back to the mid-80s, 20:04.460 --> 20:08.020 and in many languages, strings are just a list of characters, 20:08.020 --> 20:10.940 but in O-lang strings are a list of integers, 20:10.940 --> 20:13.980 representing the ASCII character code points. 20:13.980 --> 20:18.140 So in Elixir, if it sees a list of numbers that look like ASCII code points, 20:18.140 --> 20:20.100 it thinks it's a string. 20:20.100 --> 20:21.900 Cool. 20:21.900 --> 20:24.780 Despite that, have this problem. 20:24.780 --> 20:27.780 In Python, if I import date time from the standard library, 20:27.780 --> 20:30.300 and have a variable now as date time date time now, 20:30.300 --> 20:34.660 and I print the result of now, I get a nicely formatted date 20:34.660 --> 20:37.020 for my particular locale. 20:37.020 --> 20:40.020 And if I ask just for now, I get something 20:40.020 --> 20:43.860 that looks very weird to anyone who's not a programmer. 20:43.860 --> 20:45.140 One of these is human readable. 20:45.140 --> 20:47.340 The other one, Mike, it confusing as it appears printed on, 20:47.340 --> 20:49.980 or it's seek from a coffee shop, ask me how I know. 20:49.980 --> 20:51.460 In this case, when we print, 20:51.460 --> 20:52.900 we're getting the string representation 20:52.900 --> 20:54.340 of an object, something which is readable, 20:54.340 --> 20:55.940 but we don't print. 20:55.940 --> 20:58.620 We're getting the wrapper or representation, 20:58.620 --> 21:01.940 which clearly defines if this is a date time object. 21:01.940 --> 21:03.780 It's important to remember this one, 21:03.780 --> 21:06.540 if you're working in the Python shell or a repal, 21:06.540 --> 21:10.660 or a Python notebook, because if you just try to get the wrapper 21:10.660 --> 21:13.380 of an object as your output, it will not work, 21:13.380 --> 21:14.980 if you try to convert it to a script, 21:14.980 --> 21:18.340 and it may or may not return a different output 21:18.340 --> 21:22.620 to what a string representation would ask me how I know. 21:22.620 --> 21:26.060 Let's talk about PowerShell. 21:26.060 --> 21:27.860 This is the last word. 21:27.860 --> 21:32.340 In PowerShell, if I check, if 36 is greater than 42, 21:32.340 --> 21:35.620 print true or print false, who thinks this will be true? 21:35.620 --> 21:37.620 Who thinks this will be false? 21:37.620 --> 21:39.620 Great, PowerShell understands math, 21:39.620 --> 21:41.540 we all understand math, this is great. 21:41.540 --> 21:44.540 So, if I try the reverse, if I try is 32, 21:44.540 --> 21:47.300 less than 42, who thinks this will be true? 21:47.300 --> 21:49.900 Who thinks this will be false? 21:49.900 --> 21:51.180 Good. 21:51.180 --> 21:52.180 Good. 21:52.180 --> 21:53.180 Good. 21:53.180 --> 21:54.180 Good. 21:54.180 --> 21:55.180 Good. 21:55.180 --> 21:56.180 Good. 21:56.180 --> 21:57.180 Good. 21:57.180 --> 22:02.540 So, PowerShell is a combination, compiler, and interpreter. 22:02.540 --> 22:06.020 And in this case, that is in greater than. 22:06.020 --> 22:08.380 That is file redirection. 22:08.380 --> 22:13.660 I have a file called 42 with the contents of 36. 22:13.660 --> 22:16.300 But in this case, the file redirection operation 22:16.300 --> 22:19.420 was successful and returned to no value, 22:19.420 --> 22:22.380 but because no value is false, the false side 22:22.380 --> 22:24.940 of the conditional was invoked. 22:24.940 --> 22:29.180 So, the powerShell.ca, the greater than operator, 22:29.180 --> 22:32.020 shouldn't be confused with the greater than comparison operator 22:32.020 --> 22:35.500 as often denoted by alligators in other languages. 22:35.500 --> 22:37.300 And then it shows an example. 22:37.340 --> 22:39.820 It shows my example because the powerShell 22:39.820 --> 22:42.580 docks are open source. 22:42.580 --> 22:45.860 I got code and powerShell before I got code and see Python, 22:45.860 --> 22:49.220 Jesus. 22:49.220 --> 22:52.140 The way to avoid this is to use actual comparison operators, 22:52.140 --> 22:54.900 because like powerShell and other languages, 22:54.900 --> 22:57.340 you don't have to remember which way the crocodile goes. 22:57.340 --> 23:00.260 The crocodile eats the bigger number. 23:00.260 --> 23:03.300 So, despite then have this issue. 23:03.300 --> 23:06.140 In Python, if I check if 36 is greater than 42 in print, 23:06.140 --> 23:07.780 the result would get false. 23:07.780 --> 23:09.700 Go in the other way, we get true. 23:09.700 --> 23:11.260 And we can check our local file system. 23:11.260 --> 23:13.500 Great, no files were created. 23:13.500 --> 23:20.300 Except, we've just proven the case for integers. 23:20.300 --> 23:22.020 What about other objects? 23:22.020 --> 23:28.020 In Python, if I declare a dictionary of A1 and a dictionary of B2, 23:28.020 --> 23:30.460 what is A pipe B? 23:30.460 --> 23:35.580 It's a union, because we have unions now as of Python's 3.9 23:35.580 --> 23:38.100 and if you're using a version older than Python 3.9, 23:38.100 --> 23:38.900 please upgrade it. 23:38.900 --> 23:40.500 You have no more security updates. 23:40.500 --> 23:43.260 3.9 is great. 23:43.260 --> 23:45.260 But this is a new in-fix operator 23:45.260 --> 23:48.780 as per a newer version of Python. 23:48.780 --> 23:51.980 But there are other in-fix operators that do strange things, 23:51.980 --> 23:54.460 such as ParkLib. 23:54.460 --> 23:58.820 If I import Park from ParkLib and I define P as a path, 23:58.820 --> 24:03.340 and I put this path between two normal strings, 24:03.340 --> 24:06.740 I get a possex path. 24:06.740 --> 24:09.660 And if I take a string or stringy type object 24:09.660 --> 24:14.140 and redirect that into that path, I get a type error. 24:14.140 --> 24:18.300 For now, there's nothing stopping us 24:18.300 --> 24:21.900 from implementing this in later versions. 24:21.900 --> 24:23.020 We've gone through a number of things, 24:23.020 --> 24:25.580 but hopefully you've learned something new. 24:25.580 --> 24:27.820 And the curious with other programming languages, 24:27.820 --> 24:29.580 if you're a Python purest, great, 24:29.580 --> 24:31.300 but I know a bunch of different languages, 24:31.300 --> 24:33.860 it's helped me understand more about Python along the way. 24:33.860 --> 24:34.940 Resources are up there. 24:34.940 --> 24:35.940 I'm out of time. 24:35.940 --> 24:36.860 Questions outside? 24:36.860 --> 24:37.860 Cheers.