2011/7/25 David Baelde <[email protected]>:
> 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.

I don't think this is provided by json-rpc. I was more thinking of
extending the current "help" command to return this information in
json mode.
There might exist a protocol that does that though.

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

That's a good question. I think that we should have something
backward-compatible at least at first, where sources register some
functions as they used to be, and a global setting that allows to
disable this.

Once the user has disabled the automatic registration, I think it
should simply be his duty to pick and register the things he wants.
However, we may provide a "export common stuff" that would export
everything that used to be exported (queues etc..).

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

Very much..

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

The idea of registering a method is probably the best indeed.
On_metadata was just an example and I agree that its not really
relevant at this point.

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

Sure. In this case, we'd have to type the methods associated with each
sources, though.

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

Yeah. Honnestly, I am not sure how much we actually do want to import
OO aspects in liq scripts. To me, having an "object oriented feeling"
is way enough and I don't think we need all the burden of inheritance,
extensions and etc.

I totally agree with your idea of just allowing to attach methods to
any object. This is pretty much how JS work on the surface and I find
it simple enough.

One feature that I like from JS and ruby that we could think about is
the possibility to attach a method to a source at run-time:
  s#foo = fun () -> (...)

>> 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 ;)

The most changes would be in the parsing and typing, which is your
department so I take your word here :)

I'm all for a 1.0 release before these changes and soon enough :)

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

Yup, moving the discussion there.. I've let a CC to -users but feel
free to remove it in the next response :)

Romain

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