Check out a free preview of the full The Good Parts of JavaScript and the Web course

The "Function Challenge 4" Lesson is part of the full, The Good Parts of JavaScript and the Web course featured in this preview video. Here's what you'd learn in this lesson:

In this challenge, you will write the from(), to(), fromTo() and element() functions.


Transcript from the "Function Challenge 4" Lesson

>> [MUSIC]

>> Douglas: Write a from a function that produces a generator that will produce a series of values. So, we're going to pass a zero to the from function. It will return a generator in this case I'm calling it index. Every time I call index, it will return the next value in the sequence that started with the starting value.

>> Speaker 2: What's a generator?
>> Douglas: Generator is a function that will make things. So each time you call a generator, you'll get another thing. In this case, where you were making a generator that's gonna produce a sequences of integers starting at some value. Okay, so here is from, from takes a start value it returns a function which computes the next value simply by taking the start it adds one to start and then returns next.

So, who got something that works? Okay, very good, anybody take a different approach?
>> Speaker 2: I just read that in your function. I just did return X plus equals one
>> Douglas: Okay
>> Speaker 2: That work?
>> Douglas: Sure. Anybody else?
>> Speaker 3: That will give you a starting point different. Then zero ought to be starting one.

>> Douglas: Yeah, he's right.
>> Speaker 2: You'll like this. I did return start plus plus
>> Douglas: Yeah, there's always one of those.
>> Speaker 3: [LAUGH]
>> Douglas: Anybody else?
>> Speaker 4: You wanna get start plus one?
>> Douglas: Yeah, start 1’s to be, if we say from zero we need to start from zero.

>> Speaker 4: You need plus, plus 1. But you return plus, plus start.
>> Douglas: We’re not doing that.
>> Speaker 3: Yeah, I know you’re not doing that.
>> Douglas: Okay, ready to move on? Okay here's the next one, write a to function that takes a generator and an end value and returns a generator that will produce numbers up to that limit.

So, we'll pass to the to function a generator that we make with our from function. So I will pass from 1 to 2 and also pass it a 3, and it will return a generator which will return values up to the limit to 2 and from that point on it will return undefined instead.

>> Speaker 2: So on the previous limit, this one does not include the limit? [INAUDIBLE] times.
>> Douglas: Right, this is 2 a value
>> Speaker 2: Not including this one.
>> Douglas: Right.
>> Douglas: Well, this is the convention we have in our languages, right?
>> Speaker 4: That's true.
>> Douglas: When you're taking a substrain of something?

This is the way we do it.
>> Speaker 4: Is this your reason Max?
>> Douglas: Yeah. [SOUND] So, here's one way to write the to function. To takes a generator and an end value, it returns a function that gets the next value from the generator. If that value is less than the end value, it returns that value, otherwise it returns undefined.

So, who got something that works? Very good. Anyone take a different approach or do something amazing?
>> Douglas: Wonderful, spectacular, anything like that.
>> Speaker 2: Amazing it is but mine looks very similar to the limit function. Just uses from generators inside of it. So I set variable in the outer scope, and then add a number to that and if that number is less than or equal to the limit a return find, otherwise generator.

>> Douglas: Okay, anybody else? All right, wanna do another one? Yes, all right, let's do another one. Okay, let's write a from to function that produces a generator that produces value in a range. So we're going to pass to fromTo 0 and 3 and it will get us the generator that gives us a sequence zero, one, two and then undefined.

So here is fromto, fromto (start, end) value in the returns result of calling to passing it from (start), end. So, who got something that works? Very good. Who did it the hard way? Yeah, first rule of functional programming, let the functions do the work. Write an element function that takes an array and a generator and returns a generator that will produce elements from the array.

So we're gonna pass to the element factory, and array containing a,b,c and d. And will give it a generator which does from two one to three, and that will give us a generator which will produce b and c and then undefined. So here's element, element takes an array and a generator.

It returns a function that gets the next index from the generator. If the index is not undefined it returns the next, or the element of the array at that index. So, who got something that works? So, I want to talk about this statement that's underlined. Because if you leave that if out, if we do the return unconditionally, it does the same thing.

And the reason it does the same thing is kind of weird. So,
>> Douglas: If we don't have the if there, and if index is undefined. Then the brackets will turn undefined into the string undefined. It will then look for the member undefined in the array and not find it, and return undefined, which is what you return if you can't find something.

So it kind of accidentally works, if you leave that test out, except in the case where if someone creates an undefined property in the array. Then they can cause the behavior of this function to change in that case.
>> Speaker 2: So, you would to call delete on a node in the array?

>> Douglas: No not deleting a node, if you said array, what are calling the array? Yeah, if we said array.undefined = five, then in that case will return five instead of undefined which might not be what you want, and so while most of the time it works. I'm concerned about the weird cases which are what actually screw you up in production and at life.

And so, I would rather be explicit and look for that case. Anybody else do something different?
>> Speaker 2: This is continued to be array, I mean, to the task.
>> Douglas: Yeah.
>> Speaker 4: Here it's returned array gen.
>> Douglas: Mm-hm and yes-
>> Speaker 4: Cuz there's too much to do that. [LAUGH]

>> Douglas: Almost always work, modify the element function so that the generator argument is optional. If the generator is not provided then each of the elements of the array will be provided. So we can call element pass the array a, b, c, and d, and we will get a generator which will return a, b, c, d and undefined.

So here is the revised element, all I did was add the code that's in the yellow box. If we didn't get past a generator, then we'll call from too and get a new generator, otherwise everything else is the same. So, who got something that works? Did anybody try to do it the hard way?

First rule of functional programming. Yeah, let functions do the work. So, I want to talk about the condition that I underlined. There are three ways I could have written that. That's the first one where I'm looking for explicitly, did undefined get passed in. Which means did nothing get passed in.

Another way I could have written it is, is the type of gen equal to function? So if they passed in something but it wasn't a function, we'll make it a function. So the difference between those two approaches is the second one will tend to always succeed, and the first one will tend to fail if something bad was passed in.

And it depends on the characteristics of your application generally, fast failure is what you want because it helps you discover bugs faster. But sometimes you got code which is really critical, and you wanna be sure that no matter what happens this code is gonna be working right. The third way you could write that condition would be to do a bullish check.

if not gen then do something and I don't like that. Because what we're trying to do in making the condition is divide the whole universe of possibilities into one of two states that either is or it isn't. And the bullish case splits it in a really weird way in that, if they pass in a one, the behavior will be very, very different than if they passed in a zero.

And it doesn't make sense to me that one in zero should behave that differently when we're looking for a function. So this is why I think that JavaScript depending on boolish values and conditions was a mistake, I recommend always be more explicit. Either figure out, do I want the fast failure question or do I want the will seem to always succeed question, but not the the convenient one which can straddle both of those in unexpected ways.

>> Douglas: In that case, that'll work fine too. From we'll keep going forever but we run into the end to find things so it'll stop so from by itself is also okay. Anybody else?
>> Speaker 4: [INAUDIBLE] That when, because you said undefined, as opposed to boole square.

>> Douglas: Right. So, I used to recommend using the logical OR operator to do something like you're suggesting. To replace default values and I've stopped recommending that because it's too hazardous. That if someone passes in a zero, zero is falsely and so it might get replaced in cases we don't expect it will.

And that's problematic so I now recommend instead be explicit don't depend on boolish chucks.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now