Tags dejafu, haskell, programming, release notes
Target Audience Haskell programmers.
Attention Conservation Notice dejafu is a Haskell library for testing concurrent programs.

I will be giving a present­a­tion about Déjà Fu at the Haskell Sym­posium next week.

Déjà Fu is a lib­rary for de­vel­oping and testing con­cur­rent Haskell pro­grams, it provides a type­class-­ab­strac­tion over GHC’s reg­ular con­cur­rency API, al­lowing the con­crete im­ple­ment­a­tion to be swapped out.


Why do we need this? Well, con­cur­rency is really hard to get right. Em­pir­ical studies have found that many real-­world con­cur­rency bugs can be ex­hib­ited with small test cases using as few as two threads: so it’s not just big con­cur­rent pro­grams that are hard, small ones are too. We as pro­gram­mers just don’t seem to have a very good in­tu­ition for tra­di­tional thread­s-and-shared-memory-­style con­cur­rency. The typ­ical ap­proach to testing con­cur­rent pro­grams is to just run them lots of times, but that doesn’t provide any hard cov­erage guar­an­tees, and then we need to won­der: how many runs do we need?

For­tu­nately, there has been a lot of re­search into testing con­cur­rency in the past sev­eral years. Sys­tem­atic con­cur­rency testing is an ap­proach where the source of non­determin­ism, the ac­tual sched­uler, is swapped out for one under the con­trol of the testing frame­work. This al­lows pos­sible sched­ules to be sys­tem­at­ic­ally ex­plored, giving real cov­erage guar­an­tees for our tests.

This is a lib­rary im­ple­menting sys­tem­atic con­cur­rency test­ing. It provides two type­classes, Mon­ad­Conc to ab­stract over much of Con­trol.­Con­cur­rent and re­lated mod­ules, and Mon­adSTM, to sim­il­arly ab­stract over Con­trol.­Mon­ad.STM.

How to use it

If you’re not making use of any IO in your code other than for con­cur­rency, the trans­ition to using Mon­ad­Conc and Mon­adSTM will prob­ably just be a tex­tual sub­sti­tu­tion:

If you are using other IO, you will need a gentle sprink­ling of Mon­adIO and liftIO in your code as well.

Is this really just a drop-in re­place­ment for IO/STM?

That’s the idea, yes.

More spe­cific­ally, the IO in­stance of Mon­ad­Conc and the STM in­stance of Mon­adSTM just use the reg­ular IO and STM func­tions, and so should have no no­tice­able change in be­ha­vi­our, ex­cept for CRef, the IORef equi­val­ent, where modi­fyCRef be­haves like atom­ic­Modi­fyIORef, not modi­fyIORef1.

  1. There are some other dif­fer­ences which can lead to in­cor­rect res­ults when test­ing, but which should not af­fect code when used in an IO or STM con­text. Spe­cific­ally: Con­trol.­Mon­ad.­Con­c.­Class.­get­Num­Cap­ab­il­ities can lie to en­courage more con­cur­rency when test­ing; and Con­trol.Ex­cep­tion.catch can catch ex­cep­tions from pure code, but Con­trol.­Mon­ad.­Con­c.­Class.catch can’t (ex­cept for the IO in­stance).