Thanks for the clarification. But statements like this are why I think you're spouting crap:
"is actually trivially done (and has been used by countless projects for years) in almost all imperative languages, and less intrusively"
Is simply not true. In a JavaScript test framework, drawing from top-of-mind, recent examples, you cannot prevent the code under test from replacing document.location.
In Java, as you gave in another examples in this thread, you can't statically prevent access to the RNG or perhaps the current time.
In Python, there's nothing stopping any code from calling into a C module that has arbitrary effects.
Haskell is unique among any languages I've ever used in production that allows deterministic testability as a static, enforced-by-the-compiler guarantee.
I partially agree with your second comment, and I do think other forms of testing (such as fuzz testing, integration tests with third parties, acceptance tests) are valuable, but the technique described can be used in much larger tests than simple unit tests. As I mentioned, IMVU uses it for testing entire web service request handlers.
I get the feeling some people think that World is onerous and expensive to set up, but in practice you just write all of your code in World and it's not boilerplatey or complicated at all. The framework around World is set up once and never touched again.
* Disclaimer: I no longer work at IMVU, but I super super super miss Haskell in production.
I don't know too much about JS or python (I'm mostly C/C++/Java/Clojure/Matlab) but there's nothing to stop you from accessing C, in Haskell either, nor from using unsafePerformIO, and while in Java you can't prevent access to random numbers etc. statically, but you can certainly do it at runtime (though, in Java, too, you can call C and then all bets are off).
> Haskell is unique among any languages I've ever used in production that allows deterministic testability as a static, enforced-by-the-compiler guarantee.
Oh, that's true. It's just that if your tests are guaranteed to be deterministic, I don't see why the fact that the property is enforced statically is so important.
Personally, I think Haskell sacrifices a lot for the sake of static guarantees (including the ability to reason about programs not before they run, but during and after). Also, its reliance on Curry-Howard for verification is limited and narrow-sighted, and its insistence on referential transparency everywhere is interesting yet misguided. I'm now preparing a talk for the Curry On/ECOOP conference where I'll show -- among other things -- how all monads can be easily translated to imperative constructs (I won't go into details here, but what you need is continuations and continuation-global variables) in a way that makes them more understandable and compose more naturally than in PFP (i.e. there's no need for monad transformers). Even though this model does not equate the subroutine with the mathematical function -- as PFP does -- it is no less verifiable than the PFP approach. But I digress...
You can prevent access to `unsafePerformIO` and other unsafe language features using "Safe" Haskell (e.g. -XSafe). This happens at compile time. Functions like unsafePerformIO (IO a -> a), pure C FFI functions, overlapping instances,and TemplateHaskell are not allowed. Nothing is stopping you from accessing C but you can force FFI function to reside in IO.
"is actually trivially done (and has been used by countless projects for years) in almost all imperative languages, and less intrusively"
Is simply not true. In a JavaScript test framework, drawing from top-of-mind, recent examples, you cannot prevent the code under test from replacing document.location.
In Java, as you gave in another examples in this thread, you can't statically prevent access to the RNG or perhaps the current time.
In Python, there's nothing stopping any code from calling into a C module that has arbitrary effects.
Haskell is unique among any languages I've ever used in production that allows deterministic testability as a static, enforced-by-the-compiler guarantee.
I partially agree with your second comment, and I do think other forms of testing (such as fuzz testing, integration tests with third parties, acceptance tests) are valuable, but the technique described can be used in much larger tests than simple unit tests. As I mentioned, IMVU uses it for testing entire web service request handlers.
I get the feeling some people think that World is onerous and expensive to set up, but in practice you just write all of your code in World and it's not boilerplatey or complicated at all. The framework around World is set up once and never touched again.
* Disclaimer: I no longer work at IMVU, but I super super super miss Haskell in production.