# Example of subtract

**URL:** <https://forums.foundationdb.org/t/example-of-subtract/2526>\
**Category:** Using FoundationDB\
**Created:** [January 23, 2021, 6:50am UTC](https://forums.foundationdb.org/t/example-of-subtract/2526 "2021-01-23T06:50:51Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![falsandtru](https://sea1.discourse-cdn.com/foundationdb/user_avatar/forums.foundationdb.org/falsandtru/32/546_2.png) [@falsandtru](https://forums.foundationdb.org/u/falsandtru)\
**Post date:** [January 23, 2021, 6:50am UTC](https://forums.foundationdb.org/t/example-of-subtract/2526/1 "2021-01-23T06:50:52Z")

</div>

Example code of atomic operations in [Multimaps — FoundationDB 7.1](https://apple.github.io/foundationdb/multimaps.html) looks inefficient.

```python
@fdb.transactional
def multi_subtract(tr, index, value):
    v = tr[multi[index][value]]
    if v.present() and struct.unpack('<q', str(v))[0] > 1:
        tr.add(multi[index][value], struct.pack('<q', -1))
    else:
        del tr[multi[index][value]]

```

Should use compare\_and\_clear (recommended in the developer guide).

```python
@fdb.transactional
def multi_subtract(tr, index, value):
    tr.add(multi[index][value], struct.pack('<q', -1))
    tr.compare_and_clear(multi[index][value], struct.pack('<q', 0))

```

> Note  
> If a transaction uses both an atomic operation and a strictly serializable read on the same key, the benefits of using the atomic operation (for both conflict checking and performance) are lost.  
> [Developer Guide — FoundationDB 7.1](https://apple.github.io/foundationdb/developer-guide.html#atomic-operations)

Another, I think the next code

```python
@fdb.transactional
def decrement(tr, counter):
    tr.add(counter, struct.pack('<i', -1))
    tr.compare_and_clear(counter, struct.pack('<i', -1))

```

is safer and easier than the original code in the developer guide.

```python
@fdb.transactional
def decrement(tr, counter):
    tr.add(counter, struct.pack('<i', -1))
    tr.compare_and_clear(counter, struct.pack('<i', 0))

```

---

<div class="post-metadata">

**Author:** ![alloc](https://sea1.discourse-cdn.com/foundationdb/user_avatar/forums.foundationdb.org/alloc/32/9_2.png) [@alloc](https://forums.foundationdb.org/u/alloc)\
**Post date:** [January 25, 2021, 6:40pm UTC](https://forums.foundationdb.org/t/example-of-subtract/2526/2 "2021-01-25T18:40:19Z")

</div>

Yeah, that’s probably true. I believe the multimap example (and most of the examples) were written before `COMPARE_AND_CLEAR` as added. I think this should probably be a GitHub issue to improve that.

> [@falsandtru](#):
>
> Another, I think the next code
> 
> ```auto
> @fdb.transactional
> def decrement(tr, counter):
> tr.add(counter, struct.pack('<i', -1))
> tr.compare_and_clear(counter, struct.pack('<i', -1))
> 
> ```
> 
> is safer and easier than the original code in the developer guide.
> 
> ```auto
> @fdb.transactional
> def decrement(tr, counter):
> tr.add(counter, struct.pack('<i', -1))
> tr.compare_and_clear(counter, struct.pack('<i', 0))
> 
> ```

I’m not sure I quite understand this part of your post. Not sure if this a copy-paste error, but I think the argument to `compare_and_clear` needs to be 0 instead of -1. (If it’s -1, then the key will be deleted _after_ the key is decremented to zero, which I think should never happen, whereas we want it to be deleted precisely when it gets decremented to zero.)

---

<div class="post-metadata">

**Author:** ![falsandtru](https://sea1.discourse-cdn.com/foundationdb/user_avatar/forums.foundationdb.org/falsandtru/32/546_2.png) [@falsandtru](https://forums.foundationdb.org/u/falsandtru)\
**Post date:** [January 25, 2021, 8:03pm UTC](https://forums.foundationdb.org/t/example-of-subtract/2526/3 "2021-01-25T20:03:44Z")

</div>

> [@alloc](#):
>
> I’m not sure I quite understand this part of your post. Not sure if this a copy-paste error, but I think the argument to `compare_and_clear` needs to be 0 instead of -1. (If it’s -1, then the key will be deleted _after_ the key is decremented to zero, which I think should never happen, whereas we want it to be deleted precisely when it gets decremented to zero.)

It is my intended change. Clearing a value when the value is -1 enables to decrement 0 or an empty value. Due to this advance, developers don’t have to check that the count is 1 or more (decrementable). This robust decrement code would safely work with more use cases. My decrement code is as follows.

```go
func decrement(tr fdb.Transactor, key fdb.KeyConvertible) uint32 {
	step := []byte{0xff, 0xff, 0xff, 0xff}
	value, err := tr.Transact(func(tx fdb.Transaction) (interface{}, error) {
		tx.Add(key, step)
		tx.CompareAndClear(key, step)
		return tx.Snapshot().Get(key).Get()
	})
	if err != nil {
		log.Fatalf("Unable to perform FDB transaction (%v)", err)
	}
	return bytesToUint(value.([]byte))
}

```

---

<div class="post-metadata">

**Author:** ![alloc](https://sea1.discourse-cdn.com/foundationdb/user_avatar/forums.foundationdb.org/alloc/32/9_2.png) [@alloc](https://forums.foundationdb.org/u/alloc)\
**Post date:** [January 25, 2021, 9:28pm UTC](https://forums.foundationdb.org/t/example-of-subtract/2526/4 "2021-01-25T21:28:08Z")

</div>

I see. I guess I’m not sure I totally follow (i.e., if you have a count which will hopefully always be non-negative, it seems like it would never get to -1), but it may depend on your desired semantics. I suppose there are versions of this where you do want to distinguish between a zero value and no value at all

---

<div class="post-metadata">

**Author:** ![falsandtru](https://sea1.discourse-cdn.com/foundationdb/user_avatar/forums.foundationdb.org/falsandtru/32/546_2.png) [@falsandtru](https://forums.foundationdb.org/u/falsandtru)\
**Post date:** [January 25, 2021, 10:18pm UTC](https://forums.foundationdb.org/t/example-of-subtract/2526/5 "2021-01-25T22:18:43Z")

</div>

> [@alloc](#):
>
> want to distinguish between a zero value and no value at all

Of course my version is inappropriate in that case. However, my version works without reading the current value, right? And transactions should avoid reading the current value in atomic operations. So I think replacing `tr.compare_and_clear(counter, struct.pack('<i', 0))` with `tr.compare_and_clear(counter, struct.pack('<i', -1))` will make no problem. Well, the current code would be easier to understand.
