Re: object newbie [message #21126] |
Fri, 11 August 2000 00:00  |
John-David T. Smith
Messages: 384 Registered: January 2000
|
Senior Member |
|
|
Martin Schultz wrote:
>
> Mark Hadfield wrote:
>>
> [...]
>
>> Also object properties are not strictly tied to the class
>> structure: GetProperty/SetProperty keywords can represent tags in the class
>> structure or they can be dynamically interpreted, thus hiding the
>> implementation details.
>>
>
> ... to elaborate (because Chip calls himself an object newbie): I have
> an example where I store among other things an array of structures
> (actually objects of the same type) in the object (and I am in fact
> using a container for this). Say this structure array is named
> "campaigns". In my GetProperty method I then have keywords to access
> - the complete array as objects campaigns=campaigns
> - the campaigns data as structrues struc_campaigns=struc_campaigns
> - only the campaign names cnames=cnames
> - only the campaign dates cdates=cdates
> etc.
>
> Specific retrieval methods (usually functions then) enhance the
> flexibility of the access. E.g.
> GetCampaignDates(name=name) can be used to retrieve the dates for
> campaigns selected by name
> (including a pattern match) -- this is
> something I would consider
> "value added feature" when you use
> objects.
>
> The GetProperty method may in fact use the special retrieval methods to
> extract things. As long as you store only small amounts of data, it
> won't matter if you access the campaigns structure array several times
> and pass parts of it between methods. If you envision huge amounts of
> data you may want to think more carefully how often these arrays must be
> copied. I haven't dealt with these issues yet, but I would be happy to
> hear comments.
>
> Cheers,
> Martin
It should be pointed out that the GetProperty procedures outlined in the prior
postings are fully functional only when the _REF_EXTRA keyword is employed (in
fact it was created by RSI due to this failing). This allows proper keyword
inheritance when chaining up to the properties of superclasses -- the only other
option is enumerating in the keyword list all superclass properties, which of
course is an egregious violation of encapsulation... But of course, all this
still does not excuse the inflexible encapsulation functionality IDL's object
framework presents us.
Remember to give those properties unique names -- if you follow the data member
naming convention as Martin does (e.g. cnames=cnames) you'll avoid risking
namespace conflicts an additional time, since you have to worry about it with
INHERIT'ing anyway. This leaves only the computed ("dynamically interpreted")
property names to worry over.
As far as the array copying issue, for dealing with those properties which are
truly large, the only way to pass by reference out of your GetProperty method is
to use pointers... which is actually good: imagine the confusion of having
otherwise unremarkable variables as silent referents to object data members.
Pointers are your friends.
An additional side note: I think a basic concern people have with pointer usage
is memory management -- forgetting to free pointers at the right time, or the
awkwardness of having to free them. When you have various nested levels of
pointers to structures with pointers to arrays of pointers, etc., it can get
ugly. There are a few tricks to make freeing pointers at cleanup (object or
otherwise) less cumbersome. They rely on a few convenient properties of
ptr_free:
1. The fact that you may free a null pointer with impunity.
2. Arguments (of which there may be any number), are freed from first to last.
3. Pointers in arrays can be freed all at once by passing the array.
Consider this statement:
if ptr_valid(self.Recs) then $
ptr_free,(*self.Recs).Ints,(*self.Recs).Time,self.Recs
self.Recs is a pointer to a struct containing various other pointers (like Ints
and Time), which may or may not be defined (i.e. they might be null pointers).
Rather than pedantically test all of the cases before freeing each field and
then, and only then, free the higher level pointer, I rely on properties #1 &
#2. I can free self.Recs ptr field members and the pointer itself all in one
go. No worry about the chicken before the egg scenario, or undefined
pointers.
Consider a pointer to an array of pointers: self.parr. Freeing it is as simple
as:
if ptr_valid(self.parr) then ptr_free,*self.parr,self.parr
This works even if any or all of the pointers are null -- a general assumption
for which I always allow. With these few properties of ptr_free you can really
reduce the hassle of cleaning up after yourself. Allowing any pointer to be a
potential null pointer also allows you to prune various things from your data
structure before cleanup, to save them for other uses. Simply do something
like:
kept_ptr=self.saveme
self.saveme=ptr_new()
This technique has a myriad of uses -- but that's another article.
Good Luck,
JD
--
J.D. Smith /*\ WORK: (607) 255-6263
Cornell University Dept. of Astronomy \*/ (607) 255-5842
304 Space Sciences Bldg. /*\ FAX: (607) 255-5875
Ithaca, NY 14853 \*/
|
|
|
|
|
|
Re: object newbie [message #21256 is a reply to message #21126] |
Mon, 14 August 2000 00:00  |
Martin Schultz
Messages: 515 Registered: August 1997
|
Senior Member |
|
|
"J.D. Smith" wrote:
>
> Martin Schultz wrote:
>>
>>
>>
>> The GetProperty method may in fact use the special retrieval methods to
>> extract things. As long as you store only small amounts of data, it
>> won't matter if you access the campaigns structure array several times
>> and pass parts of it between methods. If you envision huge amounts of
>> data you may want to think more carefully how often these arrays must be
>> copied. I haven't dealt with these issues yet, but I would be happy to
>> hear comments.
>>
>> Cheers,
>> Martin
>
> And J.D. Smith commented:
>
>
> As far as the array copying issue, for dealing with those properties which are
> truly large, the only way to pass by reference out of your GetProperty method is
> to use pointers... which is actually good: imagine the confusion of having
> otherwise unremarkable variables as silent referents to object data members.
> Pointers are your friends.
>
I fully agree, but ... ;-)
I am currently reworking a netcdf file object (based in turn on a
geenric datafile object, but that"s a detail), and I am thinking about
how to best achieve the two conflicting goals:
* allow flexible access to subportions of the data
* minimize memory usage
What I envision is a method that would allow something like
thefile->GetData, variables=['o3','co'], /include_dimensions,
lon=,lat=
which should return an array containing only the selected data. But this
means that I have to copy the data rather than pass a pointer back,
because otherwise the next access with a different range would overwrite
the data stored in the object and thus render the first pointer
"invalid" in the sense that it would point to something different now.
The problem arises, because I do not want to read in the whole field
first and then extract what I need but I want to take advantage of
netcdf's capabilitity to extract a subset of the data directly from the
file. So, the data will be loaded dynamically only when requested. On
the other hand it will also be possible to retrieve the complete
variable data from the file and do the extraction in memory, which may
be considerably faster if you need frequent access to various portions
of the data. For example, the dimension variables
(for non-netcdf'ers: these are variables holding the values of the
dimensions of other variables.
Example: a model ozone field may have dimensions LON, LAT, and LEV,
then LON will be a variable
named LON which contains the longitude values, i.e. 2.5, 7.5, 12.5,
... 357.5 on a rather coarse grid)
will always be loaded into memory and accessed from there. Makes things
a little more convoluted if I want to support write access to the netcdf
file as well (which I do want), but it's a nice challenge, and
thanks to the beauty of objects, the user doesn't have to care a dent.
As to pointer freeing: I remember that it took me three or four attempts
(about 15 years ago) before I had a vague idea what a pointer was and
how one could use one. Well, this was Pascal (maybe Borland 3 or so),
and things have certainly changed since then (my little daughters
learned about pointers at age 2 already: "Where is pointer, where is
pointer? Here I am..."). But the key to not loosing pointers nor data is
that you should make it clear to yourself where your data actually
resides. What often helps me is the concept of a "master pointer", i.e.
the one pointer that got the data passed first. And then I usually only
allow the master pointer to free the data. All other pointers are
considered local variables (they are just unsigned longs in a sense),
and I don't need to care about memory allocation or freeing for these.
Example:
master = Ptr_New(data) ; this is the master pointer
other = master ; this is only a local pointer
(*other) = (*other)*0.5 ; this operation affects the data
which is conceptually stored in master
Ptr_Free, master ; free memory
So, you don't have to worry about the fate of other at all (just that
one should of course check if it is a valid pointer before using it).
[excerpt from b2p2 = beginners' guide to pointers, unpublished material,
2000, copyright = left]
Cheers,
Martin
--
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ [[[[[[[
[[ Dr. Martin Schultz Max-Planck-Institut fuer Meteorologie [[
[[ Bundesstr. 55, 20146 Hamburg [[
[[ phone: +49 40 41173-308 [[
[[ fax: +49 40 41173-298 [[
[[ martin.schultz@dkrz.de [[
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ [[[[[[[
|
|
|