Hacker News new | past | comments | ask | show | jobs | submit login
Interview gone wrong (ashu1461.com)
139 points by ashu1461 33 days ago | hide | past | favorite | 200 comments



If you know nothing about Python or coding, and you see a=b=c, you'd think that's true when all three a,b,c are the same. Python does that beautifully here, and that's the intent. It's not Python that's confusing, it's your previous experience with other languages that's confusing you.


I have some experience in computer language design. The issue here is that `a==b==c` expression is magical - that is it does not follow from extending comparison binary operator. Specifically, `==` is a binary operator that that compares an expression before and after and returns a boolean. In this case, A==B==C is a trinary comparison operator. This is normally ok, except it's rare and the symbol it is using is overloaded with binary comparison operator, so the people will be confused.

This actually gets weirder - in python you can make an arbitrary long comparison operator - it's called comparison chaining - https://www.programiz.com/online-compiler/6uyqb52IVH8if . It works with a lot of operators - https://www.geeksforgeeks.org/chaining-comparison-operators-...

Once you know how it works and are used to it, I think it makes the code easier to parse... but there are heavy downsides. For example, it's not clear how short circuiting works. I've used python a bunch and logically I expect ```side_effect3()``` to not be evaluated if results of 1 and 2 are not equal: ```side_effect1() == side_effect2() == side_effect3()```. However, I do not know that for sure, while in other languages I would be able to reason about this from basic principles.


> the symbol it is using is overloaded with binary comparison operator, so the people will be confused

I think most people would expect expressions like `5 < x < 10` to work as they do in math, without necessarily thinking about it in terms of being an overloaded binary operator. The result in other languages that `5 < 12 < 10` = `true < 10` = `true` is more surprising, just that we've (perhaps by being bitten by it early on) gotten used to it.


Yeah, but should that math equivalence hold for programming though? Programming is different. x=x+1 is perfectly legal in programming but does not make sense in algebra math and could confuse mathematicians.


> should that math equivalence hold for programming though?

It's not a hard rule that overrides all other considerations, but I do think Python's choice to follow math is the right decision here.

I'd claim if you teach someone `<` then show them `5 < x < 10` for the first time, they're far more likely to go with the math interpretation than the C one. That is, beyond the fact that someone's familiarity with math reinforces this intepretation, the reason for math using this interpretation in the first place is because it aligns with intuition.

It's also just pretty useful. It's common to want to check if a number is between some bounds, like `0 <= i < len`, or that multiple things are equal. In cases where you really do want the C behavior, I'd say you should already write that as `(x == y) == z` for clarity anyway, regardless of whether the language lacks chaining and thus lets you omit the parentheses.


Maybe = should actually be := which it is in some languages?

x = x + 1 sounds wrong if you are in math mode

x := x + 1 is uncommon in math and you can take it to mean "set x to whatever is currently x, plus one"

But it's also true that you need to be able to accept certain conventions when changing fields.



It's a completely useless question - it's language trivia. It's like asking "what happens if you do X in database Y version Z and up". Who cares? It's something you figure out when you get there. There are tons of examples of something like this where it's language-dependent, so don't even bother memorizing this stuff.

I once passed an interview where it was all just Spring documentation questions. I had never built a Spring app in my life, I just "read the docs" five times.


Is “let me check the docs” an appropriate thing to say in an interview setting?


It’s what you’d do on the job, right? A place which dings you for checking your work is broken.

I’d expect a raised eyebrow if it was some very basic question about something you’ve claimed to be an expert in but given how many, many bugs over the years stem back to confusion about order of evaluation I would consider it a minor plus if someone said “I think I know but I want be certain”, and a major one if they paired that with mention of defensive coding practices like adding tests covering cases where it’d matter and structuring the code so there are no side effects hidden in the test (e.g. the code as written is fine but if it was f1() == f2() == f3() I’d probably write it as a clearer multi-line if block when there are side effects to those calls to make obvious when I’m intentionally not doing them in every case).


I'd prefer a candidate to check the docs or look something up if they were unsure, because that would also provide useful information to me as an interviewer.

Although I'd also want that benefit of the doubt for myself. I'm quite familiar with how Ruby handles collections, for example, but if I tried to use `slices.Collect` in Go the same way as `Enumerable#collect` in Ruby I'd end up stuck and would need clarification.


Yes.

Extra points if you are familiar enough with the documentation to find the answer quickly.


yes.


It absolutely is.


Agree, also by reasoning from basic principles adding extra brackets ( ) should not change the output result - at least this is what our brain is programmed to believe, but in the case of chained operations it will.

Example

(a==b)==c would be different from a==b==c


>> but there are heavy downsides. For example, it's not clear how short circuiting works.

Opinion: Code that depends on side effects like that in a conditional is BAD. It is not an optimization, it's an obfuscation.


Most programming languages ought not to be optimized for a non-programmer to read, but rather for someone who writes code to read.

There's a lot of options for a language to deal with a statement like this. It could be a syntax error, a compile or lint warning, it could work by doing order of operations and comparing the boolean from one compare with the third element, or it could work in the way you described.

I'd prefer languages that I work with to chose earlier options from that list. In most languages this sort of statement is usually a bug, and deserves explicit parenthesis to clarify the order of operations. I really don't want to have to pull out an operator precedence chart in order to read your code, much less have to look up some esoterica about this specific language.


I'd argue that many programming languages are not optimized for "people who read code" but they are optimized for programs who read code (compilers, interpreters) and programmers can stockholm-syndrome themselves into believing that it is targeted at them.


Code optimised for an interpreter is often also optimised for the programmer, whose primary job is interpreting code. What makes natural language intuitive is that it doesn't have to be precise. You can assume language does what it is intended to do. A programmer, by contrast, must know exactly what the program does. You cannot assume it does what you want it to do because the computer doesn't know what you want it to do. A language cannot be made less precise by the addition of new rules; it is only made more complicated as there is more to remember. In this example, the person writing the ternary expression had to learn that it exists. If it didn't exist, there would have been less learning to do. Perl is the limit of this process – a language with many rules to appear natural and human-like that it's almost impossible to actually read.

Each rule of a language is a cognitive burden. It can only justify itself if the thing it replaces is a greater burden.


"someone who writes code" is very vague. For someone who writes code primarily in Python this behavior is less surprising than the rest that you described.


Intentionally so.

