Hi Romain,

On Mon, Jul 25, 2011 at 12:13 AM, Romain Beauxis <[email protected]> wrote:
> Our ultimate goal is to export everything that we used to do through
> telnet using json-rpc. The nice idea would be to have a command such
> as:
>  rpc.register(function)
> which would use the function's type to deduce which type of json-rpc
> request corresponds to it. For instance, a function "foo" of type:
>  (int,float) -> int
> would translate into a request of the form:
>  { method: "foo", params: { unamed: [1, 3.14]} , ... }

Here you're "translating" a liquidsoap function type to one possible
call, namely f(1,3.14). Does JSON-RPC have a notion of type, or
something that lets clients explore available services / methods? This
is what our types would translate to.

As a bonus (this is probably asking too much for now) is there a
ready-made application for browsing a service described in that means.
Using a simple standard is the top priority, but it's even better if
it comes with more tools than just libraries in major scripting
languages, so that non-programmers can use it more easily.

> Getting rid of the current mess
> ======================

I'll focus more on that part. The main idea is to unify the server
interface and the scripting language. Calling a command will be the
same in the script language and the server interface: if you want to
skip the "before" source in your transition you'll write before#skip,
and the server will be a remote REPL (read-eval-print loop, similar to
liquidsoap --interactive) in which you'll write the same source#skip.

I use the notation object#method(...) rather than object.method(...)
for simplicity, since we already use the dot as part of normal
identifiers. It would also be nice to put more structure to this use
of dot, introducing a notion of namespace or module, but it makes
sense to keep it separated from objects/methods.

One question that puzzles me is how to address sources in the server
interface. Seeing it as a REPL made me consider things like using the
environment at the end of the (final) script as the environment for
the REPL: source definitions that are visible at toplevel at the end
of the script are accessible under the same name in the server.
However this is too limiting as this does not make it possible to
access dynamically created sources, and modifications of that idea
haven't yielded anything convincing, except addressing sources by
their ID like we do currently. This would be an okay solution in a
first time, but it has its problems: (1) default IDs are often ugly
and explain little and (2) all sources would be accessible through the
server interface, even if they have nothing else to offer than
source#id and source#skip. As an alternative, we might require the
explicit addition of a source to the server interface, for example by
setting an explicit ID. I suspect that this won't be very practical --
and it only solves the ID issue in the server, not in the logs.
Another thing that would be nice would be to view graphically the
source graph, with ID annotations, to identify who's who -- for the
logs, this would require the possibility to view the graph at a given
point in time.

> However, this approach is very limited for two reasons:
>  * Some functionalities are intrinsic to some specific sources, for
> instance the queues in a request source
>  * The current approach is ugly and ad-hoc: insert_metadata(source)
> returns a new source and a function to insert metadata. This is
> cumbersome, bloat the type of the function and is just not very
> elegant..

I will add that the server is string based, and it's annoying to do
server.execute("<id>.<method> #{param}") instead of
source#method(param). Parsing the returned string must be simplified
as well: for example, to obtain a list of requests from
<source>.queue, we currently have to split a string, convert its
components to integers, and get the requests from them.

> The idea proposed by david some time ago was to lift the liquidsoap
> language and add some object-oriented aspects. I think this is really
> a good idea!
>
> For instance, instead of writing:
>  s = source.on_metadata(f, s)
> one would write:
>  s.on_metadata(f)

What I have in mind is closer to the current style and clearer from
the typing point of view.

I don't see a problem with on_metadata, because it doesn't export
commands. In the snippet above, it sounds like you can add on_metadata
handlers to any function a posteriori. Essentially it boils down to
integrating the on_metadata facility into the core source class. It
may be convenient but it might be a slippery slope: what else should
become a core feature, and what remains an operator? Some answers
result in a messy model: if you perform metadata rewriting in the same
imperative style, and install several on_metadata handlers, you have
to know if rewriting is performed before or after this and that
handler. Anyway, this is a different question from the server
interface.

> Similarly:
>  x = insert_metadata(s)
>  insert_function = fst(x)
>  s = snd(x)
> would be written:
>  insert_function = s.insert_metadata
> (or even simplier..)

This is more like what I had in mind, except that I would keep the
insert_metadata operator.

s = playlist(...) # create a source
s = insert_metadata(s) # install a metadata insertion point
...
  # insert metadata
  # in arbitrary pieces of code (or in the server)
  s#insert([("title","foo"),...])
  another_source#skip
  ...

(By the way, I realize now that object#method is not a good notation,
it creates some confusion with comments...)

Keeping an explicit insert_metadata operator, in addition to keeping
things similar to the current model, allows us to keep track of
available methods: insert_metadata takes a source (with any methods
attached) and returns a source with (the base methods and) a special
"insert" method. This way, everything is statically known, it'll also
make it possible to document available commands together with the
documentation API.

> Concerning optional functionalities, such as queues in request
> sources, I am not sure yet. I think it could be a optional methods,
> which would return None (or null or anything else) if they do not
> exist..

That would be a mess. In the style I propose, only request sources
would have the "queue" method, and only request.queue() would have
"push", etc.

> Of course, these are huge changes in the language. They raise many
> questions, such as whether we should type the source objects with
> their methods or let them be typed "source" as before etc..

There are several OO styles, I'm not sure which one is best here.

In the nominal style, classes are identified by their name, and
related by inheritance relationship. In this style we would have a
base source class, and an insert_metadata class providing the same
methods plus insertion. An insert_metadata source would be usable
everywhere a source is expected. In this style, insert_metadata is not
so much a function, but a new class with a constructor that takes a
child source. Instead of having a function of type (source)->source we
have a new class which may be written:
class insert_metadata =
  inherit source
  constructor insert_metadata(source)
  method insert : (metadata)->unit
end

The less common structural style is the one used in OCaml. Here a
class is described by its structured, ie. a set of available methods.
Two classes with the same methods are identified. Inheritance is a way
to build new classes, but at the level of types only subtyping
matters: if class A offers the same methods as class B (and possibly
some more) then A is a subtype of B and it may be used where B is
expected. In this style, insert_metadata is still a function but it
returns an object, which has all the methods of the base source class,
plus one:
insert_metadata : (source) -> object extend source with insert :
(metadata)->unit end

The notation may be improved. The "extend" is a way of avoiding to
write all the methods of the base source class.

I believe the structural style is conceptually simpler and fits well
with "light" OO approaches that would make it very easy to quickly add
user-defined methods to a source.

In the nominal style, everything is abstract in a sense, while the
structural style makes abstraction less natural. Concretely, my
problem is with the source type: what is it? In the structural style,
if we define it as "object method skip : unit, method id : string
end", ie. anything which offers a skip and ID methods, then one can
implement something of type source that has nothing to do with
streaming. Having an abstract base class source is not something that
OCaml would allow as far as I know -- it would be something like a
private class, whose methods are known but whose implementation is
hidden and which cannot be implemented in another way.

In the end, we can also invent our own style. For example, I'm toying
with the idea of attaching methods to any value, be it an integer or a
source. This way we can have a structural style and naturally keep an
abstract source type: source would be totally abstract, as is the case
currently; most operators would return a source with a few common
methods such as skip; other operators would add their own specific
method such as insert.

> My concern here is that, although all these ideas are really exciting,
> we are currently supposed to be preparing a stable release. It seems
> to me that all those ideas would take way too much code and changes
> right now and would postpone even further later a stable release.

As said before, I won't start now. Fixing bugs should be the priority,
and I don't mind if 1.0 features the current server interface style.
However, I don't think it'll be such a big change, not the kind of
change that compromises stability anyway. We'll discuss later if it
comes with a 2.0 bump or not ;)

> Please, do comment. Once we have a sort of agreement, I'll open some
> tickets and sub-tasks in the bug tracker so that we can keep track of
> the discussion :)

The mailing list (savonet-devl perhaps) seems better for preliminary
discussion IMO.

Cheers,
-- 
David

------------------------------------------------------------------------------
Storage Efficiency Calculator
This modeling tool is based on patent-pending intellectual property that
has been used successfully in hundreds of IBM storage optimization engage-
ments, worldwide.  Store less, Store more with what you own, Move data to 
the right place. Try It Now! http://www.accelacomm.com/jaw/sfnl/114/51427378/
_______________________________________________
Savonet-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/savonet-users

Reply via email to