We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.
Feedback

Eliminating branching, nil and attributes

00:00

Formal Metadata

Title
Eliminating branching, nil and attributes
Subtitle
Let's get weird
Title of Series
Number of Parts
50
Author
License
CC Attribution - ShareAlike 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this
Identifiers
Publisher
Release Date
Language
Producer
Production PlaceMiami Beach, Florida

Content Metadata

Subject Area
Genre
Abstract
Although "being OO" isn't an end unto itself, we can often learn a great deal about programming by taking things to the extreme. Branching, nil checks, and attributes are not very "OO" and are often the source of great complication in our code. What would our code look like if we did everything we could to avoid them? In this talk, we'll create some odd-looking constructs and write some weird code in an attempt to understand just how useful branching, nil, and attributes really are. Do these constructs make our code easier to read and understand, or are they vestiges from our shared programming backgrounds like C, PHP, and Java?
Attribute grammarCodeStatisticsService (economics)Pointer (computer programming)Attribute grammarBranch (computer science)Lecture/Conference
Video gameWorld Wide Web ConsortiumControl flowComputerLine (geometry)SoftwareService (economics)Computer programmingMereologyMobile appException handlingExpert systemPressureSimilarity (geometry)File formatMultiplication signPattern languageLecture/Conference
1 (number)Level (video gaming)Shift operator
Attribute grammarLevel (video gaming)Time zoneCodeMultiplication signLie group
DatabaseObject (grammar)Formal languageType theoryPhysical systemVulnerability (computing)Relational databaseMobile WebProgramming languageError messageCrash (computing)Term (mathematics)
Physical systemDefault (computer science)Type theoryMultiplication signSymbol tableObject (grammar)Variable (mathematics)Pointer (computer programming)Sinc functionProcess (computing)Sign (mathematics)SequelArithmetic meanComputer animation
Computer configurationModule (mathematics)CodeComplex (psychology)Object (grammar)Type theoryRight angleSocial classCompilerLine (geometry)Pointer (computer programming)Attribute grammarSound effectSoftware testingSlide rulePhysical systemComputer fontEndliche ModelltheorieDevolution (biology)Function (mathematics)Arithmetic meanPoint (geometry)Default (computer science)
Pointer (computer programming)Symbol tableDifferent (Kate Ryan album)CodeRevision controlDefault (computer science)
Social classBlock (periodic table)System callSymbol tableObject (grammar)Default (computer science)Message passingBitType theoryDecision theoryPointer (computer programming)QuicksortBlock (periodic table)CodeRootLine (geometry)FlagTrailRight angleMereologyOffice suiteLogicSocial classService-oriented architectureDependent and independent variablesLecture/Conference
Attribute grammarAttribute grammarPointer (computer programming)MereologyLogicForm (programming)Arithmetic meanCodeEqualiser (mathematics)Object (grammar)State of matterSpacetimeMathematicsRow (database)Point (geometry)DatabaseLecture/Conference
State of matterStandard deviationCodeCombinational logicVirtual machineLibrary (computing)PlastikkarteAttribute grammarFormal languageWritingDatabase transactionQuicksortArrow of timeProcess (computing)Java appletRiflingRight angleCodeComputer animation
GenderDreizehnAttribute grammarBlock (periodic table)Range (statistics)Line (geometry)Power (physics)Process (computing)Database transactionGraph coloringNumberState of matterParameter (computer programming)Statement (computer science)Formal languageComputer programmingObject (grammar)Right angleSound effectQuicksortLevel (video gaming)MereologyField (computer science)Game controllerRevision controlMathematicsAttribute grammarCodeInteractive televisionExterior algebraVariable (mathematics)CASE <Informatik>Latent heatBlock (periodic table)InformationSimilarity (geometry)GenderLogicData structureReading (process)Multiplication signBlogDisk read-and-write headDifferential (mechanical device)Electronic mailing listLibrary (computing)Entropie <Informationstheorie>Normal (geometry)Row (database)PerimeterCoroutineLambda calculusDefault (computer science)ImplementationJava appletCone penetration testDatabase
Assembly languageComputer programmingStatement (computer science)QuicksortSound effectProcess (computing)Programmer (hardware)CodeCASE <Informatik>Formal languageLecture/Conference
Block (periodic table)System callPeg solitaireAssembly languageCodeStatement (computer science)CASE <Informatik>WritingHecke operatorState of matterData structurePlastikkarteService (economics)ResultantShift operatorException handlingImplementationLevel (video gaming)QuicksortFreewareBlock (periodic table)Social classSpeicherbereinigungFehlererkennungSoftwareFormal languageWordSystem callSoftware testingBitPattern languageCoroutineField (computer science)Right angleInternetworkingInsertion lossCuboidProduct (business)Negative numberPurchasingBroadcast programmingGraph coloringHand fanLecture/Conference
Block (periodic table)StatisticsStatement (computer science)Product (business)MereologyCondition numberElectronic mailing listSoftware testingResultantSystem callElement (mathematics)ExpressionRight angleFormal languageSet (mathematics)Level (video gaming)State of matterFigurate numberData structureOrder (biology)Revision controlLogicMappingException handlingoutputError messageBlock (periodic table)CodeQuicksortSocial classProgramming languageMultiplication signType theoryCASE <Informatik>Symbol tableLambda calculusLink (knot theory)Performance appraisal
Universal product codePlastikkarteCodePower (physics)Business modelService (economics)Link (knot theory)Lecture/Conference
SoftwareVideoconferencingBusiness modelMultiplication signSoftware engineeringLink (knot theory)Computer animation
Transcript: English(auto-generated)
Alright. Has everyone enjoyed their lunch? Ready to talk about some really strange and
weird code? So thanks a lot for coming. My talk is called Eliminating Branching Nil and Attributes. Let's get weird. So we're going to see some really strange code. Briefly about me, I work at a company called Stitch Fix. We're a personal styling service for women's clothes. I'd love to talk about all the cool things that we're
doing, but that's not what this talk is about. I wrote this book about writing command line apps in Ruby, which you should buy and read and do. Also not really what the talk is about. I also wrote another book about how to do everything to be a great programmer, except for the actual programming part. Again, it's not really what I'd like to talk
about. I'd like to talk about Top Chef. Anybody watch Top Chef? Alright. My wife and I have watched it for years. It's one of my favorite shows. I'm very excited when it shows up. I haven't been home for about a month, so no spoilers about the current season. What I love, and if you're not familiar with it, it's a reality show about cooking. So these chefs will compete each week, and at the end of each episode,
a chef will be eliminated, and at the end of the season, one chef wins a bunch of money and some kudos and other things like that. What I like about it is that unlike a lot of reality shows that are about dramatic personalities arguing in some house that they live together, on Top Chef, you're watching experts execute things
that they're good at. You're watching these people cook this amazing food under intense pressure, and just watching experts work, I always find fascinating. So what's also fascinating is that the show's format hasn't really changed over the years, and so when you see experts doing things in a very similar format over many years, patterns start to emerge that I find interesting. So at the beginning of
each show, there's what they call the quick-fire challenge. So the chefs are given a short amount of time to make a dish. So, for example, they may have to make an Asian-inspired dish that features the daikon radish, and they might have 30 minutes to do it. And so it's very intense watching them try to do
this. Now what always happens in the show, and if you watch Top Chef, and you've watched it for years, you'll know exactly where I'm going, there'll always be one chef who works in an Asian restaurant, who makes Asian food. This chef grew up on a daikon radish farm, knows everything about everything in this particular challenge, so he is very confident. He is like, I got this, I know how to do all these
things, no one's gonna beat me, I'm gonna get the advantage later in the show by winning the quick-fire challenge. And of course, there's always another chef, and she is a French pastry chef. She doesn't know what a daikon radish is. She doesn't like Asian food. She's never cooked Asian food, and she's very worried that not only is she not going to win, but
she's going to lose the quick-fire challenge, which comes with a disadvantage later, which means that her chance of getting eliminated is very high. So she's very upset about this particular challenge. Now what happens is, our chef who works in the Asian restaurant will do what he always does, produce what he always produces. And he'll produce a mediocre dish, because
the level of competition is so high, that when he just executes these things that he knows how to do, he's not really rising to the level of his competition. Which is kind of unsurprising, but what's more surprising is that our French pastry chef will invariably, oh, I forgot to hit start on this thing, will invariably win the competition, even though she technically has no idea what
she's doing, right? Because she has the abilities of a chef, she understands the basic tools of cooking, and even though she doesn't know how Asian food is supposed to be made, or what you're supposed to do with the daikon radish, she's forced to get creative. This happens all the time on the show, and I think it's interesting to note the being constrained and being forced to
work without the things that are comfortable to you, can force people to become creative, and can force people to do something that they wouldn't have thought of, because they're outside of their comfort zone. So that's what this talk is about. We're going to talk about some things like nil, like
branching, like attributes that we use all the time, and are very useful, and are comfortable to us, and we're going to take those away and see what the code looks like without those, and see if that kind of makes us get a little more creative or think of things that we wouldn't normally have thought of. So I
want to first talk about the billion dollar mistake. Anybody familiar with this term? So it was coined by Tony Haar, who is a luminary in the world of database research. If you've ever used a relational database, you have him to thank for how it works. And in 1965, before most of us were probably born,
before most of us were probably programming, he was working on an object oriented programming language. He has this to say, I was designing the first comprehensive type system for references in an object oriented language, 1965. I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors,
vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last 40 years. I think it's probably been 50 years since that happened, and it's interesting to think about. The whole time I've been programming, there's been null. You use null everywhere. Null's in SQL, it's in C, it's in C++, it's in Java, it's in JavaScript,
it's in Ruby, it's in Python. It's just everywhere, like, and you always use it for I don't know, or unassigned, or nothing. So what if he hadn't done that? What if he had resisted that temptation? So what if Ruby didn't have null at all, right? So specifically, that would mean that every single variable would have to
have a value, because there is no default stand-in value. And it would also mean that there's no handy global symbol you can reach for everywhere that means nothing. So let's say Ruby didn't have this at all. Would we be able to get our work done? So here's some code. It is a person. A
person may or may not have a title. So typically we'll default that to nil, so that you can create people without specifying explicitly nil or anything like that. So you can see how this optional title affects our code. Title is nil, we say hello Bob, but if Bob has a title we say hello Mr. Bob. This
is, you know, it's very simplistic, but it's pretty typical of code that we write around nil. So if we don't have nil, we can't do this. So how would we solve the problem of having people, some of whom have titles and some of whom don't have titles? Well why don't we use the type system, right? So we can make a person that just has the attributes that all people have, a name
and a birthday. So we can see the greeting method is very simple, hello Bob. And then we'll make a subclass called titled person, and that will have a title, and then the override greeting to say hello Mr. Bob. So now we know everywhere we have a titled person, we know there's a title, if we
don't have a titled person we don't have a title, so we didn't need to check for nil. Unfortunately this technique is, it's great for giant slides with giant fonts on them, but in reality, right, think of an object in your system that has a lot of optional values. It would be super complex to do this with lots and lots of optional values. You could use modules, it gets kind of weird, but it
also kind of shows like a, this is not really the most Ruby way to solve this problem, right? Ruby, yes, when you make classes and they create objects, but having lots of fine-grained types like this is not as helpful as it might be in like a statically typed language. So if we were doing Scala, we might want to write a routine that says I need a person that has a title, so I'm gonna
require you to pass in a titled person, and the compiler will refuse to compile your code if you don't do that. Ruby doesn't work that way, and it's no offense, I'm glad it doesn't work that way, but the point is if you were using types like this, we end up having to check the types of things, or have our tests check the types of things, and that's just kind of strange to be
adding these degenerate type systems to our test and code. So we really do need some concept of null, or some concept of like there is no value here, or I don't know, like we do need that concept. We can't skirt it just by using types and modules. So we could do this, right, but let's think harder than this. Let's try a little harder than just recreating null, and let's
think about what null means. So null means a variable hasn't been set. It could mean that we don't know the value of a variable yet, but we might later. It could mean that there is no value. We know that there is no value. We know someone doesn't have a title. Could mean some vague concept of empty. So if we want to model these four things, I don't think nil would be the way we'd
go about it. I don't think we'd want to have a single symbol represent all these four concepts, because they're different, and there's no way to tell the difference between a unset variable and a variable whose value we don't know if they're both nil. So let's create four symbols. Sorry about the
zoom here. So four symbols, each one represents one of those concepts. So now we can tell the difference, and so if we look back at our person code, again we're going back to the kind of the original version, but here you'll notice we're giving title of the default value of unknown. So because now there are four different things we've created, we can make a design decision about
what title should default to. We could decide that a title has no value by default. We could decide that it's unknown by default. So that's a design decision we get to make that expresses something about our person that we couldn't do before. So we're gonna call, we're gonna just say a person is unknown. A person's title is unknown by default. So our greet method,
you know, we could do it like this, and you know, this is not gonna work. Obviously this is buggy, right, because if we give no value, then hello no value Bob, like that's not right. But more so, since there's so many different symbols that represent some type of no value, we can't just get away
with comparing it. Like with nil, it's handy. We know there's only one nil, and even though we know we should be calling the dot nil method, we tend to compare it to nil a lot, but that's okay because there's only one of them. Well in this world of no nil, there isn't one of them. There's four, and it would be pretty darn ugly to be checking title against all four values. What we
really need is some sort of API around this, some messages that we can send to make this a little simpler. So what if we had something like this? We have a message called when value that everybody responds to, and if the person we're sending that message to happens to be a value, it will execute this code. Hello Mr. Bob, and if title isn't a value, it's some sort of nil
like thing, it will execute this. Hello Bob. This is pretty easy to implement. Basic object, right, is the root of all objects in Ruby, and all objects are values by default, so when value, we'll just call the block given to it, and or else is a no op, because since the basic objects are values, we don't want
to do this or else thing. Now for these four special nil like things, we'll make a superclass called nil like sentinel, which is the best name I could come up with without using one of the names of these objects, and it does the opposite, right? So when value is nothing, it's a no op, but or else, because these are not actual real values, will execute, and then we give all these
guys a new superclass, so that makes that work, which is kind of interesting. It's a little bit strange looking, right, because we've got this method called or else, but Ruby also has this else thing. It's kind of like we're branching, but we're not. It's a little bit weird, and it's kind of the same lines of code as our nil checking thing, so you know, I would
probably want to know, is there any advantage to doing it this way? Well, let's consider if our greeting method gets a little more complex, and now what we want to do is if we have a title, we want to say hello Mr. Bob, but if we don't have a title, but we know that a person has no title, right, we know you
have no title, we'll say hello Bob, but if we're not sure, if the title is unknown, or we haven't been told what the title is yet, we want to say I'm not sure how to greet you Bob. So these are these are different things, right? We know a person doesn't have a title is different from not knowing what a person's title is. So with nil, this would be very hard, but now let's kind
of, let's expand our little nil-like API to have this concept of when known. So does this value, this thing we have, is a value or not, is it something known? Do we have knowledge about something? So of course, basic objects, since they are values, we know that they are that value. And nil-like
objects, again, are not known by default, and then we'll have our known nil-like sentinel, which will represent things that are not values, but represent knowledge that we have. So no value at empty, represent that, and now a code looks like this. And this is what I love about Ruby. Title when value hello
Mr. Bob, when known hello Bob, or else not sure how to greet you Bob. I can just read you the code and it sounds like a sentence, it sounds like what it does. So this is actually a little bit more interesting. It's definitely strange looking, but you'll notice that we've lost all that deep nesting that we
might have had. Everything's kind of typographically the same, which it should be, because these are all equally likely to happen in our world. And it's just, you know, it kind of reads nice. And it's important to point out, if we were using nil, we probably would never have come up with any of this, and to be able to tell a nil title, does that mean unknown, or does that mean I know
that there is no title, like you'd have to have some boolean flag to keep track of that, or some magical symbol. So instead what we've done is we've just created objects and messages to model the actual thing we want to do. So that's kind of cool. Now you'll notice that I didn't make methods called is value, or is known, or anything like that. And that leads to the next, oh,
also this is the best part of this, so I can't believe I forgot. Wouldn't it be nice to get that in your stack trace, or that, instead of no such value for nil class? Like who knows what that means? But this, right, this means I didn't handle some logic, and this means that I screwed up. So that's another kind of
side benefit of doing this. So to get back to the nil method, or the value method, or is known method, like you might think that I should have added those, and based my logic on that. So I want to talk about attributes. Those are kind of a form of attributes. And so what I mean is, adder accessor, adder reader, adder writer. These give the appearance of being able to access the
internal state of our objects, and the ability to change directly the internal state of our objects. Ruby helps by allowing this method named foo equals to be called with foo space equals. So it really does give the appearance that our objects are these dumb structs that we can just kind of change willy-nilly. Because it's so darn handy, and so easy, especially when we're
manipulating things in a database, we tend to write code like this a lot. But I think that is potentially bad. So let me try to make that point with describing how you might buy something by using attributes. So you take out your wallet, hand your entire wallet over to the clerk. The clerk will then
rifle through your wallet to find whatever combination of cash, credit cards, gift cards he decides that you should use to pay. He'll execute the transaction and hand you back your wallet in whatever state he felt like leaving it in. So right, some countries don't even take your credit card. They
give you a machine to run your credit card. No one buys things like this. This is crazy. But when you write code that makes heavy use of attributes, it's kind of like how you're coding, right? So let's say that Ruby doesn't allow this sort of thing. Let's say that Ruby doesn't have this little nice equals method deal, and that the standard library doesn't provide adder accessor, adder reader, adder write. It doesn't provide any of
that stuff. So if you've ever coded in JavaScript or Java, you know what that's like, because they, those languages don't provide that. Oh boy. Okay, that's not too bad. So here's some code that we will not be allowed to write. So we have a very sophisticated greeting method now that is going to
give you a casual greeting. Hi Bob, if we know your first name. If we don't, but you have a last name, then we're gonna see if you have a gender, and if your gender also has a gender-specific salutation, and if all that is true, we will say, hello Mr. Jones. If not, we'll say hello Jones, and all else fails, we'll say hello. So this is convoluted, but I'm sure we've all written code
that looks more or less like this, asking things for their things and checking their things against other things. So if we can't do any of this, we can't create easily an API like this, right? What would we do? So getting back to the Java and JavaScript part, we all know what those languages do. They make methods called getters and setters that look like crappy versions of
attributes, and that makes sense for those languages, because those languages aren't terribly powerful compared to Ruby, but Ruby has more features available to us that might not lead us down that path. So what if we did something like this? We have a method called with attributes, and so if the
first name is there, then we'll run this block of code. If we didn't, but we have a gender salutation and a last name, run this block of code, etc. So I should point out, this absolutely works. A lambda has access to not only the
number of parameters, but the names of those parameters, so you could just look at the parameter list to figure out what attributes are being asked for. So this is kind of strange, right, but you could imagine if the standard library provided something like this, this would start to look kind of normal, and
again, right, we've lost that big, huge cone of nesting, and now we have a nice little typographically organized thing for each thing that could possibly happen. It's nice, but there's another couple things that are nice about this that we wouldn't have gotten with this craziness. One is that we have an API that differentiates a request for
information and actually being given that information, so that allows us some more flexibility. So if we wanted to have logic that says, you know, maybe someone has a gender salutation, they have a last name, but if someone asked for them both at the same time, we want to do something else. Like we could do
that with a structure like this. We couldn't do that by just allowing people to have access to whatever they wanted. So that's kind of interesting, but what's more interesting is when you think about the scope of some of these variables. So here, the scope over which first name, last name, gender, all this stuff, it's all global to this method, right?
All those values can be accessed anywhere, and although this is a very short method, I think we all know that the larger the scope of a variable is, the harder a routine is to understand, because you have to keep a lot of things in your head to understand what is going on and what might happen. Here, the scope of first name is just here. The scope of gender, salutation, last name is just here. Now even though these are one-liners, each of these blocks, each
of these alternatives, is still going to be smaller than the entire routine. So we've actually made the code a little simpler to understand by reducing the scope of the variables that we need to do our job. But we haven't taken away any power. You still have access to these things, and it's kind of the same lines of code. So that's kind of interesting, I think. Where it
gets really interesting is we want to change the internal state of an object. So again, we might want to change a person's city to normalize it or something like that, and you know, whatever your feelings are on mutable state and changing things, like our programs do need to make changes to
something somewhere sometime. So we have to have an ability to change something about something. So if we can't do something like this little magic, magic-ness here, and we're not doing setters because setters are weak, what are we gonna do? Well, what if we made, we'll follow along our with attributes concept, and we'll make a method that records all of the
changes a caller might want to make to us, and then we can decide what to do with that. So maybe that looks like this. Person has this update method, takes a block, and inside that block, we will use the update object to record basically a bunch of requests of changes, and you know, I'd like to update
the city to this and blah blah blah. So again, it's the same lines of code, but now we have a level of indirection between what we would like to do and having those changes actually made, which is kind of interesting, right? Because it gives us a little more power that we wouldn't get with these equals methods that we use so often. So you know, a naive implementation might
just be to just do what equals methods do, right? So we could kind of default to that if we wanted to. So we're getting the exact same thing with about the same lines of code, but we could do more interesting things. What if we wanted to run this in a database transaction? Well, if you've done Rails programming, then the way to do this is either you, the caller, must
put everything in a transaction, or you have to use a Rails specific magic method that only some objects have that is known and documented to put things in a transaction. So me being the object who's being changed, I don't really have a lot of control over that, so this would allow me to do that if I wanted. What's more interesting is that since we have all of the changes
that we want to make to an object in one place without them having actually been made, we can examine them before doing anything. So we could decide that if you're changing the zip code and city together at the same time, then we want to make sure that those are consistent with each other, and then we could blow up if not. So doing this with equals methods would be
tricky. It would be really hard to get it exactly right in every case, but it's, you know, it is kind of, it's kind of strange looking, but you know, I think like I would get used to this if this was just kind of how you did things, and it's kind of interesting that by not using these handy things that we think are easy, we get a lot more power available to us. So you may have
noticed that the before and after, the after didn't have any if statements in it, and that was sort of intentional, but sort of a kind of side effect of just the way we went about solving those problems. But that makes me wonder,
right, what if we don't have if statements? Which is a crazy notion, right? I kind of feel like programmers' jobs are to write if statements, right? If I need to write an if statement, programming would be easy. And if you think about, like, what are the features of assembly language that are also in Ruby? If statements is one of them, right? You can't write assembly language
without some method of branching the code. You have to direct the code to go one place in a certain case, and another place in another case. So what if Ruby didn't have if statements? There's no if. There's no unless, no else, no switch, none of that stuff. How in the heck would we get anything done without if statements? Let's find out. So here, so we're gonna get away from
the exciting world of greeting people to a little bit more of the real world of getting their money from them. So here is an imaginary routine. So let's say we've been given this credit card service, and the idea here is we want to charge somebody some money, and then if anything goes wrong, we want to give them a reasonable explanation. And so this is a pretty typical pattern, right?
We get back some blob of data, then we ask the blob of data some stuff, and do things based on that stuff, right? That's pretty reasonable, like if it's a success, fine. If it's not, we compare the error code to some magic value, and that means expired, and else must mean declined, and because we're doing network programming, right, we got to, you know, we got to rescue everything,
because, you know, that might go wrong there. So without if statements, how might we implement something like this? Well, if there were no if statements, I would bet that the creator and designer of the credit card service might design an API a little differently, right? This design of passing back a blob of data
and hoping you know what to do with it is a lot more difficult if you don't have these branching structures. So the credit card service might be designed in a way that doesn't require having if statements. So let's see what that might look like, right? What it might do instead is map every possible thing that could happen to some code. So I'm the caller, I'm gonna say for every
possible outcome, here's the code I'd like you to run if that happens, and then the credit card service will sort out what outcome actually did happen, and call the right code. So that might look something like this, right? On success, do nothing, on decline, on expiration, on exception. So this is kind
of interesting, right? For one thing, again, typographically, everything's together, it's kind of nice. We brought this exception up to where it belongs, because exceptions are just as likely to happen, so it doesn't deserve a special place known at the end, and it also reads a lot clearer, right? I don't have to make that mental shift of like, if some field
equals some magic value, then that means the concept of expiration. I can just call a method that says what it is. So that's kind of cool, right? We skirted the issue by redesigning the API to not need if statements, and but there's some negatives, right? Like this is totally custom, totally proprietary to
this service. So this isn't like a generalized language construct that we might be able to use. It's very one-off. If statements are handy, because when we talk about what code is supposed to do, we use the word if. That's why it's in the language. So this gets rid of that. So you could say that if you had a large code base, had lots of things that worked like this, it could be kind of strange. So I'm gonna ask again, what does this let
us do that this if statement approach didn't let us do? So let's say I screw up when I'm implementing my credit card charger, and I forget to handle the case where someone's card is expired. So I just have this code, and again it looks nice, it reads nice, everything's good. My tests all pass. The failure was
that I didn't understand every possible outcome that could happen when I'm using the credit card service, right? So I am living in the fantasy world where I can charge credit cards, and the garbage collector who has made the credit card service for me has to explain to me at some level what I need to do, and I haven't understood that. Now if I did make this mistake,
it's really hard to find out that this happened, right? You might have people buying things and being told that they successfully purchased, but then they never get their item, which is bad. Or worse, they could be told that they successfully purchased, and then they did get their item, so we're giving away things for free. This is a very hard mistake to find, and it has
disastrous consequences. And so the hope, right, the way that we prevent ourselves from making a mistake like this, is we hope that our garbage collector who created our credit card service wrote enough documentation and explained things well enough that we understand, and that we read that documentation and totally understood how to use this API. So with the way that we normally do
things, that's what we have. We have hope. Here, we can actually check, right? Because what we're doing, this code isn't actually running, this code is mapping outcomes to code. But it's not actually running the code. This guy, the credit card service, is actually running the code. So before the credit card
service runs the code, it could check to see if I handled everything. It could check, and it could notice I didn't provide any code for the on expiration case, and it could decide, dude, you did not understand how to use me. I'm not going to go forward because something is broken. You have failed. If you want to give away products, that is cool with me, the credit card
service. You need to tell me explicitly that you knew that there was this case to handle, and that you handled it in some way. That's kind of cool, right? You can't do that with if statements. It's impossible to do with if statements unless you remember to call some magic method or something. And here, instead of relying on documentation and my ability to read and understand how
to use this credit card service, the API itself can bake in all of this safety. It can encapsulate the knowledge that our garbage collector has so that we can live in fantasy land, which is kind of cool. So it's something, and I should point out, I didn't come up with this little pattern and then write a talk around it. I just came up with a talk,
and I just tried to write this code without if statements, and that's kind of what I came up with. So it's kind of interesting that that is something that fell out, that I can do more things. But I've skated the issue of the if statement, right? I've changed the rules so that I didn't need an if statement to implement this. But somebody somewhere is going to
have to figure out, did the credit card succeed or not, and do something or do something else. Somebody has to do that somewhere. So let's delve more into our imagined credit card service and see where that leads us. So we could imagine that the way this works is it'll sort out some URL, it will call the URL over the internet,
get some status back, and then we'll have the outcome class handle figuring out what that result means. So the outcome class since it has all those blocks of code that we gave it, it's going to look at the result of our RESTful API call, figure out what it means, and figure out what block of code to call. That sounds like a job for if statements.
So taking a step deeper, right, our method has kind of three parts. It gets a status from the result, it'll call a private method that sorts out what that status means, it returns the name of a method, and then we will call that method on ourselves. So the what to call method is where we have these if statements. So this might be how we would do it if
we had if statements, but we don't. So we could do this outcome type thing again, I mean we could just keep doing outcomes within outcomes and all that, but somebody somewhere is going to have to compare two values and decide to do one thing or the other. So let's not do the outcome thing here, let's try to do this a different way. The result is going to
be super strange. So we're going to do a little pseudocode here. So what we have is we have some expressions, and if this expression is true, we want to do this. And if this is true, we want to do this, and all else we do that. That's the basic logic that we want. So since we don't have these if statements, how can we capture these expressions in some way that we can
evaluate them? Well we could wrap them in a lambda. So now we have a mapping of a lambda representing our expression to some symbol. So what we want to do is we want to go through all of these lambdas that we have and find the first one that's true. So if we had them in a list, say, so now we have a list of pairs, each pair is a lambda
representing our expression and the method to call. So we want the first one in this list, so that's detect. So detect, if you don't know, it finds the first element in a list for which a particular condition holds. So in that case, that condition is to call our lambdas and see if they return true with our input. So that is going to return one of our
pairs, our pair being the lambda and the method, of course we don't care about the lambda, so we destructure it and we get the method. And if detect didn't find anything, it's going to return nil, which means it will return call on exception. So that is how you do that without any if statements. That is weird, right? I mean, does this look normal to anyone?
If I came across this, it would take me a long time to learn that this was an if statement, and I would venture to say a language for which this was the primary way to direct logic would probably not be a successful language. Because this is very strange. So I must ask myself,
is there something I can do with this? Is there some advantage to this that I didn't get with these if statements? So let's suppose I made an error. Now, this is very simplified, right? You can see here that 200 is less than 500, so this code is never going to be called. Now this is super simple, you can kind of see by inspection that there's a problem
and it would be very simple to write a test that reveals this and you would probably have those tests. So I'm asking you to remember that code that you have fully tested but yet was buggy, because there's something that you forgot. Or a bunch of if statements that were very hard to understand all at once, right? And that you have totally tested and then went to production and then
it didn't work because of something like this. So the only way to solve this is to have a lot of tests and just be diligent, right? Just try harder. But is there a way with this other crazy structure that we could do that? And so you might be wondering why, you might have noticed that I use a list
instead of a map between the map and all that stuff, that's because the list retains the order. And so the order in which we evaluate these things is very important. So how could we detect this error? Since our logic is not encoded in the programming language but is actually encoded in a data
structure, we could examine this data structure and find out things about it. So if we assume that our crazy version of Ruby that has no if statements and requires us to do this exists, it seems logical that it might have a class that helps us write this weird if statement. So again, all this code works, there's a link
at the end, this all absolutely works. So let's say this logic class here handles all that mumbo jumbo with going through the list and detect and all that crap. So all we have to do is this. Now I'm not saying this is not weird, this is still strange, but it kind of creates a class concept here. So when we evaluate the logic given an input,
the logic could say, hey, that input is true for more than one expression. So I don't know which one you meant, I don't know what to do, I'm just going to assume that you haven't thought this through, you've screwed something up and I'm just going to blow up. With a non-exclusive disjunction error, that's the best name I could come up with for that concept.
Took a lot of Wikipedia sleuthing to figure that out. So that's kind of handy, right? So if every crazy set of conditionals I ever wrote could be evaluated by someone smarter than me and tell me that I didn't think it through and things aren't mutually exclusive, that would be useful to me. So to fix it,
we have to do this. Now these two things are mutually exclusive, they will never be true for the same input, but everybody's bothered by this repetition, I hope, because this bothers me. I don't like having to say the same thing twice, that's what the if statement gave us, the else concept. But this is just blocks and lambdas, so
we could extract them and reuse them. And now look at our code, right? Logic on success, then return call on success. Logic on decline, then return call on decline. Logic evaluate status or else call on exception. It has that awesome Ruby-like quality where you can just read the code out and it's like executable pseudocode, like that's kind of cool. Even though it's kind of weird what we're doing,
it's pretty easy to understand, and this is a lot easier to understand than that crazy list and detect and all that. So I could see a language that had this as the way of branching, well that might be a little more successful than our other one. So yeah, that's kind of crazy. So
that was a lot of weird stuff, and like I said, it all works, and I'll show you the link at the end. I'm not telling you you should do that, ever. I'm not saying you should put that in your production code base, I certainly haven't. But what you should take away is that sometimes more interesting things can come if you
remove tools, if you remove techniques, if those things that you are really hold dear or think that there's no way I could ever do without X, well try solving the problem without X and see what happens. And you might be surprised, you might come up with something that is actually really useful and maybe gives you more power. I mean this business with the credit card
service where you map the outcome to the code and it blows up if you haven't thought of everything, that seems actually kind of useful, especially for something as critical as taking money from people. I kind of want to get that really right. So it's kind of interesting. So I'd encourage you to do the same things. It's all I've got. I do want to pitch from my company. We are small.
We have a business model that works and is easy to understand, which I hope you find interesting. If you're interested at all, come talk to me. Here's the links for everything. The book, Senior Software Engineer that I told you I wouldn't talk about because it's not relevant, well you can buy it today for $10 if you'd like. That's all I've got. I think
we have a few time for questions if anyone has them. Cool, well if you've got any other questions, come up and talk to me and I really appreciate you guys coming. Thanks.