 So this talk is about math. Well, it's about algebra actually and it's a little bit about cats They're providing the visuals So I I thought it'd be rude not to mention the cats. They're they're quite central So I'm Chris Hoffman in real life, and I'm on the internet. So I'm yarn McGonoska at a variety of places And I work for up Toro, and if you're junior developer, you should too we're an e-commerce firm in DC and we're quite fantastic Yeah, so we're gonna be talking about numerical coercion and It's kind of a scary thing, but it's it sounds scary. I mean Corrosion that that's not a good. That's not a good word, but it's it's not it's not that frightening Basically It's how Ruby deals with with unfamiliar math So does anyone know what would happen if we tried to multiply a number by a range or a hash or a fruit bet? so here we're trying to multiply two times the range one one one to three and It says That's Ruby's polite way of asking. Do you are you sure you know what you're doing because I don't that doesn't work But we can derive some meaning from the air We get a type error indicating that there's a fundamental incompatibility between what we want to do and what and what the class is Ruby and what the class is support by default and it also tells us that the thing range can't do is to be coerced Which gives us a hint of where to look so we do some googling and then we we eventually get to this Which is the ruby lang dot org core docs for course On two one two Now the text is kind of useless here. It doesn't really tell you a lot So I'll give you the TLDR when you send the course message to a numeric object With why is the argument? It only takes one argument Ruby expects the course method to return an array of two elements and it expects these elements to be Compatible and we'll explain what compatible means in a minute with some code samples because they are the actual useful portion of this documentation So here the integer receiver One is being asked to course two point five and in that case two point five doesn't course to an integer But one course is to a float so it returns an array of two point five and one point zero Here Of the float one point two is being asked to course three and three does course to a float So we return so it returns the array three point zero one point two Here The integer one is being asked to course the integer two and that works out just fine It doesn't actually need coercion, but it's useful to Show the reversal behavior of This operation the first number in the array is going to be the one the type of the first number in the array Should be the type that you want the entire operation to course to which is why here, sorry We course to floats Some some more examples involving some more of the esoteric Numeric types in ruby here. We're coursing the integer four and it beat with a complex and it becomes the complex number four plus zero i Here we're coursing the rational four and it becomes four over one Here we're coursing We want the rational one half to course four point five and that courses to a float Here we're coursing The they're at the float four point five to a complex and it becomes a complex with a float as the first argument So now we all have a basic understanding of how numerical coercion works We're going to talk about vectors as they are a a great use case for numerical coercion So vectors are a mathematical object that are ludicrously common in all the sciences I actually don't know if you can do physics without vectors like I'm pretty sure it's not possible unless you're Even in one dimension you'd still need them So what they are is that they wrap a magnitude and a direction So we're going to have some examples of scalars and vectors. So things like population area volume battery percent in all our phones how loud I am and and and the pressure that my Voice is pushing against the microphone are all Non-directed numbers population doesn't have a direction Volume doesn't have a correction direction. So these are called scalars Things like velocity things on the right-hand side like velocity or acceleration or momentum. They do have they do have a direction And so they're vectors Vectors are routinely represented graphically as arrows because it's very easy because it makes it very easy to understand That two pieces of information are encoded here the magnitude that this which is the length of the arrow in the direction That's the direction the arrow is pointing in there is a ubiquitous representation of vectors And also leads us to the most common notation for vectors, which is which is not actually treating them as a magnitude and a direction but Treating them in orthogonal components in this case along an x and y axis One of the other mathematical properties of vectors is they can be scaled and that's why we're calling our non-directed numbers scalars because they scale vectors They can be scaled by regular numbers. So basically integers floats rationals and irrationals This scaling only affects the magnitude and does not affect the direction. So it simply makes the vectors longer or shorter In this in this case we're scaling the vector on the left by a factor of three halves to produce the vector on the right So can we do that in Ruby, I mean it sounds pretty simple It sounds like a value object that encapsulates a couple of a couple of coordinates and has some interesting multiplication behavior a Look, it's a value object that has some weird behavior related to multiplication It's almost like I share Sandy's ability to predict the future Let's look at how this works So first we're going to instantiate a vector class that has three that has that has three units on the x-axis and four units along Y-axis I didn't specify that in this class But let's just assume that it's a two-dimensional error like the one I was showing a little earlier And we want to scale it by two Two is a good number So here's what happens We have the We have the two times V and then what happens there is that Ruby says I don't know how to multiply two by a vector Help hopefully or it helpfully rather we have for well hopefully and helpfully actually we've provided a course definition On in our vector class So what happens is that V is asked to course to and I'm just having reduced by multiplication here for to store the The operation of multiplication somewhere Ruby doesn't actually use reduced to do this internally, but it's a nice Ruby land description of it So What happens when we course to is that we return an array of V and then the number and the reason we do that is that Ruby then Ruby then Ruby then basically reduces with multiplication and passes and calls multiplication on V and passes it to and Luckily, we've also defined a multiplication operation that returns a new vector that is twice well in this case twice as big So here's that Here is actually some code that makes the title of the talk actually compute So we have a cloud or object that contains a splatted array of cats Don't worry. No cats were harmed in the making of this talk via splatting It coerces By when we give it a number it takes that number and returns an array of that and the number of oz And the number of oz is a map reduce with addition over each of the cats in the cloud or We have a cat class to supply cats to the cloud or and each of them has Allows humans to Say one awe per cat. So they're relatively surly cats or or cats And then we have a cuteness class which initializes with default quantity of cuteness in this case being one and then courses just as though It's a number So we say cats equals cloud or not new cat a new cat a new we say cute equals cuteness done new and then we Compare two plus cats and four times cute and I will show how that works So we we have it it's going to be true spoilers But here's how it works again with the with the helpful colorful boxes When we do two plus cats cats is then as to course two and it reduces with addition similarly on the right-hand side Cuteness the cuteness object is as to course four and reduces via multiplication the definition for There the definition for course on the cloud or object is to map reduce the oz for each cat Which is clearly shown in the red box in the left in the big red box on the left-hand side We're still we're still reducing with multiplication or addition rather on the left hands on the right-hand side We are Reducing the cuteness object and that one's going to resolve more quickly because it's more simple We still have the two on the left hand side We still have the two we the the one one array is indicating that we have two cats and each one has One awe and it's still and it's reducing by addition Similarly on the left on the right-hand side the quantity of cuteness is has reduced to one or has course to one And it's still reducing by multiplication We're now reducing this is the actual reduction of the number of oz in the cloud or with addition and On the on the right-hand side you can tell it's just become straight-up math again And this is going to end pretty quickly Then one plus one is two and four times one is one or is four times one is four rather And then we get to two plus two and then four equals four and then that's true and because you've all been very good Here's a adorable remote hogging cat Now I'm going to talk about dimensional analysis another another math thing This is not dimensional analysis The proper response to that picture is this because it's a black hole and they're terrifying Dimensional analysis is the simplification in conversion. It is the analysis of the dimensions of measurements. What the heck does that mean? So let's talk about what let's Give some examples of the measurements So some measurements are basically things you can measure 60 miles an hour 88 feet four inches, which is how tall I am 2.7 gigahertz or 9.8 meters per second squared, which is how fast I fall When I jump at the earth's surface on Mars it would be different So measurement is anything with a unit kind of makes sense And dimensional analysis is the simplification and conversion of measurements It is simplification of a complex unit to a more simple one hence simplification or the conversion between between units So here's an example. We're converting 10 meters over 10 meters per second to Kilometers per hour and we do it in three steps. We first convert meters to minutes That's the top line or we first convert seconds to minutes. That's the top line And then we convert Minutes to hours and then we finally convert meters to kilometers. So this this is a conversion process Is that not showing? God damn it. There's some math there It's invisible So here we're determining how far our massed object will fall in a vacuum at the earth's surface in the span of point Zero one minutes or a normal people numbers three-quarters of a second. It turns out would fall about six feet I will note one important thing here, even though you can't see the math the negative sign in the answer is Is actually very important and it should not just be discarded. It's a it's it indicates the direction of the vector It's pretty cool in that we don't need to remember or know that gravity goes downward The negative sign just falls out of the math. I think that's really cool It would be much cooler if we had, you know actual SVG's So where's the ruby? Here's the ruby so This is a bit of a shameless plug, but I Wanted to be able to do dimensional analysis in ruby the way it felt like doing it on paper So I wrote a library called unitary That would allow you to do that in here, we're doing We're setting up the speed to be five miles per hour except we're writing it kind of weird We're writing it as a multi as five being multiplied by The symbol mi to denote miles divided by the symbol HR to denote hours and that's really strange I'm dividing and multiplying symbols here. That's that's craziness and I'm doing it again on the next line I get to get to get what what represents six hours But then when we multiply speed times time will actually get 30 miles with with this library the hours will cancel out essentially Which is even stranger symbols don't cancel out. That's crazy talk The second example is is a little is also pretty simple We have a length of two kilometers and then if we square it it were asserting We're comparing it to four times four kilometers squared And then if we cube it we're comparing it to eight kilometers cubed and the math all works out and Here's how we did that or I did that The first part of the code is pretty much we require a bunch of stuff And then we and then we include something into symbol don't ever do this in production It's a hideously bad idea, but it's very very cool So we include some simple unless your rails are active support and then just totally yeah do that Fine So we include some this this module into symbol and as you can see the first big headline method is we have a course method So now when we try to multiply six by a symbol it Ruby at least has some idea of what to try to do And what it does is it returns an array of two quantities or sort which are also objects introduced by this library And the first quantity is going to be Quantity with the so quantities in this library have a size and a dimension and the size is the size the number Sorry five or the number six or two and Then the dimension is going to be derived from the symbol But in this case we have the quantum the first quantity just been having a number It was basically a size and node and no dimension So no unit and then the second quantity having unit size so one and then the and then the dimension So we're because the course requires us to return the array of two elements We're basically splitting the part quantity into two parts and having on one hand the the number on the other hand the unit And then and then once it once it does that we've also defined Multiplication division and exponentiation on symbols to tell it how to combine them This next slide is how quantities combine It's a little complicated and not the best written thing in the world. There's a large case statement But when you combine it with itself You're combining your size and the quantity size and your dimension the quantities dimension when you're combining it with just a Numeric you just multiply by the size by the quantity Allah our vector friends earlier and then when you're multiplying it by another symbol or another dimension then you just add to your to the current dimension Similarly, we have Division is Defined simply as the inverse of multiplication and exponentiation is just defined as repeated Multiplication the other cool thing is that you can't add miles per hour and Mega watts like that that doesn't make sense and similarly the library says it raises an incompatible dimension addition And less the dimensions equal each other This is how dimensions course you can yeah, they they also return an array of two quantities and They when you multiply dimension Multiplies dimension when you give it a symbol it turns it multiplies it by a unit and then when you multiply it by numeric It just multiplies it by a numeric The cool thing is that it will cancel out as you saw the hour stuff So once it's done the multiplication it has a process where it finds any so the exponents are The exponents are represented by a hash where the key is mi or HR and the value is the exponent there So when it's miles per hour That's a hash of mi to 1 HR to negative 1 and only we when we multiply it by the 6 hours The we have then have hours and they reduce the addition So they turn into HR 0 and then there's a there's a pass after the multiplication that takes out all the zeros Because they don't make sense in real life So other coercion uses There are many You can do unit conversion a dimensional analysis You can do currency manipulation and conversion, which is kind of unit conversion and dimensional analysis just with monies You can do math or maths for any Brits in the room And the last one is I'm lying. There are no other uses for conversion for coercion It is entirely for doing cool math in The thing is that Ruby isn't very good at representing math the way we think of it in the real world Or the way we write in on whiteboards. It's abysmal at it We end up with these value objects and code like the stuff I just showed you that looks impenetrable and God, what are you doing here? But wouldn't it be cool If we could do stuff like this if we could compose functions with multiplication or could scale functions with with numbers or could do chemical equations and Just add two NAs and two CLs to get two salts or it could do four dot dollars equals six point five dot euros the cool thing is with the exception of The first two and you would just need a little syntactic sugar to make that work. You can do all these things You can do these you can do more you can do things. I haven't thought of You can do things I would not occur to me to think of I like math I don't like chemistry and yet I came up with the chemistry example if I mean There are way more things to do with numerical coercion than I've shown here The resources for it are relatively slim on the other hand. It is not the subject of the Ruby blogging Industrial establishment and and has relatively few blog posts. I couldn't find any from before 2012 Though I guess it hasn't changed that much. So I could have gone earlier A guy named Seamus Abchear has a conversions library that will pretty much let you do the thing that I wrote on the last Line of the previous slide, which is four dot dollars equals six point five dot euros and His approach was a little different than mine He just did active support style methods for just tacking on the the unit to a numeric My library unitary, which you shouldn't ever use in production again Is available on github as well and the docs are available where they are and Again, I'm Chris Hoffman and so go do course