66

Interviewed a dev for a junior role earlier this week...my first question:

const numbers = [0.1, 0.2, 0.3];
let sum = 0;

for (i = 0; i < numbers.length; ++i) {
setTimeout(() => {
sum += numbers[i];
}, 0);
}

// Refactor the preceding code so that the following returns true.
console.log(sum === 0.6);

---
He had no idea where to even start, so I asked him to walk through the code with me line by line, he couldn't get past line 1 - literally didn't know what an array was... I walked through the code with him and he just started to look more and more lost.

I didn't even bother with the rest of my questions on OOP, FP, etc...

Am I really expecting too much of somebody that claims to have 2 years practical experience in JavaScript, jQuery, Angular, and PHP?

Do you think this is a problem a junior dev should be able to solve...even if it takes some hand-holding?

Comments
  • 12
    Heh, I got that and I have 0 years/months/weeks/days experience, yey! :))
  • 1
    @securiter ...and your solution?
  • 2
    Remove the settimeout? That way the code of the function will get executed before the log. Otherwise the settimeouts will only be executed after the code (and the console log) ends and sum will be 0 by then
  • 1
    @YouAreAPIRate still returns false though 😉🤔
  • 2
    This is a basic question that he should have answered or atleast tried.

    Btw, I will get rid of the setTimeout first to get 0.6.
  • 0
    @samarthagarwal still returns false.
  • 41
    let sum = 0.6
  • 5
    Clue 1. JavaScript's Number type uses IEEE 754 floating point precision.
  • 1
    Do we need a delta-check here? If that's the solution than i'm slightly pissed for not thinking of it sooner
  • 9
    console.log = () => true;
  • 3
    Even with the setTimeout removed,

    0.1 + 0.2 + 0.3 === 0.60000000000000001
  • 0
    @terminalterror I would probably modify the increment from pre to post, modify the strict equality and lastly modify the timeout, either set an timeout value that's not 0 or remove it completely, I honestly do not know how it would react in a for loop. And lastly, if it's about floating point precision, I wpuld deal with that, nothing SF tho, not to mention I would be able to at least go through it and/or troubleshoot it.
  • 4
  • 2
    Just tested it. Sum will be 0.60...01, and sum === 0.6 will fail. You can do the following:
    sum *= 10
    sum &= 0xf
    sum /= 10

    (You can't round sum because a reassignment is not possible). This is a somewhat good rounding algo, given the value we work with you can justify the lines.
  • 6
    @terminalterror aside from the fact i would use fucking numbers.reduce..

    Doesn't this rounding-error shit happen only _sometimes_, not always?

    Oh and ++ for using ++i instead of i++. I know, the difference isn't even notable but there is simply no reason to use i++ in loops if you know both.:b
  • 3
    You don't need to remove the setTimeout...you can use block scoping and closure of the i variable using let in the head of the for loop, e.g.

    for (let i = 0; i < numbers.length; ++i) { .. }

    Even after that, or with the setTimeout removed,

    0.1 + 0.2 + 0.3 === 0.60000000000000001

    console.log(sum === 6); // false
  • 1
    @samarthagarwal good hack, switching the modifier of sum from let to var
  • 1
    @daintycode well yeah, that's the point of the question...to refactor it... obviously Array.prototype.reduce is the preferred method.
  • 0
    @terminalterror but does this fix the rounding stuff? I mean reduce is meant to solve this kind of problem, does it round right?
  • 1
    @YouAreAPIRate I did that but not using the benefit though. I used a parseFloat to get a number to number comparison.
  • 1
    @daintycode and yeah...you can't be *sure* about it because it's unpredictable, i.e. sometimes sum == 0.6, sometimes it might not.
  • 3
    @terminalterror do you have more questions like this? Please share.
  • 5
    @samarthagarwal anyways, this is a pretty nitpicky question. If there was a good answer i'd be ok with it, but i can't seem to find one
  • 5
    One solution might be...

    sum = numbers.reduce((a, c) => parseFloat((a + c).toFixed(1)));
  • 0
    @terminalterror just tried it, reduce itself doesn't fix it. But it fixes it to be clean code.:D
  • 2
    @YouAreAPIRate the point isn't that the candidate comes up with an answer...I just want them to walk through the initial implementation with me and identify where there might be potential problems, e.g. globally scoped i variable, setTimeout pushing the operation it to the end of the message queue, floating point precision in JS, etc...
  • 0
    @daintycode no, you still have the floating point precision issue.
  • 8
    @terminalterror with all respect, this is not refactoring in my opinion.
  • 2
    @samarthagarwal true, it's not. It's fixing 'broken' code.
  • 3
    1. This is a reduce pattern.
    2. The bug in the code is i haven't defined in for loop, so it has side effect.
    3. The timer is totally garbage
    4. There is a hidden problem which float number may not equal, it's safer to compare with int, use round, floor whatever

    Conclusion: if they give you something like this, they probably think most of junior developers r stupid.
    Tell them you are not!
    @terminalterror
  • 3
    @terminalterror true, it's bugfixing. But there is no ideal solution, so you shouldnt expect from the guy to find every bug without help.

    But if he claims to have 2 years experience and doesn't even find one thing wrong with the code... then he clearly is underqualified
  • 0
    You should give him some time 😂
  • 1
    @FrodoSwaggins setTimeout to drive you crazy, => are arrow functions. A bit like lambdas, bound to their initiator and unable to be rebound via .bind or stuff like that.
  • 3
    I’ve been learning JS for about 4 months now. I know what an array is.. and I removed setTimeout and thought that was it but scrolled through some of the comments to see it still returned false.

    It’s tough but if he’s been practicing JS for 2 years.... lol he’s full of shit. And if you held my hand at all I’m sure I’d get it.

    I didn’t read all the comments to know if the answer was posted.
  • 0
    @daintycode cool. I didn’t know about ++i
  • 2
    When I was a junior dev fresh out of college, I was intimidated by the fact that plenty of other devs applying for the same positions claimed to have more experience, that made me look down on myself and believe I couldnt compete against them, but later on I realized the job market is full of clowns saying they have many years of experience, but aren't capable of write a simple fizzbuzz program.
  • 1
    @FerDensetsu just got on this website and reading this discussion gives me hope to succeed. 😁
  • 2
    Trick question!
    console.log always returns undefined
  • 0
    Couple of problems, if you don't want to remove the setTimeout call, you can:

    1) Create an implicit closure by having for(let i = 0...)
    2) Create an explicit closure by wrapping the setTimeout call inside an IIFE like:
    for(..){
    (function(num){
    setTimeout....
    })(numbers[i]);
    }

    As for the comparison part, you can use Number.EPSILON, like:

    console.log( sum - 0.6 < Number.EPSILON )
  • 1
    Same solutions as an image if anyone's curious
  • 1
    @cmrickels to see if the person being interviewed understands that by pushing the operation onto the end of the message bus means it's not executed until after the current call stack has completed, meaning it doesn't take place within the current execution context and it has no lexical scope over the i variable at the points it gets incremented, so only has access to it's final value in the global execution context.

    ...hopefully I articulated that properly.

    There is no actual requirement in this use case beyond testing the applicant's knowledge, it could quite easily be making http requests instead of summing the values.
  • 1
    @terminalterror what would be your next questions though? I really want to try and answer the rest
  • 0
    @terminalterror @cmrickels no surprise webkit and v8 treat things differently
  • 0
    @cmrickels without working experience, there's no way to answer these kind garage correctly. Shame on the recruiter 😒
  • 1
    @sunfishcc OP is the recruiter, not the interviewee.
  • 0
    @cmrickels can you post screens?

    If you're talking about the 2923, 2943, 2949, as in this pic, that's just the implicit return value of the for loop.
  • 2
    @sunfishcc well the applicant claimed to have 2+ years commercial experience of JavaScript and jQuery.

    It's easy to dismiss this question as garbage, but if you can understand and fix it, then you demonstrate knowledge of the call stack, message bus, scope & closure, and the unreliability of numbers due to using IEEE 754 floating point.

    ...all in 8 lines of code.
  • 0
    You got stop using loops with side effects!
  • 2
    @cmrickels they would have been a Junior JavaScript Developer working on a system which essentially processes vast quantities of data. A solid foundational knowledge of _how_ JavaScript works and a good understanding of algorithms is essential.

    Not knowing that [0.1, 0.2, 0.3] is an array, well...
  • 0
    @terminalterror yeah, dude, that's like 30mins into programming knowledge.
  • 1
    @sunfishcc I think you're missing the point - the code is supposed to be shoddy and unreliable. It's the applicant's task to walk through the problem with me and fix it.
  • 1
    @terminalterror this is my fix.
    TLRD:
    Chrome used to use WebKit when safari still has windows version, but it didn't support multicore.
    Google then build multicore support based on WebKit.
    When Apple has their own multicore support, they are apple and orange already.
    1.JS is nonblocking, chrome,webkit, Firefox may have different behavior when interpreting same code.
    So any side effects is asking for bugs.
    2. Never trust float! This is why bitcoin implemented use a big integer
    🤔
    If you insist to use a for loop, use self calling function, to hide parameters inside.
  • 0
    This is another example, where JS has no integer type, only number.
    When it's really big, js treat it as float in 1.6...e18 format, so the integer losses precision.
    If NaN is a number, you should expect anything can happen when you play with number.😉
  • 3
    @sunfishcc NaN is my favourite number of them all 😁
  • 3
    I think that this code task is too much for a junior. You expect juniors to understand how closures, lexical scopes, floating point spec and event loops work in JS better than some mediors might. If I was a junior I wouldn't know what to do here at all. And for junior this kind of code is scary and when they are scared they forget even the normal things they knew. And to top it off, you say "refactor" when you mean "fix" the code, confusing even more. I think it was understandable that they didn't know anything at this point because their head hit a block.
  • 2
    Well I wouldn't be too concerned if he didn't get the float precision right, but the fact that he doesn't know what an array is? That's just a bit alarming...
  • 0
    The junior dev should have known what arrays are and all that. But expecting him to know that the floating point wouldn't perfectly line up is a bit much and nitpicky. That's something that would generally be pretty easy to find and fix.

    Now, if you wanted to give him the code, and tell him the equality is false and ask why, that would work to find out if he knows floats can have those issues.
Add Comment