octave-maintainers
[Top][All Lists]
Advanced

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

Re: Update on Eliminating Singleton Objects


From: Rik
Subject: Re: Update on Eliminating Singleton Objects
Date: Sun, 7 Jan 2018 17:28:22 -0800

On 01/06/2018 02:50 PM, John W. Eaton wrote:
> [I'm quoting the whole message since it's been nearly 8 months...]
>
> On 05/18/2017 04:40 PM, John W. Eaton wrote:
>> On 04/30/2017 11:28 PM, Rik wrote:
>>
>>> Also, if the pointer to the interpreter really is used all over the code
>>> base, maybe it does make sense to have it be a global?  I know it is
>>> generally frowned upon, but it might actually be simpler then re-working
>>> the API to pass the pointer through to all functions.
>>
>> I'm beginning to think the idea of being able to start multiple
>> interpreters in a single program is just never going to be possible, at
>> least not with the current libraries we use and APIs we need to support.
>>
>> But even so, would it still be beneficial to more clearly define which
>> objects own which data?  For example, the interpreter currently owns the
>> evaluator and the load-path object.  It seems to me that most other
>> global objects like the symbol table, type info, the call stack, etc.,
>> should probably also be part of the interpreter or evaluator rather than
>> separate global singleton objects.
>>
>> I guess the question I'm asking is whether we should have an "Octave
>> interpreter" object that is composed of all the things that make up the
>> interpreter, or whether we should have a bunch of global objects
>> (implemented as singletons or not; that's really just an implementation
>> detail) that are loosely organized to make up the interpreter.
>>
>> One nice thing about having the objects that make up the interpreter
>> organized as a single object is that all resource allocation for that
>> interpreter object can be managed by the constructor and destructor for
>> the object.  So, if things are done correctly, one may create/destroy
>> interpreter objects as needed.  This could be useful for embedding the
>> interpreter in applications.
>>
>> Another advantage is that the components of the interpreter can be
>> assumed to be valid as long as the interpreter object is valid.
>>
>> Objects that are owned by the interpreter may (if needed) be constructed
>> with a reference to the interpreter that contains them.  Then they can
>> have access to other interpreter objects without having to use a global
>> object.  To me, this seems similar to the idea of a parent widget in Qt.
>>
>> I know this is not strictly necessary since we could always just use a
>> global variable (and why not, if there is only ever going to be one
>> interpreter object?).  But avoiding the global means we are at least
>> moving in the direction of having a self-contained interpreter object
>> that could allow for simultaneous instances.
>>
>> Finally, here's what I'm thinking of for DEFUN-like built-in functions.
>> I propose adding another signature for built-in functions that accepts a
>> reference to the interpreter that invoked them.  For example
>>
>>    DEFMETHOD (fun, interp, args, nargout)
>>    {
>>      // Here, interp is a reference, so
>>      // guaranteed to be valid.  Just use it.
>>
>>      interp.do_something ();
>>
>>      ...
>>    }
>>
>> To me, this seems better than accessing a global pointer, or even
>> passing a pointer, because a reference must be valid so there's no need
>> to do something like
>>
>>    if (! interp)
>>      error ("fun: no interpreter context!");
>
> Now that we've had some experience with this approach, I'd say my
> reaction is mostly positive.  Today, I eliminated the singleton pattern
> from the octave_value_typeinfo class and now there are about 15 objects
> remaining that use the singleton idiom.  I'm still hoping to remove the
> singleton pattern from all of them.
>
> There are some locations where accessing an object owned by the
> interpreter can't be done easily without asking for a global reference to
> the interpreter.  That's what the functions in the
> interpreter-private.{h,cc} files allow.
>
> Over time, as more things are added to the interpreter object, or as more
> DEFUN functions become DEFMETHOD functions, I've been able to remove a
> few calls to the interpreter-private functions.  But I don't think it
> will be reasonable to eliminate all uses of the global object.
>
> Even so, we still may be able to have multiple interpreter objects active
> in the same program if we are careful to use thread_local data (standard
> in C++11) instead of the usual static (class or file scope) or global data.
>
> So my new goal is to eliminate all the singleton objects, pass references
> to the interpreter and related objects where it is reasonable to do so,
> and make all global and static objects that are related to the
> interpreter be thread_local instead of plain old global or static
> variables, and hopefully one day be able to start a program that uses
> multiple Octave interperters simultaneously, even if they must run in
> separate threads.
>
> Comments?

This is a lot of code re-factoring.  Are there other benefits besides being
able to run multiple interpreters out of the same program (which sounds
like an edge use case)?  Is there an impact on performance if every
function call has to push a pointer to the current interpreter on to the
stack before executing?

--Rik
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]