<p><br>
On Mar 15, 2012 1:53 AM, "Masklinn" <<a href="mailto:masklinn@masklinn.net">masklinn@masklinn.net</a>> wrote:<br>
><br>
> On 2012-03-14, at 18:36 , Matt Joiner wrote:<br>
> > set.add(x) could return True if x was added to the set, and False if x<br>
> > was already in the set.<br>
><br>
> That does not mesh with the usual Python semantics of methods either<br>
> having a side-effect (mutation) or returning a value. Why would that<br>
> happen with sets but not with e.g. dicts?</p>
<p>Because dict insertions are by operator?</p>
<p>><br>
> > Adding an element that is already present often constitutes an error in my code.<br>
><br>
> Then thrown an error when that happens?</p>
<p>><br>
> > As I understand, set.add is an atomic operation. Having set.add return<br>
> > a boolean will also allow EAFP-style code with regard to handling<br>
> > duplicates, the long winded form of which is currently:<br>
> ><br>
> > if a not in b:<br>
> >    b.add(a) <-- race condition<br>
> >    do_c()<br>
> ><br>
> > Which can be improved to:<br>
> ><br>
> > if b.add(a):<br>
> >    do_c()<br>
> ><br>
> > Advantages:<br>
> > * Very common code pattern.<br>
> > * More concise.<br>
> > * Allows interpreter atomicity to be exploited, often removing the<br>
> > need for additional locking.<br>
> > * Faster because it avoids double contain check, and can avoid locking.<br>
><br>
> Nope, as Andrew noted it's possible that an other thread has *removed*<br>
> the element from the set before do_c (so you've got your race condition<br>
> right there, assuming do_c expects `a` to be in `b`)<br>
><br>
> And since you're using a set `b.add(a)` is a noop if `a` is already in<br>
> `b` so there's no race condition at the point you note. The race<br>
> condition is instead in the condition itself, you can have two different<br>
> threads finding out the value is not in the set and ultimately executing<br>
> do_c.</p>
<p>There's still a performance cost in looking up the already present value a second time. </p>