I've worked primarily in Python for the last two years and I'd still have to look at a reference to be certain of what exactly this code does. And would probably rewrite it to the expanded, parenthesized form unless the company linter insisted.


> I really don't want to have to pull out an operator precedence chart in order to read your code

Hard disagree here. I write code for people who can read the language. This includes operator precedence.


>I write code for people who can read the language

Programming languages often have syntax that's acknowledged as a source of confusion and bugs and better avoided. The line is not hard and fast, but I write C++ and there's "C++", and then there's "the C++ subset that you should use" (I probably couldn't write C++ code without tools slapping me for using the wrong parts). Operator precedence is debatable but our tools force the use of parentheses to disambiguate.


This is true, and, in this case, "confusion avoided" and "what Python does" coincide. The "double equals doing the right thing" is only confusing if you're both unfamiliar with Python and familiar with language design, which is a very small set of people.

People unfamiliar with programming will assume that "if a == b == c" is only true if all three things are the same, and people familiar with Python will know that that is, indeed, what it means.


The more complex an expression grows, the less well it works to rely on operator precedence to indicate structure to the reader.

Additionally, I think assuming the reader is aware of every. nuance of the language is an extremely bad idea unless you are and will always be the only developer. If you are doing anything weird or tricky or rare, I'd highly recommend linking the documentation or providing an explanation.


Most programming languages ought not to be optimized for a non-programmer to read

Python 'won' mostly because non-programmers could look at it, more or less understand what was going on, and feel that this was something they probably could learn.


> It's not Python that's confusing, it's your previous experience with other languages that's confusing you.

"There are no children here at the 4H club either! Am I so out of touch?

No... it's the children who are wrong."

-Principal Skinner, "The Simpsons"

EDIT to clarify- I'm just being silly, not suggesting anyone is right or wrong here.


What does A == B == C even mean? I mean I know what mathematically A=B=C means. That A, B and C are all equivalent.

But then is the mathematical '=' really a binary operator that maps two numerical inputs to a boolean output? It feels then as an abuse of notation if (A=B)=C doesn't allow A=B to change type?

Because I don't really have much use for a symbol that is some times doing a binary mapping from numbers to booleans and some times becomes some sort of ternary operator which maps 3 inputs to one boolean.


Maybe consider chained comparison operators early textual replacement along the lines of the C preprocessor, although the exact textual replacement would involve temporary variables to avoid multiple side effects and be more complicated than just "(a) == (b) and (b) == (c)". (a==b)==c does not expand, only the version without parentheses expands, so you can still do the boolean comparison if you want.


Yeah, the behavior is arguably much less confusing than the alternative of:

    5==5==5   # All three the same
    (5==5)==5
    true==5
    false
Or

    1==2==false # All three different, in a troublesome way
    (1==2)==false
    false==false
    true


I dunno, I'd expect the right hand expression (2 == false) to be resolved first, then compared to 1.

Compare this with

    a = b = c = 5
You evaluate the innermost (i.e. the tail) expression first, and work your way out to the head. As a sexpr it is a little more obvious that way:

    (= a (= b (= c 5)))
An argument could easily be made that python is making up special rules for the equality operator by treating the duplication of the operator as merging the expressions into one.

Instead of what you would expect, per the rules of literally every other expression, 5 == 5 == 5:

    (== 5 (== 5 5))
It gets rewritten as

    (== 5 5 5)
Which one is "unexpected" is really a matter of perspective: are you reading with the rules of English or the rules of your programming language as your context?

I do concede one caveat to this argument: mathematical operators tend to change operator precedence around to avoid making mathematical mistakes. I am mildly of the opinion that this itself was a mistake. Most calculators don't do it, so it's not like anyone would be* that* thrown off by it.


> An argument could easily be made that python is making up special rules for the equality operator by treating the duplication of the operator as merging the expressions into one.

I guess the argument could be made but it would be wrong. All the comparison operators can be chained in python. a < b < c, for example, or even a == b <= c < d.


> You evaluate the innermost (i.e. the tail) expression first, and work your way out to the head. As a sexpr it is a little more obvious that way: `(= a (= b (= c 5)))`

That's not true in Python though.

    a = b = c = <expression>
is equivalent to:

    temp = <expression>; a = temp; b = temp; c = temp
I don't know why that order of evaluation was chosen.


> If you know nothing about Python or coding, and you see a=b=c, you'd think that's true when all three a,b,c are the same.

Sure, that's true if you literally know nothing about coding. But that is not a very common audience for reading code. You only need to spend about 10 minutes coding to realise that the compiler follows fixed rules rather than making an LLM-like guess as to the meaning. If you get that far then most people (admittedly after a bit more 10 minutes) go on to realise that the only way to know what code does is carefully pick it apart step by step, rather than glance at it and guess yourself.

I love Python dearly, but this rule was a misstep on my opinion.


The problem isn’t meaning or intent its inconsistency of operator behavior.

1 + 1 + 1 has different operator behavior then 1 == 1 == 1. The operations here are not consistent and it’s not clear what happens if I overload the operators.

On the surface level python looks more beautiful. But mathematically speaking python is actually more ugly and more inconsistent with weird rules to make things look a certain way.


If you know nothing about Python or coding it is not really relevant as the code is probably read and written more by those who know coding and/or Python?


Yet another way in which Lisp is vastly superior to any and all blub languages:

  (= 2
     (+ 1 1)
     (sqrt 4))
  ; => t

  (< most-negative-fixnum 0 most-positive-fixnum)
  ; => t


I have no idea what this does or if you are joking. Could use some explanation


In Lisp, you put the "operator" first, so instead of

  2 + 3 + 4
you write

  (+ 2 3 4)

This is nice for associative operations like + or *, very very very slightly confusing for - and /

---

You use the same style for comparisons, so instead of

  2 == 3 == 4
you write

  (== 2 3 4)

To support the fist "infix" syntax, you need some magic in the == operator. But the second "prefix" syntax is totally natural and you need no magic in the parser or the operator.


I knew that Lisp does this operator first thing, it's everything around this that I'm not familiar with. What does ; do? Is the => an arrow or greater than or equal to? What is t? Do I guess correctly that most-negative-fixnum is like INT_MIN?


The semicolon is Lisp syntax for comments. T is the way you write true in Lisp. Most-negative-fixnum is the most negative number Lisp can represent without promotion to bignum (so it can be int_min if int is roughly equivalent to size_t).


> very very very slightly confusing for - and /

It's fine if you DNF it:

  (- a b c) => (+ a (- b) (- c))
  (/ a b c) => (* a (/ 1 b) (/ 1 c))


In the Lisp family of languages these comparisons are not implemented as operators, but functions.

The functions behave like:

= all the same

/= all different

< monotonically increasing

> monotonically decreasing

<= monotonically nondecreasing

>= monotonically nonincreasing

Also * is product and + is sum.


So Python is a Lisp?


I know the point of the piece is the python syntax here, but I got stuck on: "judge things like code quality / speed / conciseness etc."

Do people generally write concise code on right off the bat when confronted with a new problem? I've always taken the same approach I would with writing: get something that works; refactor for concision. Maybe everyone else is playing 3D chess and I'm still on Chutes and Ladders?


There are degrees of conciseness.

I've seen real code that looks like

    if(bool_var == false) {
      other_bool_field = true;
    } else if(bool_var == true) {
      other_bool_field = false;
    }
Which I suppose could be called anti-concise.


Yes, even the "unconcise" first draft of anyone who cares enough to be here on HN is much better than some of the code out there.

There's a basic level of concision you'll have by default if you actually understand the problem and the tools. You won't go away out of the way to complicate things. Maybe it's still a far cry from optimal, and definitely not code golf, but enough that I'd be worried if I saw even a first draft without it.


When I see code like that, I wonder whether a beginner is trying to fix a bug where they unexpectedly copied by reference rather than value.


yes, when writing this as other_bool_variable=!bool_var you make it much better because the code speaks for itself ("other_bool_variable is the opposite of bool_variable").

The risk is that you may end with such concise code that nobody understands what it does. I went that dark path with perl 20 years ago, form "oh what a cool language for someone who comes from C" to "let's squeeze that in half a line, and either do no understand what it does, or add three lines of comments to explain".

But yes, there is a good middle-groud somewhere


I wouldn't consider if (bool) or x = !bool to be concise coding. That's just regular code.


Everyone thinks differently. "thing1 == thing2 == thing3" is a pretty natural expression of the idea here IMO.


Do people generally write concise code on right off the bat when confronted with a new problem?

As someone who has been on the interviewer side: this is an indicator of how much the interviewee "thinks first"; the ones who immediately start spewing tons of code are usually those who don't really have a good understanding of what they're trying to do.


As someone who's done a lot of interviews on both sides: I get where you're coming from but don't really think it's as universal as you think. Some people gain understanding through doing; and there's nothing wrong with that?


Thinking first is a very Cartesian approach to development and not necessarily the best way. Many people think through a more engaged approach of doing


Thinking by doing is also valid.

I code similarly to how I write, which is similar to how I draw etc. I start with very rough ideas and sketches, then I gradually iterate over those, refining ideas and throwing bits away. And eventually I have a working version/first draft/etc

I just can't get things done if I were to try and think of the entire solution first before getting anything down on paper. Maybe that's an ADHD thing, needing to let the idea take form lest it runs away and I get lost in the weeds

It's less "spewing tons of code" though and more starting with an outline, stub functions and comments to break up the steps before filling those out.


Exactly, amen to that.

Think first, code second.


if you know the domain for the task at hand (+a few very basic soft skills) you can learn a lot from watching and discussing with a candidate while they are doing the task.

In reality - tasks like these are garbage leet-code samples; candidated who have been grinding examples rapidly regurgitate the best solution from the forums and impress the interviewer, but would fail if asked a basic question on what they produced. Those that solve it reasonably from first principles fail the task.


There are problems I have encountered a billion times and of course I have an elegant concise solution for it, if I am an experienced programmer.

    if any([a in ["-h", "--help"] for a in args]):
        display_help()
Would be one of those. Generally I learned that it can be beneficial to treat things as lists early on, e.g. if you have a program that takes one input file it costs you next to nothing to allow the input to be mutiple files as well.


Fun Python fact time!

`any` works on arbitrary iterables, so you can use a generator comprehension instead of a list comprehension:

  if any((a in ["-h", "--help"] for a in args)):
      display_help()
