You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{-# LANGUAGE
TemplateHaskell,
TypeFamilies,
OverloadedStrings,
ScopedTypeVariables
#-}
importData.SafeCopyimportData.AcidnewtypeX=XStringdataFoo=FooXX
deriveSafeCopy 0 'base ''X
deriveSafeCopy 0 'base ''Foo
makeAcidic ''Foo []
main =do
db ::AcidStateFoo<- openLocalStateFrom "acid-hs/" (Foo (X"a") (X"b"))
putStrLn"loaded the database successfully"
createCheckpoint db
putStrLn"created checkpoint"
closeAcidState db
putStrLn"closed db"
Introduce a type Y and try to go from Foo X X to Foo X Y:
{-# LANGUAGE
TemplateHaskell,
TypeFamilies,
OverloadedStrings,
ScopedTypeVariables
#-}
importData.SafeCopyimportData.AcidnewtypeX=XStringnewtypeY=YString-- newdataFoo=FooXY-- was Foo X X
deriveSafeCopy 0 'base ''X
deriveSafeCopy 1 'extension ''Y
deriveSafeCopy 0 'base ''Foo
instanceMigrateYwhere-- migration from X to YtypeMigrateFromY=X
migrate (X a) =Y a
makeAcidic ''Foo []
main =do
db ::AcidStateFoo<- openLocalStateFrom "acid-hs/"undefinedputStrLn"loaded the database successfully"
createCheckpoint db
putStrLn"created checkpoint"
closeAcidState db
putStrLn"closed db"
Try to run the 1st version and then load the checkpoint in the 2nd version:
$ runghc acid1.hs
loaded the database successfully
created checkpoint
closed db
$ runghc acid2.hs
acid2.hs: Could not parse saved checkpoint due to the following error:
Failed reading: safecopy: Char: Cannot find getter associated with this version number:
Version {unVersion = 1627389952}
From: Main.Foo:
Main.X:
Ouch.
I think the reason it happens is that for Foo X X we generate the following safePut:
It will write the version tag for X only once (since writing the tag is done in getSafePut). However, when reading Foo X Y we will try to read the version tag twice:
(My actual usecase, by the way, involves migrating from something like Foo X X to Foo (X Int) (X Bool), where Int and Bool are phantom (i.e. X is defined as newtype X a = X Text).)
The text was updated successfully, but these errors were encountered:
@neongreen why do you expect acid2.hs to work correctly with data serialized in acid1.hs? Both modules appear to have 2 different data types with the same name Foo and you have no migration between them - how could safecopy show correct behavior when you appear to give it inconsistent definitions as an input?
Alright, I guess this makes sense. It's still pretty unexpected that there are situations where I have to write a migration even when the data layout is completely unchanged (as with my "phantom type" example), and I would argue that this warrants a note in the documentation.
(In fact I would also argue that this warrants making Simple the default behavior, but whatever.)
Take the following program:
Introduce a type
Y
and try to go fromFoo X X
toFoo X Y
:Try to run the 1st version and then load the checkpoint in the 2nd version:
Ouch.
I think the reason it happens is that for
Foo X X
we generate the followingsafePut
:It will write the version tag for
X
only once (since writing the tag is done ingetSafePut
). However, when readingFoo X Y
we will try to read the version tag twice:Ouch.
(My actual usecase, by the way, involves migrating from something like
Foo X X
toFoo (X Int) (X Bool)
, whereInt
andBool
are phantom (i.e.X
is defined asnewtype X a = X Text
).)The text was updated successfully, but these errors were encountered: