Why do I register my package deserializer with Atom? What does it get me?


#1

Hello, folks.

I’m reading https://atom.io/docs/v0.190.0/behind-atom-serialization-in-atom and it tells me that I can register a package deserializer with Atom, but it appears that I have to decide when and whether to use it, so why exactly do I register it with Atom in the first place? Does Atom hold onto the serializer for me so that I don’t have to instantiate one every time I want to use it? (It’s probably a stateless service, so I don’t foresee any problems with throwing one away and recreating it later.) Is this a placeholder for future greatness related to deserializing the Memento of my package? It seems to me, so far, that I’m giving Atom my keys so that I can ask for them back later to start my car. Or I could just store them in my pocket. :smile:

I can only imagine that I’m missing something simple. What is it?

Thanks!


#2

First of all that is totally optional. You can get your old state object from the param passed to your activate function, modify the object while your package runs, and then just send that object to serialize to save the state. It does a simple JSON.stringify to save it.

If you register a deserializer then it uses that instead. Sometimes your object isn’t compatible with JSON.


#3

Thanks, Mark. The current documentation makes it sound mandatory to me, rather than optional as you describe it or as I’d expect it to work. From what you say here, I should be able to serialize/deserialize entirely on my own without registering any deserializing function with Atom. I can try that. If it works, then I will take a crack at improving the documentation to reflect what I learn.


#4

I don’t ever serialize. I just take a plain object, modify it, and send it back every time something changes.


#5

Hm. One disadvantage to trying to understand the contract without having a specific use in mind. I’m left wondering why the feature exists at all, and perhaps I can contribute that back to the documentation. :smile:

When you say “send it back every time something changes”, send it where? Do you mean that you implement serialize() simply to return the object itself rather than a memento (as a JSON object), so that Atom can give that (full) object back to you by pass it in to activate() or something else?

Thanks. This really helps me understand what’s going on.


#6

Exactly. The docs didn’t make it clear when I started. I don’t know if they have improved. I discovered it by trial and error.


#7

Thank you, Mark! I find that very helpful and commit to contributing back to the documentation when I finish the little article I have going.


#8

Hi @jbrains

Sorry if I’m catching up late, I was going to write an answer last friday when I’ve seen your post but I completely forgot it (sunny weekends aren’t the most productive ones :smile:).

So, I was looking for a good use case for serializer, and maybe I’ve got one if you’re still interested.

Let’s say I write a package to browse a palette provider service (like kuler and such). I’ll probably have a Palette and Color model at some point and to speed up startup when my package view was still displayed on quit I want to serialize these models.

So here’s what my models would look like:

class Palette
  constructor: ({@colors}) ->

class Color 
  constructor: ({@red, @green, @blue, @alpha}) ->

Now, if I just define a serialize method on these models like this:

class Palette
  constructor: ({@colors}) ->

  serialize: -> colors: @colors.map (color) -> color.serialize()

class Color 
  constructor: ({@red, @green, @blue, @alpha}) ->
  
  serialize: -> {@red, @green, @blue, @alpha}

And if I restore a Palette using the deserialized state using new Palette(state), I’ll end up with a palette whose colors aren’t instances of the Color class, so if I try to serialize it again it’ll break (serialize isn’t a method on the current color objects).

I could test if the colors passed to the palette are instances of Color and cast them if it’s not the case, but by registering a deserializer for the Color class I’ll be sure that the colors the palette will receive will be converted to Color before it get passed to the constructor without having to take care of that in the Palette class:

class Palette
  constructor: ({@colors}) ->

  serialize: -> colors: @colors.map (color) -> color.serialize()

class Color 
  atom.deserializers.add(this)

  @deserialize: (state) -> new Color(state)

  constructor: ({@red, @green, @blue, @alpha}) ->
  
  serialize: -> {@red, @green, @blue, @alpha, deserializer: 'Color'}

Now when the model get more complex I have found that using deserializers could quickly become a burden. For instance if your model stores a TextEditor and you want keep that information in the serialized state, by storing its id for instance, you won’t be able to retrieve it in the deserialize method as it’ll be called before the editors get restored so you’ll have to deal with that later.

Hope it helps.


#9

Thanks for the example! I’m knee-deep in other stuff, so I’ll come back to this, but I’ve taken note and really appreciate you for taking the time to write it.