EPICS Controls Argonne National Laboratory

Experimental Physics and
Industrial Control System

2002  2003  2004  <20052006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024  Index 2002  2003  2004  <20052006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
<== Date ==> <== Thread ==>

Subject: Re: EPICS base V4: iocCore database: include/extend/expand
From: Benjamin Franksen <[email protected]>
To: Andrew Johnson <[email protected]>
Cc: Marty Kraimer <[email protected]>
Date: Wed, 23 Feb 2005 01:25:43 +0100
On Tuesday 22 February 2005 16:44, Andrew Johnson wrote:
> Marty Kraimer wrote:
> > Benjamin Franksen wrote:
> >> (4) include "filename": At the moment it is used for two purposes:
> >>
> >> (a) At the beginning of a record type declaration. This is poor man's
> >> inheritance. It can be replaced by *naming a struct or record type* to
> >> be included at this point. (The same goes for the new 'struct'). Like
> >> this:
> >>
> >> struct(dbCommon) {
> >>    fields...
> >> }
> >>
> >> record(name) {
> >>    inherit "dbCommon"
> >>    fields...
> >> }
> >>
> >> The "inherited" part can be declared in the same file, or imported
> >> from another one (see (b) below).
>
> Something very like this idea could be implemented using the new struct
> definition without any changes:
>
> struct(dbCommon) {
>    fields ...
> }
>
> record(name) {
>    field(all, struct(dbCommon))
> }
>
> However this does move all the dbCommon fields inside the 'all' field
> (or whatever name we pick): xxx:yyy.all.scan etc.  I don't really like
> that very much.

Me neither, which is why I proposed a new construct. Another idea could be to 
make it look like a function, that takes a struct field definition and 
eliminates the outermost level of indirection:

struct(dbCommon) {
   fields ...
}

record(name) {
   flatten(field(all, struct(dbCommon)))
}

so that it's xxx:yyy.scan etc. again. Another word for 'flatten' could be 
'expand', choose your favourite...

Yet another possibility is to make 'expanded' a special (reserved) field name:

record(name) {
   field(expanded, struct(dbCommon))
}

See below for other (maybe superior) variants.

> It might be intersting if we wanted split up dbCommon 
> into different subsystems, so there'd be a scan struct (scan, pini,
> phas, evnt, disv, disa, diss, sdis, proc), a monitor struct (mlok,
> mlst), an alarm struct (stat, sevr, nsta, nsev, ...) etc.  However I'm
> not completely sure of the advantage of this yet other than code
> modularity.

I think code modularity is quite an important advantage. See below, too.

> >> The same mechanism can be used for menus.
>
> The idea of having an inheritance mechanism is interesting, and I think
> it would be relatively easy to implement for records, structs and menus.
> However I want to put my stamp on it (of course!).  I think the keyword
> would be better outside of the braces, maybe like this:
>
> struct(dbCommon) {
>    fields ...
> }
>
> record(calc) extends(dbCommon) {
>    fields ...
> }
>
> record(calcOut) extends(calc) {
>    fields ...
> }

The problem with this is that now you are limited to only one extension which 
also has to be put at a certain default place (i.e. at the beginning). For 
dbCommon that is what we wanted in the past, so we can cast any record to 
dbCommon.

The main advantage to place it inside the braces is that we are able to select 
an arbitrary place, i.e. maybe after other field definitions, and therefore 
we can also use multiple 'includes'. This would have more uses than only 
plain inheritance (see your suggestion above to split dbCommon into 
subsystems).

So, how can we achieve both, direct access to sub-fields /and/ access to the 
whole sub-struct, even if it is not at the beginning of the super-struct?

Answer: We add a field that points to the (beginning of the) sub-struct. Thus, 
here is my refined proposal:

Keyword 'expand' actually creates a (additional) field which is a pointer to 
the expanded struct.

struct(s) {
   field(x,dbf_double)
   ...
}

record(r) {
   field(common,expand(struct(dbCommon)))
   field(y,dbf_string)
   field(z,expand(struct(s)))
}

(Note that the 'application' of expand is now only around the field /type/, 
since the field name is now visible.)

This would be translated to C thus:

typedef struct {
   double x;
   ...
} sStruct;

typedef struct {
   dbCommonStruct *common;
   ...dbCommon fields...
   epicsString y;
   sStruct *z;
   double x;
   ...
}

