# Feature or enhancement
### Proposal:
(I think this is a very simple idea, bo…th conceptually and implementation-wise, that is why I did not open a thread for it on Discourse, if you'd prefer I do that, please tell me.)
(Also I have failed to find any discussions about this idea, if I had missed them, please direct me to them.)
This proposal seeks to make `set.add` return a `bool` value that indicates whether insertion took place or not. A return value of `True` would mean insertion has taken place, while a return value of `False` would mean that insertion has *not* taken place. This can simplify snippets that use `set.add` in conjunction with `set.__contains__`.
I may be wrong, but I believe this should a (mostly) backwards compatible change since `set.add` currently returns `None`, so the return value is likely not used anywhere.
For example:
```python
s = set()
...
# currently
if x in s:
raise SomeError("duplicates not allowed")
s.add(x)
# with the proposal
if not s.add(x):
raise SomeError("duplicates not allowed")
```
Prototype implementation (not really tested at the moment):
<details>
```diff
diff --git a/Objects/setobject.c b/Objects/setobject.c
index ae3f0b8d5e..f3f939c262 100644
--- a/Objects/setobject.c
+++ b/Objects/setobject.c
@@ -170,16 +170,16 @@ set_add_entry(PySetObject *so, PyObject *key, Py_hash_t hash)
so->used++;
freeslot->key = key;
freeslot->hash = hash;
- return 0;
+ return 1;
found_unused:
so->fill++;
so->used++;
entry->key = key;
entry->hash = hash;
- if ((size_t)so->fill*5 < mask*3)
- return 0;
- return set_table_resize(so, so->used>50000 ? so->used*2 : so->used*4);
+ if ((size_t)so->fill*5 >= mask*3 && set_table_resize(so, so->used>50000 ? so->used*2 : so->used*4))
+ return -1;
+ return 1;
found_active:
Py_DECREF(key);
@@ -623,7 +623,7 @@ set_merge(PySetObject *so, PyObject *otherset)
other_entry = &other->table[i];
key = other_entry->key;
if (key != NULL && key != dummy) {
- if (set_add_entry(so, key, other_entry->hash))
+ if (set_add_entry(so, key, other_entry->hash) < 0)
return -1;
}
}
@@ -904,7 +904,7 @@ set_update_internal(PySetObject *so, PyObject *other)
return -1;
}
while (_PyDict_Next(other, &pos, &key, &value, &hash)) {
- if (set_add_entry(so, key, hash))
+ if (set_add_entry(so, key, hash) < 0)
return -1;
}
return 0;
@@ -915,7 +915,7 @@ set_update_internal(PySetObject *so, PyObject *other)
return -1;
while ((key = PyIter_Next(it)) != NULL) {
- if (set_add_key(so, key)) {
+ if (set_add_key(so, key) < 0) {
Py_DECREF(it);
Py_DECREF(key);
return -1;
@@ -1212,7 +1212,7 @@ set_intersection(PySetObject *so, PyObject *other)
return NULL;
}
if (rv) {
- if (set_add_entry(result, key, hash)) {
+ if (set_add_entry(result, key, hash) < 0) {
Py_DECREF(result);
Py_DECREF(key);
return NULL;
@@ -1237,7 +1237,7 @@ set_intersection(PySetObject *so, PyObject *other)
if (rv < 0)
goto error;
if (rv) {
- if (set_add_entry(result, key, hash))
+ if (set_add_entry(result, key, hash) < 0)
goto error;
if (PySet_GET_SIZE(result) >= PySet_GET_SIZE(so)) {
Py_DECREF(key);
@@ -1528,7 +1528,7 @@ set_difference(PySetObject *so, PyObject *other)
return NULL;
}
if (!rv) {
- if (set_add_entry((PySetObject *)result, key, hash)) {
+ if (set_add_entry((PySetObject *)result, key, hash) < 0) {
Py_DECREF(result);
Py_DECREF(key);
return NULL;
@@ -1551,7 +1551,7 @@ set_difference(PySetObject *so, PyObject *other)
return NULL;
}
if (!rv) {
- if (set_add_entry((PySetObject *)result, key, hash)) {
+ if (set_add_entry((PySetObject *)result, key, hash) < 0) {
Py_DECREF(result);
Py_DECREF(key);
return NULL;
@@ -1631,7 +1631,7 @@ set_symmetric_difference_update(PySetObject *so, PyObject *other)
return NULL;
}
if (rv == DISCARD_NOTFOUND) {
- if (set_add_entry(so, key, hash)) {
+ if (set_add_entry(so, key, hash) < 0) {
Py_DECREF(key);
return NULL;
}
@@ -1660,7 +1660,7 @@ set_symmetric_difference_update(PySetObject *so, PyObject *other)
return NULL;
}
if (rv == DISCARD_NOTFOUND) {
- if (set_add_entry(so, key, hash)) {
+ if (set_add_entry(so, key, hash) < 0) {
Py_DECREF(otherset);
Py_DECREF(key);
return NULL;
@@ -1834,9 +1834,11 @@ set_richcompare(PySetObject *v, PyObject *w, int op)
static PyObject *
set_add(PySetObject *so, PyObject *key)
{
- if (set_add_key(so, key))
+ int res = set_add_key(so, key);
+ if (res < 0)
return NULL;
- Py_RETURN_NONE;
+
+ return res ? Py_True : Py_False;
}
PyDoc_STRVAR(add_doc,
@@ -2326,7 +2328,11 @@ PySet_Add(PyObject *anyset, PyObject *key)
PyErr_BadInternalCall();
return -1;
}
- return set_add_key((PySetObject *)anyset, key);
+
+ if (set_add_key((PySetObject *)anyset, key) < 0)
+ return -1;
+
+ return 0;
}
int
```
</details>
### Has this already been discussed elsewhere?
This is a minor feature, which does not need previous discussion elsewhere
### Links to previous discussion of this feature:
_No response_