Which algorithmically is a wash, because the time you save not-materializing the list, you waste in the overhead of iterating through a generator (and it's all +/- nanoseconds in recent versions of Python anyway). However, Python has a special syntax that allows you to omit a layer of parentheses when a generator comprehension is the only argument to a function, leaving us with the very elegant (IMO) syntax:

  if any(a in ["-h", "--help"] for a in args):
      display_help()
This works for any(), all(), str.join(), and others. Yet another demonstration of why I think the iteration protocol is one of the best features in Python (and underappreciated as such).


ah cool, I didn't realize


That still looks like something that a novice might trip over when reading this. Just describing what it does is already a bit convoluted: it tests whether any value of a list of booleans, produced by a generator expression by testing membership of a value in some other list, is True.

I would have gone with the following, as it requires less mental unpacking:

  if set(args) & set(["-h", "--help"]):
      display_help()
Also, note that any() works with any iterable, the outer brackets are not needed given the list expression.

  if any(a in ["-h", "--help"] for a in args):
      display_help()


Being extremely pedantic, omitting the outer ()s is legal for a generator comprehension. That is, the following are equivalent:

  foo(x for x in xs)

  foo((x for x in xs))

  gen = (x for x in xs)
  foo(gen)
But these are not the same as:

  foo([x for x in xs]

  lst = [x for x in xs]
  foo(lst)
It doesn't matter in this tiny example, but the difference between generators and lists can be very very important when working on very large amounts of data (e.g. processing a big text corpus), or a potentially-infinite stream of data.


on my phone and a bit discombobulated today, so we’ll see how i go with this

> That still looks like something that a novice might trip over when reading this.

my experience with “juniors” who start with python is that they think in lists and dictionaries. they don’t think in terms of set theory. that’s just the way python is taught.

i would definitely set interview questions where a “decent” solution involves using sets and see who gets it without iterating over lists (ha, setting an interview question on sets… geddit? i’ll see myself out).

> Just describing what it does is already a bit convoluted

yeah, but python only/main “juniors” primarily think in terms of lists, see above.

so, between making sure all juniors can read the code versus doing it succinctly, but juniors all need to learn about sets — practicality wins out quite often.

> I would have gone with the following, as it requires less mental unpacking:

> if set(args) & set(["-h", "--help"]):

> display_help()

if i were reviewing this code i’d ask you to switch it to

    if set(args).intersection(set(["-h", "--help"])):
it is more verbose and more brackets, but it is more explicit and obvious what is happening to some junior who has never dealt with sets before (hmm what’s an intersection? should probably google it)

& is also used for the bitwise AND operator. plus some other stuff in various frameworks like django. so could lead to some confusion.

> Also, note that any() works with any iterable, the outer brackets are not needed given the list expression.

i generally HATE the overuse of generator expressions in python. everyone writes absolutely everything as an inline generator expression, making it hard to test.

but, rant aside, yes, this is probably the one i would pick during a review (likely after a discussion about how using the intersection method makes things less legible and then this gets suggested somewhere).

people don’t realise not every genexp needs to be a list. easy mistake to make with the “everything is a list or a dict” mental model.


".intersection()" takes any iterable, it can be:

    if set(args).intersection(["-h", "--help"]):
Also python has had a special syntax for sets since 2.7 (I think), though I haven't seen it used very often:

    if {"-h", "--help"}.intersection(args):


It makes so much sense to think about this as sets, thanks


Yeah - when I went through University the mantra I was taught was

1. Get it working

2. Get it working well

If you're faced with an unfamiliar domain, you don't rock up to it and throw all the super optimised fastest code at it. in fact I would view someone who did as having done the test before (making it worthless).


But the code doesn’t work. That should be problem nr 1 for such a simple problem.

Syntactical sugar doesn’t matter anymore at that stage


Maybe I misunderstood the piece, but it seems the last sentence, "Well the code is indeed correct" suggests it _did_ work (although I'm also a little confused about what it means when all values are '-' which I interpreted as 'no piece played').


The code might compile, but it does not functionally with in an empty game state. Resulting in an always win for the first player if he does not play on any diagonal


I also judge code quality at the interviews that I perform. I just give the candidates time to improve their code after they come up with something working.


I'm confused about this blog post. Python is mostly C inspired but actually more pseudocode inspired (which helps its popularity) which is why chained expressions exist.

Also, why would you conduct an interview in a language where even if you don't know the syntax (and this is obscure) you could have looked it up or disallowed the interview to be done in Python? I think the due diligence with this issue is more to the interviewer than Python.


> Also, why would you conduct an interview in a language where even if you don't know the syntax (and this is obscure) you could have looked it up or disallowed the interview to be done in Python?

The norm in most of my interviews has been that candidates can solve coding problems in whatever language they are most comfortable with. For most languages like Python etc, it would be a mistake to reject a candidate just because they don't have experience with that specific language.


The norm in most of my interviews has been that candidates can solve coding problems in whatever language they are most comfortable with.

I assume they've already filtered out candidates whose "most comfortable language" isn't the one they're hiring for, or they're going to have a difficult time when they come across the one who wants to use APL or x86 Asm.


I heard a tale of a candidate white boarding in an obscure language (in a bit of an attempt to hide a deficiency), unfortunately for the candidate the interviewer happened to be well versed in the language and saw right through the charade.


Hah. Even if the interviewer didn't see through the charade they have plenty of time to check the code after the fact. Once or twice a candidate has done something I didn't know about so I just googled it. Nice little learning opportunity for me.


I always interview for generalist jobs in python, but most jobs I’ve done use other languages.


Mate, let's be honest, we've all been in interviews where the interviewer had a serious misunderstanding of the language the job was supposedly using, let alone some other language.


In this respect, Python makes a lot more sense since that is how you'd normally write such an equality in math, and generally how people chain them: A=B=C means A=B and B=C.

Part of the problem here is that we treat true/false as "just another value" in programming, and thus the usual operators are used to compare them. In math notation, if you wanted to compare the result of comparison A=B to a Boolean value C, you'd normally write something like (A=B)≡C, using different operators for equality and equivalence.

Interestingly, programming languages haven't always treated Booleans in this way. If you look at ALGOL 60, it starts by cleanly separating expressions into arithmetic and logical ones, and defines completely different sets of operators for each (the reference language also uses = for numeric comparisons and ≡ for Booleans; and boolean inequality is, of course, just XOR).


I think that the main issue here is not treating true/false as values but allowing them to be implicitly converted or compared to numbers with the assumption that true equals 1 and false equals 0.

I think that Rust got this right. It doesn't allow you to add integer to boolean or multiply boolean by float etc, because it is unclear what does it even mean mathematically.

Also, most languages implicitly assume that any value of any type is either "truthy" or "falsy" thus you can do something like `while(1) { do_stuff() }`. Rust doesn't allow this BS, `if` and `while` expect a boolean so you have to provide a boolean.


That resolves the problem for other types, but you still have the case of (a == b == c) being parsed and evaluated as ((a == b) == c) if all three are booleans, which is still not an intuitive interpretation. I think the PL either has to ban such construct outright and require parentheses, or treat it as an n-ary operator like Python does (albeit perhaps with a few more constraints on what you can chain, for the sake of readability).


I've just checked [0], Rust bans such construct for booleans as well.

[0] https://play.rust-lang.org/?version=stable&mode=debug&editio...


Great error message, too.


That is impressive.


A lot of languages have no boolean primitive to begin with. Often in older languages, the values for `true` and `false` are aliases for `0` and `1` respectively. Perl and earlier versions of C, Python, and JavaScript are notable.

Perl is probably the most awkward due to context-sensitive casting. e.g. the string `"0"` in a boolean context evaluates as an integer, and the boolean interpretation for `0` is false.


JavaScript had Booleans as a primitive type as far back as I can remember. The problem, rather, is that it's altogether too eager to convert everything into everything else.


Sometimes Perl uses "0E0" as a value that is equal to zero yet not false. Javascript has even more cases where equality isn't transitive.


Indeed, and likewise, I think Pascal would have thrown a compile-time error due to a type mismatch.


I think it makes sense in python for ==, <=, >=

I cannot see it for !=

"a != b != c" is not equal to "not (a == b == c)" which is a bit strange imo


I don't see how you could interpret "a != b != c" as equivalent to "not (a == b == c)" in the first place. In the first expression a doesn't equal b and b doesn't equal c (no restriction on a and c). In the second expression you could have a == b, but b != c (and vice versa), clearly that's not equivalent to the first expression.


"a == b" is the same as "not (a != b)"

Maybe I'm simple minded though.


If you treat each "!" as a NOT, then (a != b != c) has two NOTs, but !(a == b == c) has a single one, so this is a bit like expecting that !(a && b) is the same as (!a && !b).


"a == b == c" translates to "a == b and b == c", similarly "a != b !=c" translates to "a != b and b != c"


This is a tangent, but checking if all the elements in the diagonal position are the same is not sufficient. You also need to check that any of the elements are not '-'.


Depends how the flow goes. It's reasonable to only check the diagonal when one player has actually played on the diagonal, in which case this is fine.


That’s… what the article says.


That’s not what the article says. The last paragraph:

  if (cell[0][0] == cell[1][1] == cell[2][2]) {
      return Winner
  }
> Well the code is indeed correct . Well done, Python… for finding yet another way to confuse us all.

The code is incorrect: if all entries are '-' there is no winner. Even ignoring the braces…


You do not know how the game was implemented to assume that.


To be fair to parent I read the whole thing and also missed that.


Stopped judging candidates on "style" due to stuff like this. I only comment if the code doesn't work, if it works i don't really bother to correct code style or provide feedback on it.

45 minutes interviews aren't really the place to evaluate this.


It sounds like the author wasn't nitpicking style - they thought the code literally wouldn't work.

(But, the intent on the interviewee's part was definitely clear - I'd definitely let this pass.)


The blog itself isn't clear, and I think that's confusing some of the people here:

> The candidate this time was programming in python

But the code blocks aren't in python. But in the paragraph afterwards they capitalize "True" which is a python thing. Then afterwards mention they're using javascript as their reference, which uses "true" instead and the code blocks could be javascript.

It feels like the author has more language confusion going on than just this one feature of python.


That's why i put "style" in quotes, the interviewer didn't know about the feature but still decided it was "wrong" or "ugly" even though the code works.


Linters are for this.

You need to detect if someone is humble and smart enough to fit in to how you do things as a team, whatever that is.

Not reject someone for not hitting a style guide on a piece of paper tucked behind a hidden secret door. (As I was once!)


If your knowledge of Python comes from JavaScript, I would not blame Python for it. It's the failure of the person to not "read the instructions" and assume instead. Maybe conduct interviews in languages that you're familiar with?


If you were programming long enough, you easily had contact with dozens of languages. How do you pick up a new language? You can't really treat it as your first one. Especially if you need it "for yesterday". You won't read about "if" or "for". No, you scan for what's different from what you already know. If you're lucky you'll find "python for javascript programmers", but that probably won't go into non-core details like this. In practice, you learn basics first and start coding. Then you find a piece of code somewhere that you don't understand. That's a learning opportunity! However, it's easy if it's a function since it's easily googlable. Operators are harder to search for, for instance in new versions of C# you have operators like "?." (just an example). Since googling is hard you go to some "operators documentation" and try to find it there. And hope that it covers the new version. For cases like this story it's even harder because it describes a concept (chaining) and you maybe don't even know which name is used for that.

At least ChatGPT recognized and explained it correctly, so it makes picking up new features easier than it used to be. I'm making a mental note to ask LLMs whenever I encounter unknown constructs.


If it’s a language I don’t know, I’d still read a book or check the doc for a tour of the syntax. I can scan one in a couple of hours and get an overview I can refer to later for a more specific question. Even if I needed it for yesterday.


Python evaluates `2 == 2 == 2` to true. JavaScript evaluates the same to false. Somehow we've decided that Python is the weird one it seems.


1 == 1 == 1 is actually true in Javascript due to type coercion

You're probably thinking `1 === 1 === 1` which is indeed false


I tried 2 == 2 == 2 in my browser's (Chrome) console and it evaluated to false.


I stealth edited my post. Sorry.


Not in my browser console. (but it's true for a different reason)


To be fair, there are edge cases [0] when it does look weird.

[0] https://github.com/satwikkansal/wtfpython?tab=readme-ov-file...


I am idiot but I would, and have in the past, have wasted the whole interview time argue in that I am right and he is wrong.

Yes, John, some switches do start sending the packet before finish receiving it. It’s called cut-though switching. Hope you googled it. And yes it was worth losing the job offer over it.


I would say if you know you have to later work with the guy and he will be higher up than you this is actually smart.


John says you were wrong then and you are still wrong now. When talking about the problem domain John also mentions some switches do start sending the packet before finish receiving, it's called cut-though switching.


Didn’t get you..


Python chained operators can be confusing, especially as it allows you to write things like: — x < y > z — a in b not in c

WalterBright mentioned that D will give you an error. When designing Starlark (a derivative of Python), I also decided to give an error for this, by making the comparison operators non associative.

https://github.com/bazelbuild/starlark/blob/master/design.md...

I agree this Python feature can look cute, but I've found it's rarely useful and can easily be avoided.


I find these expressions a lot more readable for bound checks (like `if 0 <= n < len(something):`) compared to the imperative `if (n >= 0 && n < something.length)`. This was especially true when I used it for homework, where constraints described in mathematical form were a lot more common than when dealing with real life software.

The way it works in Python allows for some hilariously unreadable code, but the concept itself is good. I think it just needs more constraints to maintain readability, such as not allowing flipping the comparison sign (like in x<y>z).

Banning these chained comparison operators is not necessarily a bad idea as comparison operators can easily cause confusion in that manner, but the reason they cause confusion is that many programming languages use mathematical symbols differently than actual math. A=B=C is perfectly understandable and more readable than A=B ∧ B=C. Restraining ourselves to "operand operator operand" as the only infix expression model made sense decades ago when computers had storage counted in kilobits. Today, we can let go of the limitations of yore and use mathematical expressions in a way that plain sense.


If you write the bounds check in the same order it's really not that bad: (0 <= n && n < something.length)


Unit tests should be part of the interview too. As should googling the behaviour live. Missed opportunities to go beyond the bland exercise to see what it is like pairing up with this person.


Any time you use language specific tricks in an interview, you’re probably going to confuse your interviewer and not do well.


I disagree: if you are demonstrating your mastery of a language (and with Python, these things are important: using appropriate syntax is the difference between dog slow code and fast code), you should use idiomatic patterns like the above.

Another of Python features is a great REPL: when unsure or confused by an interviewer, I'd just fire python from shell and type in 'x' == 'x' == 'x' to confirm and demonstrate it does the right thing (or write tests).

Obviously, the interviewer should be careful not to sidetrack the candidate much, and let them do the work and attempt to help only if things don't work out.


This is my opinion as well, but unfortunately isn’t always held by others. I once interviewed and by dint of knowing Python’s itertools module, absolutely destroyed the interviewer’s questions that they clearly thought would take some time to do.

I was told later that while I “obviously knew Python quite well, it didn’t give a good signal for my capabilities.”


>I once interviewed and by dint of knowing Python’s itertools module, absolutely destroyed the interviewer’s questions that they clearly thought would take some time to do.

If I see such a situation I usually ask the interviewer whether they want a concise solution using libraries or they want to see how I would do this if I had to do it from scratch.

Or I just offer both, I show that I can do it, but that I know it would be easier to do with x.

I think this is a great opportunity to show you're a good communicator as well as a problem solver.


Fair point.


In the real world you iterate, profile, and optimize


I am definitely a subscriber to not doing premature optimization, but in Python, there is a huge difference between

  found = searched_key in list(large_dict)
vs

  found = searched_key in large_dict
But also compare:

  searched_key in large_dict.keys()  # O(1)
and

  searched_value in large_dict.values()  # O(n)


So much this. Write code that you can reasonably expect to not be slow af, while not sacrificing readability. Then profile and optimize if necessary.


In this case the candidate evidently didn't understand it either, but was repeating a pattern they had seen before, which IMO is a form of anti-mastery: don't do things that you don't understand, especially when you're supposed to be demonstrating your skill and understanding.


Having a candidate understand all of the edge cases of a language syntax is a very high bar to clear: there is a lot of programmer between a "master" and "anti-master".

I've used Python for 20+ years, and while I'd confidently use a == b == c or 1 < a < 10, I didn't know the specifics and wouldn't use it in cases like 10 > a < 8 (or really, any other case chaining supports).

I believe myself to be an expert at Python and I'll explain differences between different loop types (while/for, ranges/iterators/generators, list comprehensions, functools, external C libraries like pandas or numpy), I think I wouldn't be confused only because I am aware I don't know the details and have a quick way to prove it works.


Maybe I interpreted the article differently than you did.

I got the impression that the candidate was repeating the x == y == z pattern because they'd seen it in other people's code and was pretty sure it worked, not because they knew about comparison chaining. At minimum I'd expect a candidate to be able to clarify that (x == y) == z is not the same thing, not just "idk it works whenever I do it". My reaction to that was: at some point, you do need to at least be able to reason about your own code.

In a more generous light, yes, I agree with everything you wrote. The precise details of comparison chaining are out of scope and I'm sure that most Python developers (myself included) don't know or remember them.


I agree that anyone (including an obviously juniorish candidate) using it should be able to explain it to an extent, but maybe not if you confidently and wrongly claim it doesn't work as an interviewer :)


But it's not a "trick", it's just a normal Python code.

I don't think that anyone who main programs in Python would perceive it as some kind of cool/unusual trick and not just normal code.


It's not a trick though. It's normal Python code. It's so common that you don't even think about it. It's just how equality comparisons work in the language.


If you're used to python, you wouldn't consider it to be a trick.

If you're giving interviews, and evaluating code in a language you don't know, don't be so confident it's wrong. Ask the candidate how it works.


I've used python for ~2y now and I'd balk at and rewrite this statement, considering it unclear at best.


That's an entirely reasonable point of view.

The important part here is that there are a substantial fraction of python developers that don't share your sentiment.


In this case the candidate also didn't know.


My usage of "yield" (alongside knowledge of "prange" from numba) in an interview instead of return has sealed the deal on a 200K offer (ML role circa 2020).

"Confusing" the interviewer is a totally valid strategy! It's the only strategy when python async is involved!


I suspect the interviewer would have likely been fine if they’d been able to explain chained comparisons and how they work. I would probably consider the interviewer using them without understanding them to be a negative signal.


It is possible that the candidate would normally use it from muscle memory, but got confused under the stress of the interview.


Fair enough. In general, I think the interview is a pretty lousy way to measure how good a software developer is.


“Language specific tricks” are the entire value proposition of there being more than one language.


Why did the author consider this an "interview gone wrong"? What was "wrong" about?


Interviewer made a mistake and confused/sidetracked a candidate in a short interview.


If the interviewer is a good interviewer - they inadvertently gave the candidate an oportunity to demonstrate a range of skills.

An outstanding candidate when questioned would mention that in most languages this evalates to that, but in python it evaluates to this, and offer an alternate method chaining and's on the spot in response to the confustion.

If they are a bad interviewer - they would allow their ego to derail the interview.


An outstanding candidate might be an average candidate in a wrong setting.

With my last job, I fumbled an easy question for me that I usually wouldn't, but it was a 10pm interview after I got up at 4am that morning and have almost fallen asleep when putting my kids to sleep at 9pm. I got the job (and then got promoted twice in 18 months), but if interviewer "inadvertently" confused me on top of my mental state, it might have been game over for me (and them, since I turned out to be an "outstanding" candidate).


The interviewer made no mistake though, they made an observation; they were confused by the boolean expression. The candidate said they understood the interviewers concerns and was also confused, and didn't have an immediate answer. This is all normal and healthy, and something you'd commonly see in healthy and competent development teams.

The only thing I see that's wrong is that the interviewer thinks something went wrong.


Mistake:

> ...the statement even though logical, is not technically right because if we start from the left cell[0][0] == cell[1][1] would evaluate to True and then True == cell[2][2] would evaluate to False given that the cell contains a char.

Interviewer seemed confident ("is not technically right") which confused the candidate:

> I told the candidate about the same and he agreed but he was confused at the same time

Candidates are already in a high stress situation, you don't want to add to it unless you really know what you are doing (i.e. you are specifically looking for deep language mastery).

Interviewer has correctly realized they've done this and learned from it: kudos to them even if too late for this candidate :)


Interviewer made a mistake, stop rationalizing.


But is it "wrong" to make a mistake?


You said earlier:

> The interviewer made no mistake though

So is it wrong to admit that you made a mistake? :)

And no, it's ok to make mistakes, but it is even better if we admit to them and learn from them (and the faster we do that, the better it is).


everyone knows the purpose of an interview is to prove that the interviewer knows more than the interviewee, thus the interview failed


Raku (https://raku.org) supports the same design as Python3 ...

  0 < 5 < 100;     #True
  10 == 10 == 10;  #True
The Chaining Binary Precedence is specified for this https://docs.raku.org/language/operators#Chaining_binary_pre...

That means you can make your own chaining comparison ops (or overload the current ones) with something like:

  multi infix:<~=>(Rat $l, Rat $r) { ($l-$r) < 0.1 ?? True !! False }
        is equivalent('<');
Much of Raku such as the default use of Rationals (Rat) is intended to make the language more approachable for non CS experts, so yes:

  0.1 + 0.2 = 0.3 # True


This mirrors mathematical notation for things like ranges or equality checks

5 < x <= 25

x == y == 10


Unfortunately, it's more permissive than mathematical notation: `3 > 1 < 2` evaluates to True.


I can think of some more interesting examples when it violates intuition gained from mathematical notation.

When looking at `a == b == c` we naturally assume that not only `a == b` and `b == c` but also `a == c` because equality is assumed to be transitive.

The problem is that in Python we can make `==` operator to do literally whatever we want, so in Python `==` doesn't have to be transitive.

You may argue that no reasonable person would define equality in such way that is not transitive.

To which I would reply that approximate comparison of floating point numbers looks perfectly reasonable to me.

    EPSILON = 10**-9

    class Foo:
        def __eq__(self, other):
            return other.bar - EPSILON <= self.bar <= other.bar + EPSILON


I love the fact that you defined Foo.__eq__ by means of a chaining comparison!


As someone who trained in mathematics, I would 100% say that mathematicians would evaluate it as true. It's not the cleanest way to write it, but intent is clear.


I think mathematicians looking at that expression would curl their lips in mild disgust, but also evaluate it to True.


D solved the problem with what happens with (a == b == c) in an unusual way. It gives an error message. Both the C way and the Python way are considered wrong. You're going to have to add ( ) to clarify.


Rust also gives a custom error message [0] that explicitly explains that "comparison operators cannot be chained" and shows you how to rewrite the expression using `&&`.

Which makes me wonder whether they came up with this idea themselves or if they borrowed it from D.

In any case, I think that this is the only reasonable solution for new languages. Because if you go with C way it will be surprising for people who expect Python way and vice versa. So, making this syntax illegal is the only way to uphold the principle of least astonishment [1].

[0] https://play.rust-lang.org/?version=stable&mode=debug&editio...

[1] https://en.wikipedia.org/wiki/Principle_of_least_astonishmen...


I gave several presentations that included this back in the 2010-2012 timeframe, and it had already been in the language for maybe a decade.

When I implemented it, I had seen many knock-down drag-out debates about which was the best way to deal with it, and none of them mentioned simply making it illegal.

It was another one of those features that were based on my experience designing aircraft systems.

Another one adopted by pretty much all languages since D is the _ in numeric literals (although C++ used a backtick). It was just something that was obviously right once you saw it. But I didn't originate it, I cribbed it from Ada. I've always had a soft spot for Ada.


you can't just add () to clarify, you have to duplicate `b` too and that is not good transformation if `b` is function call


I remember when that went into Python. It seemed too cute. There was a lot of that around the Python 3.4, 3.5 era.

The case where all items are the same type is reasonable, but if implicit type conversions are invoked, it gets really complicated. Whatever the types are, Python will probably do something. Just not necessarily what you want.

I could see having this if there was a compile-time constraint that all variables be the same type. That would disallow the bad cases.


In defense of Python here, a==b==c -> (a ==_string b) ==_bool c is an extremely confusing way to write (predicate) nxor c. A principle here could be "operators that look the same shouldn't do different things when they're written close together."


This feels a bit like a case of a "Python from 10 years ago in my head" vs "Python from 10 years ago in reality" meme.

Chained comparisons have been in Python since I started using it at 2.1. It looks to me like they've been there since at least 1.4:

https://docs.python.org/release/1.4/tut/node40.html#SECTION0...


Ah. I'm thinking of [1] from 2016, when there was a plan to add short-cut evaluation to short-cut comparisons. That avoids evaluating all the terms when not necessary. But that was deferred.

[1] https://peps.python.org/pep-0535/


That's so lazy!


> Whatever the types are, Python will probably do something. Just not necessarily what you want.

Are you sure you are not confusing it with PHP? Python is not statically typed, but it is strongly typed. There is no implicit type conversion unless it's safe to do so (such as between a float and an int).

For example, print(1 > "foo") will raise a TypeError, and print("1" == 1) will print False.


In Python, "==" calls "__eq__", a class function. The left argument to "==" determines which class is involved. The right argument is just passed into the selected class member function. There's an asymmetry there. Operators are not necessarily commutative.

This can lead to some strange operator semantics in mixed-mode expressions. Whether chained expressions left-associate or right-associate matters.

numpy.array operations do a lot of implicit conversions. You can use Python arrays on many operations that expect a numpy.array. Mixing them works. Mostly.

    python3
    Python 3.10.12 (main, Sep 11 2024, 15:47:36) [GCC 11.4.0] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import numpy
    >>> a1 = numpy.array([1,2,3])

    >>> a2 = [1,2,3]
    >>> a1 == a2
    array([ True,  True,  True])
    >>> a2 == a1
    array([ True,  True,  True])
    >>> a1 == a2 == a1
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
    >>> a2 == a2 == a2
    True
    >>> a1 == a1 == a1
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()


The candidate was writing an accounting program in COBOL and he wrote "ADD 2 TO SUM.". None of the handful of languages I kind of know support that syntax. It turns out that COBOL actually supports this nonsense. I explained to the candidate that when he is writing valid COBOL syntax, it is confusing to people who don't know COBOL and he agreed.

This is a fail for the interviewer, not the interviewee, nor for Python.


I'd be more confused about the curly brackets, I only know python and have never seen them used like that? My brain goes like: Here comes a set or dict.

Also, why not do `all(cell[0][0],cell[1][1]),cell[2][2])` if you want to have True when all 3 are True?

Perhaps I'm missing something, I don't exactly consider myself a 1337 coder.


> I'd be more confused about the curly brackets, I only know python and have never seen them used like that?

Yeah, that’s C/C++/JavaScript/… syntax, it’s not valid Python.

> why not do `all(cell[0][0],cell[1][1]),cell[2][2])` if you want to have True when all 3 are True?

We want to test whether all three are the same, not whether they’re all True.


Worth to keep in mind that python first appeared in 1991 and predates even Java, JavaScript, PHP, Ruby


And the nerve to put Javascript as the example about how equality should work, a language known for:

  0 == '' evaluates to True
  0 == '0' evaluates to True
  false == 'false' evaluates to False
  false == '0' evaluates to True
  ' \t\r\n ' == 0 evaluates to True
and the === operator you need to overcome the above. I don't have anything against JS and I understand why it is done that way, but if some language has weird and confusing comparison operators is JS.


The basic rule is "if there's a number on either side, convert the other side to a number before doing the comparison". I think false == '0' is the only one that fails that test, unless you think of false as a special case of 0 which makes false == 'false' the one that fails with that rule.


It is merely syntatically confusing.

Make == be ~~ or .fuzzyCompare()

And === be ==

And you are fixed.


Paraphrasing: "Well done, Javascript… for finding yet another way to confuse us all."

I don't know many programming languages, but of the few I know any of them has a === because == is so confusing that you don't know exactly if (or when) it would bite you. You can't attack any language for their comparison operators from the Javascript camp.

It that blog post removed the sentence "And this is how it would definitely happen if the code was written in javascript" they would be fine. But you actually don't know what would definitely happen in Javascript with the line in question "cell[0][0] == cell[1][1] == cell[2][2]", unless you know 100% what is in these cells. For example:

cell[0][0] is "0", cell[1][1] is 0, cell[2][2] is true

and "cell[0][0] == cell[1][1] == cell[2][2]" evaluates to True.


> cell[0][0] is "0", cell[1][1] is 0, cell[2][2] is true

If those values came from <input> elements, the second and third examples aren't possible without having manually converted it beforehand. Input values are always strings, even a checkbox. That's where javascript's conversion rules and lax equality came from, an attempt to have sane defaults for simple uses: If a string is being compared to a number, the string is likely from an input and the number was typed into the code, so convert the string to a number before comparison.


"Test two values for equality, but this time we mean it."


>Well done, Python… for finding yet another way to confuse us all.

Would have liked to see some humility from the author, especially since he's an interviewer, but instead he deflects the fault onto Python as being confusing, rather than attributing the fault to himself and his own lack of understanding.

Unfortunately, this kind of blame game is par for the course with enginerds. I say this all the time: engineers really should do a sales or customer service job before getting into engineering. This will help you build empathy, which will build your social skills and kindle some humility within you. These traits will give you an edge over other nerds and take you further in your career.


>> I have a very basic question which I usually ask in a interview which is to implement a tic tac toe game. I like this because the logic is straightforward and it helps to judge things like code quality / speed / conciseness etc.

"I like this because the logic is straightforward and it helps to judge things like code quality / speed / conciseness etc."

No, it doesn't.

Everyone who comes up with their own pet way of evaluating and interviewing thinks - nay has the unshakable belief - that their way of evaluating developers is 100% spot on. However it's always something they just made up, justify with plain old words and never science.


How did you get "unshakable belief" from that paragraph?

Interviewing is inherently messy, imprecise and unscientific. The process involves a lot of guesswork and feeling, rather than accurate measurements of any kind. It creates a fictional work environment that is often stressful for candidates, so any signal you may get out if it is also inaccurate.

It's natural for interviewers to have a preference for certain questions, topics or ways of conducting an interview. You're free to disagree, of course, but claiming that your way is superior is silly.


Fascinating, the task was supposed to be straightforward and a way to judge code quality etc. Yet, when the candidate solved it in a simple way, they were told they had a bug that they didn't have. This is okay of course, coding is hard. It could have been an interesting opportunity for discussion, I guess.

What's interesting to me is the conclusion that it's somehow Python's fault. I wonder if that attitude would work if it came from the candidate.

I think we should be more careful with tests like this. They need to be done with more humility, so it's great that the post was written!


In my mind,I just automatically translate a EXPRESSION1 b EXPRESSION2 c as (a EXPRESSION1 b) and (b EXPRESSION2 c), so there's no ambiguity. But I agree, it can be very confusing,so I tend to write code that is easy to read without being a master. For example, what would have guessed this evaluates to:

False is False is False. If you thought, True, you were right :)

I would recommend to take a look at one of my favourite repos for more[1].

[1]https://github.com/satwikkansal/wtfpython


wouldn't it be lovely if someone, somehow pointed out that it should be

   if a == b == c != "-": return Winner
?

so three empty fields in a row don't "win" the game?


I don't code for a living anymore, but I think if I were writing Python I would probably AVOID using that idiom because of how jarring it could be to people who are unfamiliar with it, mostly due to how strange it is coming from other languages.

There doesn't seem to be a great upside to using it, and adding confusion to the codebase for whatever poor bum has to work on it later is bad karma.


Is nobody going to point out that the code will return that there’s a winner even when all 3 cells are empty? (Even with the fancy python chaining?)



python was pleasant in the python 2 days. Now there's so many confusing ways to do one simple thing.

and one thing Golang has made inroads is there's only one way to do something.

and ruby is pleasurable because the interface is consistent i.e everything is an object.


What does the feature discussed in TFA (chained comparisons) have to do with Python 2 vs Python now.

As another commenter pointed out [0] this feature existed since 1.4 [1].

Also, I don't understand why so many people seem to be so confused/surprised by it. I can't be 100% sure because it was a long time ago, but I think that a lot of tutorials/introductory articles mention it. Like, "Hey, did you know that Python has this cool syntaxic sugar for this thing? Fascinating!". I think that I learned about chained comparisons long before I wrote my first line of Python.

[0] https://news.ycombinator.com/item?id=42038451

[1] https://docs.python.org/release/1.4/tut/node40.html#SECTION0...


I wrote Python for years before seeing it somewhere, going huh, and then I thought it's quite neat.

I still don't think it's that confusing. It does what you think it should if you're reading pseudocode, which is after all kind of Python's MO.


Yea, after spending a lot of time coding in python and then switching to js, this definitely caused some heads catching moments.


I don't know why didn't the candidate just explain to the interviewer what chain expressions are.


Sounds like he didn't know the details, but had seen this pattern in Python code and knew it worked. When asked, he was confused about the exact details of why it worked.


Regardless of the naive algorithm, wouldn't this also match empty cells?


Did he get the job?


No, because when all cells are empty he returns "Winner".

The interviewer also lost his job, since he didn't spot it nor does he know basic python syntax.


The interviewer got a promotion, since he didn't spot it nor does he know basic python syntax.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: