Re: [Vala] Design - Serialization Library - Problem: ref and async



On Sat, Apr 2, 2016 at 11:11 PM, Guillaume Poirier-Morency <
guillaumepoiriermorency gmail com> wrote:

Le samedi 02 avril 2016 à 21:08 +0800, Alan Manuel Gloria a écrit :
Hi all,

I'm trying to design a serialization library for Vala.

My initial design sketch was something like this:

// Library
/* An object that can be saved or loaded.  */
public
interface Serializable : Object {
  public abstract async
  void serialize(Archive ar) throws Error;
}
/* An object that can save or load.  */
public
abstract class Archive : Object {
  public abstract
  bool is_saving();
  public abstract async
  void archive_string(ref string s) throws Error;
  public abstract async
  void archive_int(ref int i) throws Error;
  /* .. a dozen other methods for various types .... */
}
//Client code
internal
class Something : Object, Serializable {
  private string name;
  private int id;
  public virtual async
  void serialize(Archive ar) throws Error {
    yield ar.archive_string(ref name);
    yield ar.archive_int(ref id);
  }
}

The point of the design is that a Serializable would, ideally, have a
single section of code for both loading and saving, to ensure that
loading
and saving are correctly compatible.  This pattern is similar to some
serialization libraries in C++.

Since an archive could either be saving or loading, it needs ref
access.

Unfortunately, it seems that there are a few good reasons that async
and
ref are not compatible.  The major one seems to be that exposing a
ref
argument of an async method to a non-async method could lead to a bug
where
the non-async method uses a local variable and passes it into the
non-async
method.  (for an async method, local variables are actually allocated
in
its data structure, so it's safe to use a local variable in an async
method
to another async method by ref).

I'd like to ask that ref and out be allowed in async, and restrict
them so
that async methods with ref/out arguments can only be called from
other
async methods (to avoid non-async variable reffed by an async method
problem), but I'd probably need to work on that myself, haha.

So, given the limits of today's Vala, what would be better?

1.  Remove "async".  This limits me to total data sizes that can
comfortably be written or saved while blocking the main loop.  I
could also
serialize in a true OS background thread, and ensure somehow that the
object being serialized is completely locked until the entire
serialization
is completed.

+: retain similar style as above.  -: blocking.

2.  Remove "ref".  That means I code something like:

public virtual async
void serialize(Archive ar) throws Error {
  name = yield ar.archive_string(name);
  id = yield ar.archive_int(id);
}

+: still nonblocking.  -: specify object field twice (violate DRY),
mismatch may lead to subtle bugs

Use out parameters instead, they are known to work with async
functions.


You mean like this?

void serialize (Archive ar) throws Error {
  yield ar.archive_string(out name, name);
  yield ar.archive_int(out d, d);
}

Still has the DRY problem of repeating the field name twice, although I
guess problems of mismatching the out field and the input field are
mitigated by placing them next to each other.



Personally, I would suggest that you use GVariant for serialization.
APIs are here: http://valadoc.org/#!api=glib-2.0/GLib.Variant

There is an example here using VariantBuilder and VariantIter http://va
ladoc.org/#!api=glib-2.0/GLib.VariantIter

Basically, an async method in Vala is a GSimpleAsyncResult that run in
a background thread (see GIO thread pool), so you don't really need to
work with threads here.

You could use Redis to save the states as it support binary storage or
store them in files.


Thanks, I'll check.

Initial checking seems to me that it would be useable for backend
implementation (i.e. derived classes of the Archive class) but not so much
for the actual API I want to use in client code.

In particular, I want to serialize actual objects, not just plain old data
(sorry if my sketch didn't indicate it, basically there will be
archive_object<T>(ref T), archive_unowned<T>(ref unowned T),
archive_nullable_unowned<T>(ref unowned T?) etc.).  Shared sub-structure
needs to be saved (e.g. the location object of a ship needs to be the same
as the location object used on the map).  I can use GVariant and a
saving/loading map to/from objects/numeric ids, but GVariant doesn't seem
to have it out of the box.

My question here is what is the best API between client/serialization
library given the features Vala has.



Currently, my library client is a turn-based game where the Server
component periodically saves its state if it is modified.

Sincerely,
AmkG
_______________________________________________
vala-list mailing list
vala-list gnome org
https://mail.gnome.org/mailman/listinfo/vala-list
--
Guillaume Poirier-Morency <guillaumepoiriermorency gmail com>

Étudiant au baccalauréat en Informatique à l'Université de Montréal
Développeur d'application web

Mon blog: https://arteymix.github.io/
Mon projet de coopérative: https://pittoresque.github.io/
Clé PGP: B1AD6EA5
_______________________________________________
vala-list mailing list
vala-list gnome org
https://mail.gnome.org/mailman/listinfo/vala-list




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]