<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/test-set-ahjohbn3v" -->

---
title: Test & Set | daily.dev
description: A developer shares a reusable Kotlin extension function called testAndSet() that wraps the common compareAndSet() retry loop pattern used with AtomicReference....
canonical: https://daily.dev/posts/test-set-ahjohbn3v
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Test & Set | daily.dev
og:description: A developer shares a reusable Kotlin extension function called testAndSet() that wraps the common compareAndSet() retry loop pattern used with AtomicReference....
og:url: https://daily.dev/posts/test-set-ahjohbn3v
og:image: https://api.daily.dev/og/posts/ahjohbn3V.png
og:image:alt: Test & Set
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Test & Set

**[Square](https://daily.dev/sources/publicobject)** · 3 min read · 0 upvotes · 0 comments

## Summary

A developer shares a reusable Kotlin extension function called testAndSet() that wraps the common compareAndSet() retry loop pattern used with AtomicReference. The function takes a condition and new value, uses tailrec instead of a manual while loop, and returns the previous value rather than a boolean, cleanly separating business logic from concurrency retry logic. A worked example shows a task cancellation method before and after the refactor.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://publicobject.com/2026/07/13/test-set>

## Questions this post answers

### How can I avoid writing a messy while loop every time I use compareAndSet with AtomicReference in Kotlin?

Factor the retry logic into a reusable extension function like testAndSet() that takes a condition and a new value, uses tailrec to retry on lost races, and returns the previous value instead of a boolean. This separates the concurrency retry mechanics from the business logic that decides whether and how to act on the previous state.

_daily.dev surfaces concurrency patterns like this for developers refining their Kotlin threading code._

### Why should a compareAndSet wrapper function return the previous value instead of a Boolean?

Returning the previous value lets calling code react to what the state actually was before the update, such as checking if it was a specific subtype and acting on its properties, without a second read that could race. Realizing this was the key insight that made the testAndSet() function signature work cleanly.

_Developers designing atomic state APIs can find similar concurrency design patterns on daily.dev._

## Similar posts on daily.dev

- [The Concurrency Bug That Quietly Breaks Fintech Apps](https://daily.dev/posts/the-concurrency-bug-that-quietly-breaks-fintech-apps-qqogb3pas) · Medium · 0 upvotes · 0 comments
- [Recent JUnit Updates for Kotlin](https://daily.dev/posts/recent-junit-updates-for-kotlin-v9pujhmrj) · droidcon · 2 upvotes · 0 comments
- [Finding Order in the Mayhem: A Novel Concurrency Testing Tool that Improved the Kotlin Compiler](https://daily.dev/posts/finding-order-in-the-mayhem-a-novel-concurrency-testing-tool-that-improved-the-kotlin-compiler-3rycypbau) · JetBrains · 0 upvotes · 0 comments
- [Working in Kotlin: Waiting Around with Coroutines](https://daily.dev/posts/working-in-kotlin-waiting-around-with-coroutines-vjhedyeww) · Atomic Spin · 0 upvotes · 0 comments
- [Features You Waited For So Long in Kotlin](https://daily.dev/posts/features-you-waited-for-so-long-in-kotlin-tdm4oviuu) · ProAndroidDev · 4 upvotes · 0 comments

---

Tags: [#testing](https://daily.dev/tags/testing), [#kotlin](https://daily.dev/tags/kotlin)

[View this post on daily.dev](https://daily.dev/posts/test-set-ahjohbn3v)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Test & Set","url":"https://daily.dev/posts/test-set-ahjohbn3v","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/test-set-ahjohbn3v"},"datePublished":"2026-08-23T12:21:22.585Z","dateModified":"2026-08-23T12:37:53.164Z","description":"A developer shares a reusable Kotlin extension function called testAndSet() that wraps the common compareAndSet() retry loop pattern used with AtomicReference....","image":"https://media.daily.dev/image/upload/s--2-1xRawN--/f_auto/v1722860399/public/Placeholder%2011","thumbnailUrl":"https://media.daily.dev/image/upload/s--2-1xRawN--/f_auto/v1722860399/public/Placeholder%2011","isAccessibleForFree":true,"articleSection":"Square","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Square","logo":"https://media.daily.dev/image/upload/s--QZPKZNBW--/f_auto,q_auto/v1787487457/logos/publicobject?_a=BAMAMicg0","url":"https://daily.dev/sources/publicobject"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/test-set-ahjohbn3v","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"testing,kotlin","timeRequired":"PT3M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Square","item":"https://daily.dev/sources/publicobject"},{"@type":"ListItem","position":3,"name":"Test & Set"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/test-set-ahjohbn3v#faq","mainEntity":[{"@type":"Question","name":"How can I avoid writing a messy while loop every time I use compareAndSet with AtomicReference in Kotlin?","acceptedAnswer":{"@type":"Answer","text":"Factor the retry logic into a reusable extension function like testAndSet() that takes a condition and a new value, uses tailrec to retry on lost races, and returns the previous value instead of a boolean. This separates the concurrency retry mechanics from the business logic that decides whether and how to act on the previous state. daily.dev surfaces concurrency patterns like this for developers refining their Kotlin threading code."}},{"@type":"Question","name":"Why should a compareAndSet wrapper function return the previous value instead of a Boolean?","acceptedAnswer":{"@type":"Answer","text":"Returning the previous value lets calling code react to what the state actually was before the update, such as checking if it was a specific subtype and acting on its properties, without a second read that could race. Realizing this was the key insight that made the testAndSet() function signature work cleanly. Developers designing atomic state APIs can find similar concurrency design patterns on daily.dev."}}]}
```

