Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Alternative derivation of IResource from Indexable, Serializable, etc. #14

Open
bbarker opened this issue Mar 27, 2019 · 6 comments
Open

Comments

@bbarker
Copy link
Contributor

bbarker commented Mar 27, 2019

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!

@agocorona
Copy link
Owner

agocorona commented Mar 30, 2019

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

@bbarker
Copy link
Contributor Author

bbarker commented Mar 31, 2019

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.

@agocorona
Copy link
Owner

agocorona commented Apr 2, 2019

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

@bbarker
Copy link
Contributor Author

bbarker commented Apr 2, 2019

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
Copy link
Contributor Author

bbarker commented Apr 5, 2019

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 = ...

@agocorona
Copy link
Owner

agocorona commented Apr 9, 2019

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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants