| Safe Haskell | Safe-Inferred |
|---|
Control.Final.Example
Description
Consider this peace of code:
join $ atomically $ do
radarPositive <- readTVar radarTVar
launchKeyInserted <- readTVar launchKeyTVar
case radarPositive of
False -> do
modifyTVar radarNegativeCounter (+1)
return $ print "No need for missiles, it's peaceful"
True -> do
modifyTVar radarPositiveCounter (+1)
case launchKeyInserted of
False -> do
modifyTVar keyMissingCounter (+1)
return $ print "No launch key, ignoring radar"
True -> do
modifyTVar launchCounter (+1)
return $ launchMissiles
return $ print "extra debug: state checking finished"
We use STM to make state checking of multiple TVars one atomic
transaction. Since we can't do IO in STM, we are just returning
the IO that needs to be done in the different cases. Unfortunately
when we try to add the extra debugging as the last statement, that
silently ignores all the previous "return" values, even
launchMissiles.
On the other hand when using final:
atomicJoinFinal $ do
radarPositive <- readTVar radarTVar
launchKeyInserted <- readTVar launchKeyTVar
case radarPositive of
False -> do
modifyTVar radarNegativeCounter (+1)
final $ print "No need for missiles, it's peaceful"
True -> do
modifyTVar radarPositiveCounter (+1)
case launchKeyInserted of
False -> do
modifyTVar keyMissingCounter (+1)
final $ print "No launch key, ignoring radar"
True -> do
modifyTVar launchCounter (+1)
final $ launchMissiles
final $ print "extra debug: state checking finished"
We get a compile error that contains this:
Note: there are several potential instances:
instance FinalClass Control.Final.FinalTooManyReturns
Internally Final is based on ambiguity checking in the type
system. The prohibited ambiguity occurs, because the only way to
decide what final means is by matching it to the corresponding
atomicJoinFinal. This is now only possible for the final at
the end of the function and not for the middle ones, so we get the
error.