Thus no more casting is necessary. In addition, dbToRecordtypeH should provide 
initialization routines that set these pointer fields correctly.

One disadvantage is that we need special code that handles the distinction 
between real sub-structs and flattened ones. Maybe such code can be generated 
by dbToRecordtypeH. A second disadvantage is the waste of our precious 
memory. TANSTAAFL.

Another, maybe even better, idea would be that dbToRecordtypeH generates 
macros that perform the pointer arithmetic and the casting, e.g. 
'ao_to_dbCommon' or 'r_to_s', as in the above example. Then we wouldn't need 
the pointer-to-the-sub-struct fields but still had a way to easily (and 
safely!) refer to the requested sub-structure by reference.

Note that the dbCommon fields still need to be at the beginning of a record.

> What actually happens inside the parser is that the child gets created
> by copying the complete definition of the parent object, rather than
> from scratch.  Note that I'm allowing a record to inherit from a struct
> above, I think that's probably a reasonable thing to do.

Of course.

> However the 
> DBD file is as far as the inheritance would go, the record support
> routines would be on their own.

That is also what I have been thinking.

> Maybe we should ensure that calcOut can 
> find and call calc's support routines relatively easily, but we haven't
> really thought about this properly - I'm just saying at this stage that
> we could do the above textual inheritance if we want to.  The same
> syntax would work for menus:
>
> menu(menuScanBasic) {
>    choice(menuScanPassive, "Passive")
>    choice(menuScanEvent,"Event")
>    choice(menuScanI_O_Intr, "I/O Intr")
> }
>
> menu(menuScan) extends(menuScanBasic) {
>    choice(menuScan10Second,"10 second")
>    ...
> }

This could also be handled by one or the other version of 'expand'/'flatten' 
and with the same advantages. Although the arguments are not as convincing in 
this case, so I have no strong opinion here.

> >> (b) At the top-level: This is poor man's modularization. But complete
> >> textual inclusion is often too coarse. I propose a limited form of
> >> module import (allowed only at the top-level):
> >>
> >> import <module-name> (<element-name>, ...)
> >>
> >> for element-wise import (i.e. only the listed names are imported) or
> >>
> >> import <module-name> [ hiding (<element-name>, ...) ]
> >>
> >> for importing everything, where the optional 'hiding' clause can be
> >> used to list names that should not be imported. <module-name> would be
> >> the filename of the imported module without the extension.
>
> I don't see any advantage of providing import like that, and do see lots
> of disadvantages - DBD files are not an attempt at being able to create
> any kind of data structure, and it would require us to store
> significantly more meta-data than we currently do - what elements come
> from which file, what the hiding scope is of each name (not least how do
> we convert name hiding into equivalent C code, and what the search path
> is to a name in any particular context).

I agree that it adds a certain amount of complexity and I am not completely 
convinced of the necessity either. I just thought that hiding some 
definitions or selecting only certain ones from another file might be handy. 
I readily admit that I haven't thought much about implementation difficulties 
such as scoping, meta-data etc. Note, however, that at least the search path 
issue is exactly the same as with simple textual inclusion. 

> The advantage of the include technique that we're currently using is
> that it's actually pretty simple to code and understand.  There is no
> need to remember which file a definition came from or its scope.

Yes.

> Unless you can explain what this permits us to accomplish that we
> couldn't with the much simpler textual inclusion, I see no point is
> spending more time on implementing something that we need to.

If we can agree that textual inclusion is limited to the top-level, i.e. that 
we replace all other uses by more structured means (inherit, extends, expand, 
flatten, whatever...) than I will no longer object.

Cheers,
Ben


References:
Re: EPICS base V4: iocCore database Marty Kraimer
Re: EPICS base V4: iocCore database Andrew Johnson

Navigate by Date:
Prev: Re: EPICS base V4: iocCore database: registrar, special Benjamin Franksen
Next: Re: [Fwd: RE: EPICS base V4: iocCore database] Benjamin Franksen
Index: 2002  2003  2004  <20052006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
Navigate by Thread:
Prev: Re: EPICS base V4: iocCore database: registrar, special Benjamin Franksen
Next: Re: EPICS base V4: iocCore database Marty Kraimer
Index: 2002  2003  2004  <20052006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
ANJ, 02 Feb 2012 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·