TCache icon indicating copy to clipboard operation
TCache copied to clipboard

Alternative derivation of IResource from Indexable, Serializable, etc.

Open bbarker opened this issue 6 years ago • 6 comments
trafficstars

The only definition I see (sorry if I missed one) is in DefaultPersistence:

instance  (Typeable a,  Indexable a, Serializable a) => IResource a where
  keyResource = key
  writeResource =defWriteResource
  readResourceByKey = defReadResourceByKey
  delResource = defDelResource

I realized after chasing a bug for a while that it was this definition that caused issues (I'm pretty sure), because when I switch from using file-based to custom database persistence, these definitions were still in use.

At this point, I could probably just implemented by own IResource class, but it seems like if TCache provided another definition for the IResource instance analogous to the above in the Defs module that queried getPersist to find out how to write/read/del, this might be ideal. But wanted to discuss here first.

Thanks!

bbarker avatar Mar 27 '19 19:03 bbarker

What kind of issues? Is it the "no parse" error? There is one problem caused by lazyness: Registers are not deserialised when they are read, but when the fields are accessed. So when the deserializer and deserializer are not well defined, the "no parse" error could happen at places unrelated with TCache.

To solve it, for testing purposes, it is good to make deserialization eager by using seq or print. Or better, verify that deserialize $ serialize x== x

Hope that this would be useful

agocorona avatar Mar 30 '19 23:03 agocorona

What kind of issues? Is it the "no parse" error?

Just replying to this for now, but thanks for the other suggestions and details, will take a look soon. But no, it is a different error (compiler error):

    • No instance for (Data.TCache.IResource.IResource SxRecord)
        arising from the superclasses of an instance declaration
    • In the instance declaration for ‘IsCowRec SxRecord’
   |        
23 | instance IsCowRec SxRecord where
   |          ^^^^^^^^^^^^^^^^^
          

Since there is no way to infer ``IResource` otherwise in TCache, as far as I can tell at the moment. But as I said, I could attempt to make a modification to support this, but wanted to check with you first.

To very briefly reply to your second bit of info without giving it due consideration, I believe I did try Control.Exception's evaluate, which, iirc, is implemented using seq and has similar behavior in this regard.

bbarker avatar Mar 31 '19 20:03 bbarker

have you included

  import Data.TCache.DefaultPersistence? 

Please give me a (reduced example source code) that produces that error and I will take a look

agocorona avatar Apr 02 '19 20:04 agocorona

Hi @agocorona,

I'm happy to include a reduced source example, but first, I want to clarify a potential point of confusion. As I probably too-tersely noted in the first line of my initial post in this issue, I was including import Data.TCache.DefaultPersistence. And it compiled, but did not behave as expected. The reason seems to be, as also mentioned in my initial post, that the provided instance in DefaultPersistence uses the def* functions in its implementation, which I believe correspond to the default file-based persistence, rather than whatever the user of TCache has selected to use as their persistence method. Does this make sense? Thanks

bbarker avatar Apr 02 '19 20:04 bbarker

Hi @agocorona ,

I added an example, though I have to say there is nothing terribly interesting here. It builds, but upon this simple commit, it no longer does, and we get the error (as expected):

    * No instance for (IResource FarmRecord)
        arising from a use of `withResource'
    * In the expression: withResource rec storeIt
      In an equation for `insertFarmRec':
          insertFarmRec rec
            = withResource rec storeIt
            where
                storeIt :: Maybe FarmRecord -> FarmRecord
                storeIt (Just rc) = rc
                storeIt _ = error "The FarmRecord does not exist"
   |
78 | insertFarmRec rec = withResource rec storeIt
   |                     ^^^^^^^^^^^^^^^^^^^^^^^^

My point is that there should ideally be a way to derive other IResource instances so that instead of the following TCache code in Data.TCache.DefaultPersistence:

instance  (Typeable a,  Indexable a, Serializable a) => IResource a where
  keyResource = key
  writeResource =defWriteResource
  readResourceByKey = ...
  delResource = ...

We instead have something like this leveraging the currently active Persist object:

instance  (Typeable a,  Indexable a, Serializable a) => IResource a where
  keyResource = key
  writeResource val = write getDefaultPersist $ (key val) (serialize val) -- untested pseudocode
  readResourceByKey = ...
  delResource = ...

bbarker avatar Apr 05 '19 23:04 bbarker

Hi @bbarker

Really I'm going back to TCache after some time and, since I'm using it lately and I get also a bit lost with the definitions. I expect that this clarifies it a bit.The structure of classes and modules is as such:

IResource class: takes key extraction serialization-deserialization as well as read-write to database. they are three roles that may be orthogonal , but they are mixed in this class. It is defined in Data.TCache

Indexable class: takes only the key extraction role Serializable class: takes the serialization-deserialization and write read role but they are both orthogonal and decoupled since read/write is defined in an independent structure called Persist

Persist data definition: is an structure that specifies the way to write/read a serialized string to-from a database

The last three are defined in Data.TCache.Defs. It defines a particular instantiation of this structure: filePersist which contain the definitions for persisting in files.

Data.DefaultPersistence use the three latest: Indexable, Serializable and filePersist to define IResource so that any data that is Indexable and Serializable can be written/read to-from files. It does so by constructing a IResource Instance, that is all what Data.TCache needed for that.

So if you import Data.DefaultPersistence, you are setting persistence in files for everything and you don´t need to import Data.Defs. This latter is for more sophisticated things:

Data.Defs alone, without DefaultPersistence can be used if you want to use Indexable and Serializable, BUT you want to store the serialized data in another storage, for example, Amazon S3 services.

For example: http://hackage.haskell.org/package/tcache-AWS uses that. It defines amazonSDBPersist which generates a Persist structure for amazon.

Also in case you want to define different persistence instances for different kinds of data.

Does this clarifies things a little bit?

agocorona avatar Apr 09 '19 20:04 agocorona