Hello Kitty, so Kitty will explain some particularities of Python and because Python was based
on some other languages and maybe...
There's my Python in this talk.
OK, it's for a spell or something like that.
Oh my gosh.
I'm not in the good room, sorry, bye.
OK, hello everyone, let's talk about JavaScript.
In, I think I have 25 minutes.
In JavaScript, what is 4 plus 2?
It's 6, what is 4 minus 2?
It's 2, what is 4 minus the string 2?
It's 2, so of course, 4 plus the string 2 is 42.
Let's talk about JavaScript in JavaScript is 1 equal to the string 1.
Hands up for true, hands up for false.
It's true, but if you add an extra equals, it's true, it's false.
It's fine, everything's fine.
Let's talk about JavaScript in JavaScript.
What is the sum of 2 empty arrays?
It's an empty string, what's the sum of an empty array and an empty object?
Object objects, what about the sum of an empty object and an empty array?
Zero, what about the sum of 2 empty objects?
Not a number!
Ah, I see you have seen this talk before.
Oh, Gary Bernhardz, what's talk?
Which is now over a decade old?
I'm sorry.
It was from 2012.
That talk goes on the wats.
I want to do something more.
I want to talk about the wats.
We're going to focus on the wide during this talk and work out.
What the heck was all that?
But well, specifically, does Python have the same problems?
Woo!
In this example, it's an issue of overloaded operators.
The first one we have implicit coercion.
Subtraction is only defined for numerics.
So it coerses the string into a number.
The second one, it's the plus operator that is overloaded.
It can act as both numeric addition or in this case, string concatenation.
In JavaScript, double equals will only compare the values after it coerses it into the same type.
That triple equals will also confirm that the types it equal and exit early if they're not.
And our third case is a little bit more complicated than this.
So to explain this, we're going to have to dive more into the addition operator.
What is it exactly?
Well, thankfully, we have a way to know exactly what the plus does in JavaScript.
Thanks to AgmasScript 2024 standard specification as defined by ECMA262.
This is a standard that defines the JavaScript you use in the browser today,
and it covers JScript as well as actionscript.
And within that standard, we can go into section 138.1,
which denotes the week and then go into the runtime semantics,
which then denotes the week and go into a value,
it's string on numeric binary expression.
If we go there, it says apply string on numeric binary expression.
And from there, it says exactly what we need to do.
Just that.
Now, if a language has a standard, you probably won't learn how to use the language by trying to read this.
So, but for our purposes, it's useful to see like what a standard looks like,
but let me simplify this down.
Consider the addition of two placeholder values A and B.
Step one, convert A and B to primitives.
If after converting A or B are a string, then can cadinate them together.
Otherwise, convert both to numbers and then return the operation in this case plus,
who can see where the problem starts.
To primitive is also its own separate defined method,
where if it is an object, then first try to get the value of that object.
And if that itself is not an object, then return it.
Otherwise, can't the object to a string.
And then return it, and if it wasn't an object in the first place,
then you'll find you're already in a primitive.
So, let's try one of our examples, empty array and empty object.
According to our algorithm, the first thing we need to do is convert both to primitives.
So, bringing up that algorithm, we start by converting the empty array into a primitive.
So, we try the type of, which is an object, so we have to go further,
and so we check the value of.
And the value of an empty list is an empty list,
and if we cast that to a string, it's an empty string.
Well, how does that work?
Well, this is defined because if you take an array and you go to string on it,
it calls the join of all the elements in that string.
So, if we join the array 1, 2, 3, we'll get 1, 2, 3,
and if it's an empty string, empty list, it will be an empty string.
This makes sense.
So, we can do the exact same thing to object.
We first check what's the type of an object, it's an object,
and what is the value of that?
Well, it's still the same squiggly brackets, hello again,
and then if we try to cast that to a string, of course, we get object object.
Well, how does that happen?
Well, again, it's defined.
If you call two string from an object,
the method will return the string object tag,
where tag is determined by the object type,
or in this case, literally, the string object.
So, in JavaScript, any time you try to do a two string on an object,
and you get this, mostly in your console error logs,
that is what is supposed to happen.
A lot of programming languages will instead have this type of method,
give a string-based representation of the contents of the object,
but here, it's hopefully telling you, yes, I am object.
You can use Core JavaScript to get the contents of an object
by using stringify.
Instead, JSON.stringify will give you a stringy representation
of the contents of an object.
So, we know what the primitive types for our two objects are,
and so we can start putting them together.
We can concatenate an empty string, an empty object,
and so we know that the concatenation of an empty list,
an empty object, is object object.
Great, and we can do the same thing for two empty lists.
We can concatenate their two primitive together,
and we know that it's an empty string.
But what about the other permutations?
Because we know that they don't match,
and we would presume that, in JavaScript,
addition would be commutative, A and B
as the same as B plus A.
So, based on our knowledge, we know that something's not right here.
But guess what?
That's defined in this specification.
Well, because in the runtime semantics,
it says what to do if you have an empty object,
or in this case an empty block, is to return empty.
So, when we have an empty object here,
that's actually being interpreted as an empty block.
So, when we try to do anything with an empty block,
it actually does unary addition,
which tries to then, as per the specifications,
cast it to a number.
And in this case, we know that the primitive,
this is an empty string, an empty string, is falsely,
and so it's zero.
And that is actually defined as what happens
when you have a white space, this term is zero.
So, if we try to do the same thing with our objects,
we're trying to add together two objects,
which is actually an empty block,
and a unary addition of an object,
and we know that the primitive of the object
starts with a bracket, which is not a number.
And therefore, we have our entire collection of things
that we know exactly what's going on, except I cheated.
Earlier, I was wrapping the objects in parentheses
to make sure that I could actually get the value of an empty object,
as a switch to an empty block.
And so, this original example will run correctly
if you actually use variables,
and not just throw this in a repel,
because those last two examples are doing strange things.
So, you can actually preserve community
if you use parentheses.
Ta-da!
So, now's the question.
Does Python have this particular peculiarity?
Is Python prone to the same potential problem, perhaps?
Well, in Python, what is the concatenation of two empty lists?
It's an empty list.
What about the concatenation of an empty list, an empty dictionary?
It's a typo.
What about the concatenation of an empty dictionary, an empty list?
It's a typo.
What about the concatenation of two empty dictionaries?
It's a typo.
But different typoers.
So, to see what's going on here,
we're going to have to look at the Python standard.
Now, Python, like a few modern programming languages,
doesn't have a capital S standard.
Some languages have standards, held by bodies like ISO,
ECMA, I tribally, etc.
But some have defector standards.
In PHP, we have Python enhancement proposals,
and we have the defector standard,
which is the C-Python implementation of Python,
which we can reference.
And in C-Python, there is the Python standard library.
And within that, there is documentation for sequence types,
that being list, tuple, and range.
And within that, it includes that the plus parameter
does concatenation of two types.
And if we were to search the source code for this error,
can only concatenate list.
We would get the C-Python C implementation of
what list concatenation does.
And the first thing it does is goes, if B is not a list,
and we can also see this within Python itself
in a roundabout way, because the Python language
refers to special method names,
also known as double underscores,
Australia, Dundah, nana, nana, nana, nana, nana, nana.
So these double underscores methods in this case,
we have Dundah add, which is defined for all the other
in fixed operators as well,
multiplication, subtraction, etc.
We can check, well, this is a type of list,
and what we can do is instead of having the in fixed operator
between our two lists, we can go list.
Dundah add our two lists and get the same result.
And there are many other Dundah methods implemented in Python,
including the doc string, which will give you
what the doc string of the concatenation method
Dundah add is in the Python implementation,
which is overloaded by other things.
For shadowing is a literary device, where we can also use
the same logic to check our other concatenation methods.
In this case, we can see that this is a dict,
and if we go Dundah add on a dict,
we can see that it's attribute error.
This is not implemented.
This also explains why the different type errors
we're getting different descriptions depending on whether we
will list forward or dict forward.
Take a drink of Watergate.
All right, let's talk about Java.
In Java, if I declare an integer A as 127,
an integer B as 127 is A equal to B,
hands up for true, hands up for false.
Guys, come on.
In Java, if I declare an integer A as 128,
and B as 128 is A equal to B, hands up for true,
hands up for false.
There we go. We're learning.
So let's talk about Java.
When you're running Java, you're probably running something like OpenJDK,
and in OpenJDK, there is an optimization to create
a list of integers for you from negative 128 to 127,
and if you define an integer within this cache,
it points to that part of memory.
But in this case, we're using integers,
and double equals for capital I integers,
is identity checking.
And if you declare your integers outside of this case,
you will actually point to other parts of memory,
and these are not the same object,
or identity check fails.
If you're working with capital I integers in Java,
you need to use dot equals to check for a quality,
but if you drop down to ints,
you can actually do double equals as being a quality.
So Python doesn't have this issue, right?
If I declare an Python, the variable A as one,
there's 256 and B as 256 is AB.
Hands up the true, hands up the false.
It's true, oh my god, there's no trick questions.
If I declare in Python, variable A is 256 and B is 256 and AB.
Hands up the true, hands up the false.
Great, but if I declare it on the same line,
and then check again, they are.
Let's talk about Python.
In Python, when you load the interpreter,
you're probably using C Python,
and an optimization of C Python is to create a list of integers
from negative 5 to 256 for you,
and when you assign that variable,
it can point to that part of memory.
So when we declare A and B is 256,
where point is to that same part of memory,
and if we ask for is, it's an identity check.
These actually are the same thing,
not that they're represented values are equal,
is this the same thing,
and in this case, they are.
But if we declare a variables outside of this integer case range,
we're assigning them to different parts of memory,
and so they are not the same object except,
if you define them on the same line,
and optimization only allocates the memory once,
and so when identity checks exceeds,
the way to avoid this in Python is simple.
Don't use is, is equals.
If you want to check it for a quality user quality,
a quality, double equals,
a quality is the same in every language, right?
Let's talk about Pell.
In Pell, if I want to check if the string A is equal to string B,
I can do a print statement and tell me if they match or not.
So, who thinks that this will print match?
Who thinks that this won't print anything?
What do you mean A is equal to B?
In Pell, if we want to check for numeric equality,
then we use double equals, and in this case in Pell,
it will cast both sides to numbers.
So, if we actually want to do string equality in Pell,
we should use EQ to make sure that we're actually working in the type we meant.
Let's talk about bash.
In bash, I can use conditions to test values,
so I can do if A is equal to B, then print match, otherwise print nothing.
Who thinks this will print match?
Who thinks this won't?
What do you mean by match?
Because in bash, EQ and N E are arithmetic binary operators.
Because they will cast the things as if they were numbers,
and in this case A and B both cast down to zero and so they're the same.
So, in bash, you should use double equals for string equality.
Double equals the same everywhere, y'all.
So, does Python have this particular issue?
Well, at the very least, double equals and done to EQ, they're the same.
They're the exact same thing, so we don't have to worry about that.
But what does this actually do?
Well, by default, object implements done to EQ as an identity check.
It's onto the lower level of objects to define what EQ means for them.
Different standard types will override this implementation, depending on what's logical.
So, maybe for some complex class that you've had, you'd implement your own words,
like check that the first and last name of the same and then this is the same person or something like that.
You can override this.
But we had overriding, with just using the standard language.
We had some problems.
Thankfully, had.
Let's talk about Python too.
In Python too, is full less than 2?
No, okay, so, called Python 2 knows math.
Great. So, we know that 4 is greater than 2.
Yes, okay, excellent.
So, is 4 greater than the string 2?
No.
So, the string 4 is that greater than 2?
Well, yes, let's keep going.
Is 4 less than a list of just 4?
Yes.
Is it also less than a string of 4?
Yes.
Is it also less than a 2 pull of just 4?
Yes.
Let's talk about Python 2.
Python 2 7 defines comparisons thusly.
Objects are different types, except different numeric types, and different string types, never compare equal.
Subjects are ordered consistently, but arbitrarily, so that sorting a heterogeneous array yields a consistent result.
A C Python implementation detail of that.
Different types, except numbers are ordered by their type names.
An integer comes before a list, comes before a string, comes before a tuple.
Now, I think we all understand that the way to avoid this is,
God, it's been 5 years, please stop using Python 2.
Yes.
Agreed?
Okay, great.
Good.
Yes.
Okay, great.
If you've only ever had to use Python 3, great.
That's great.
You've never had to deal with this.
Particularly because if you try to do the same thing in Python 3, you get a type error.
Yeah.
Saying that the less than is not supported between instances of and list.
And very helpful.
The Python 3 tutorial says in the data structure section, rather than providing an arbitrary ordering the interpretable raise a type error.
Amazing.
Excellent.
One last bugbear to worry about.
Let's talk about elixir.
In elixir, if I want to map over a range, and in this case, for every element in this range, I want to get the square number.
I'd get a list of the first 5 square numbers.
Yeah?
Cool.
I did the same thing, but changed the range from 1 to 5 to be 6 to 10.
I guess, wearing.
Well, something's going on here.
Let's investigate further.
If instead, I was to assign the result of this mapping into a variable.
And then iterate over that variable and use IO.puts.
I would get the expected list of numbers.
So, what did our first example break in our second one, didn't?
Well, let's try a different range.
Let's say random numbers off the top of my head are 65 to 90.
And we'll just return as is.
For those who aren't familiar with different encoding standards, good.
But also let me teach you that in 8-bit variable encoding ASCII, ASCII starts at sequence
capital A is 65.
I haven't available 255 characters.
So, we get the alphabet.
Because ASCII is cool.
Elixir was built on top of Erlang, and Erlang dates back to the mid 80s.
And in many languages, strings are just a list of characters, but in Erlang strings are a list of
integers representing their ASCII character code points.
So, in Elixir, if it sees a list of numbers that look like ASCII code points, it thinks it's a string.
Cool.
Despite that, have this problem.
In Python, if I import date time from the standard library and have a variable now as date
time date time now, and I print the result of now, I get a nicely formatted date for my particular locale.
And if I ask just for now, I get something that looks very weird to anyone who's not a programmer.
One of these is human readable.
The other one might confuse as it appears printed on or received from a coffee shop ask me how I know.
In this case, when we print, we're getting the string representation of an object something which is readable, but when we don't print,
we're getting the rep or representation, which clearly defines that this is a date time object.
It's important to remember this one if you're working in the Python shell or a rep or a Python notebook.
Because if you just try to get the rep of an object as your output, it will not work if you try to convert it to a script.
And it may or may not return a different output to what a string representation would ask me how I know.
Let's talk about PowerShell.
This is the last word.
If I check if 36 is greater than 42, print true or print false, who thinks this will be true?
Who thinks this will be false?
Great. PowerShell understands math. We all understand math. This is great.
So if I try the reverse, if I try it is 32, less than 42, who thinks this will print true? Who thinks this will print false?
So PowerShell is a combination compiler and interpreter. And in this case, that is in greater than.
That is file redirection.
I have a file called 42 with the contents of 36.
But in this case, the file redirection operation was successful and returned to no value.
But because no value is false, the false side of the conditional was invoked.
So the powerShell.ca, the greater than operator, shouldn't be confused with the greater than comparison operator as often denoted by alligators in other languages.
And then it shows an example.
It shows my example because the powerShell docks are open source.
I got code and powerShell before I got code and see Python, Jesus.
The way to avoid this is to use actual comparison operators because like powerShell and like other languages, you don't have to remember which way the crocodile goes.
The crocodile eats the bigger number.
So, does Python have this issue?
In Python, if I check if 36 is greater than 42 in print, the result we get false.
Go in the other way, we get true and we can check our local file system, no files were created.
Except, we've just proven the case for integers.
What about other objects? In Python, if I declare a dictionary of A1 and a dictionary of B2, what is a pipe B?
It's a union, because we have unions now as of Python's 3.9 if you're using a version older than Python 3.9, please upgrade it.
You have no more security updates, 3.9 is great.
But this is a new in-fix operator as per a newer version of Python.
But there are other in-fix operators that do strange things, such as ParkLib.
If I input ParkLib and I define P as a path and I put this path between two normal strings, I get a possex path.
And if I take a string or stringy type object and redirect that into that path, I get a type error for now.
There's nothing stopping us from implementing this in later versions.
We've gone through a number of things, but hopefully you've learnt something new.
And, be curious, with other programming languages, if you're a Python purest, great.
But I know a bunch of different languages, it's helped me understand more about Python along the way.
Resources are up there, I'm out of time, questions outside, cheers.