Topic: methods for accessing attributes


Author: JdeBP@jba.co.uk (Jonathan de Boyne Pollard)
Date: 1996/04/25
Raw View
Steve Clamage (clamage@taumet.eng.sun.com) wrote:
[Moderator's note: actually it was someone else, not Steve Clamage. -fjh.]
| For instance, let's say we've got:
|
|  class Display {
|  public:
|   int wid, hgt;
|  }
|
| (with lots of other useful stuff too, but we'll omit that for now)
|
| If lots of code already exists like the following:
|
|  void blah(Display &d)
|  {
|   d.wid = 80;
|  }
|
| And now suppose that we want Display to do something when
| the width is changed--- has there been any consideration of adding
| a way of doing this?  (besides changing all the direct accesses
| to function calls)
| Or is there some way, within the current standard, to do this?

It can be done without violating the standard, and there already exist
several implementations that let you do so.

DirectToSOM C++ compilers (MetaWare High C++ 3.32 and IBM VisualAge C++ 3.03)
provide this functionality as a language extension, and I've made quite heavy
use of this myself in my own class libraries.  For example :

    //
    //    (Simplified) Excerpt from jpmcls.h :-
    //

    class GuiWindow : public SOMObject {
    public:
        // ...
        long width, bottom, height, left ;

 pragma SOM_Attribute(width, bottom, height, left;
    noset, noget, virtualaccessors) ;
        // ...

 HWND handle ;
    } ;
    class GuiForm : public GuiWindow {
    public:
 // ...
 virtual MRESULT SizeEvent(short, short) ;
 // ...
    } ;


    //
    //    Excerpt from some application code :-
    //

    class DesignerMainWindow : public GuiForm {
    public:
 // ...
 GuiBar toolbar, statusline ;
 // ...

 virtual MRESULT SizeEvent(short, short) ;

 // ...
    } ;

    MRESULT
    DesignerMainWindow::SizeEvent(short x, short y)
    {
 if (!IsMinimised()) {
     toolbar.width = x ;
     toolbar.bottom = y - etoolbar.height ;
     statusline.width = x ;
 }

 return 0 ;
    }

Programmers from <cough> other languages may find this syntax hauntingly
familiar.  (-:

Data member accesses from "outside" of the class are translated by the
compiler "under the hood" into run-time calls to "_get_XXX" and "_set_XXX"
accessor methods, which are implicitly declared as a result of the data
members being marked as attributes.

Data member accesses from "inside" the class of course are not altered, and
access the data member storeage directly (thus avoiding the catch 22
problem of how to implement the accessor functions themselves).

( I use the terms "outside" and "inside" loosely.  The main criterion that
  the compiler uses for determining what to do -- I believe -- is what
  particular name-lookup rule is satisifed by the data member name.  )

The accessor methods themselves can be *defined* either implicitly  by the
compiler, or explicitly by the programmer.  Since I want to intercept all
calls to get and set the width, and map them onto Presentation Manager API
calls, I've used the "noset" and "noget" modifiers above, and included the
following explicit function definitions in the library :

 //
 // Excerpt from window.cpp :-
 //

 void
 GuiWindow::_set_width ( long w )
 {
     SWP swp ;
     if (WinQueryWindowPos(handle, &swp))
  WinSetWindowPos(handle, 0, 0, 0, w, swp.cy, SWP_SIZE) ;
 }

 long
 GuiWindow::_get_width () const
 {
     SWP swp ;
     return WinQueryWindowPos(handle, &swp) ? swp.cx : 0 ;
 }

I have three suggestions.

To those who want the functionality: I suggest that you go and investigate
DirectToSOM C++ compilers such as MetaWare High C++ and IBM VisualAge C++.
They work.  They provide what you want.  And you don't have to give up
using C++ in order to get it.

To those who are seeking standardisation of such syntax extensions: I suggest
that you seriously consider the situation of people such as myself, who
already have a fair amount of code that uses this syntax, in *existing* and
*working* C++ applications.  I'd appreciate it if you didn't break hundreds
of thousands of lines of code.  So don't invent some new syntax that no-one
uses.  As much as you can, standardise the syntax that people are *already*
using.

And to those vendors who haven't yet implemented DirectToSOM in their C++
compilers: pull your fingers out and do it !
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: jah@cais.cais.com (John A Hughes)
Date: 1996/04/18
Raw View
In article <9604160147.AA25931@grace>,
Steve Clamage <clamage@taumet.eng.sun.com> wrote:
[I don't think this was really Steve Clamage, but that's what my
newsreader said!!]
>If lots of code already exists like the following:
>
> void blah(Display &d)
> {
>  d.wid = 80;
> }
>
>And now suppose that we want Display to do something when
>the width is changed--- has there been any consideration of adding
>a way of doing this?  (besides changing all the direct accesses
>to function calls)
>Or is there some way, within the current standard, to do this?
>I toyed with some ways that involved replacing the type of 'wid'
>(int) with some class that did the desired operation when assigned to,
>but in order to have full access to Display, it has to be a specialized
>class for each instance variable, and each class has to have special
>code containing knowledge of the offset of 'wid' within 'Display'
>and then it has to use that offset along with some really evil
>casting to find the address of the 'Display' object it resides in.

No, not necessarily. For the exact case you showed in your post, you
could have a class like this, though it wouldn't solve all your
problems:

template<class MainClass, class MemberClass>
class SmartMember {
public:
   SmartMember(MainClass &o, void(*MainClass::f)(MemberClass))
      : main_obj(o), change_fn(f) {}
   SmartMember &operator=(MemberClass t) {
      main_obj.change_fn(t);
   }
   operator T() {return datum;}
private:
   MainClass &main_obj;
   MemberClass datum;
   void(*MainClass::change_fn)(MemberClass);
};

So now your class Display looks something like this:

class Display {
public:
   Display(...);
   SmartMember<Display,int> wid;
//...
private:
   void updateWid(int new_wid);
//...
};

and you'll need to make sure your Display constructors do the following:

Display::Display(...) : wid(*this, &Display::updateWid) {
//...
}

which means that wid now knows it's a member of the given display and that
when it changes it should change via updateWid.

Now you can leave all your

void blah(Display &d)
{
 d.wid = 80;
}

as they are. The SmartMember class is generic so you can do it for
every kind of member of every kind of class that has assignment
semantics.

I suspect defining this one class and changing a couple constructors
is easier than changing all your assignments, but then again, it's
weird and I only suggested it to show that you COULD do it without
changing all your assignment statements or defining a class for every
type.  This won't work at all if you ever pass wid by reference and
expect changes to happen that way. You should have known better than
to make your member data public in the first place, and rewriting it
is probably the RIGHT thing to do.


Have fun

jah
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: damian@molly.cs.monash.edu.au (Damian Conway)
Date: 1996/04/18
Raw View
Steve Clamage writes (or forwards, I suspect):

>Has there been any consideration of adding to the standard
>a way of overloading access to instance variables, so that
>code that directly accesses a variable can be made to call
>an access function if the class is modified to need it?

>For instance, let's say we've got:
>
> class Display {
> public:
>  int wid, hgt;
> }

>If lots of code already exists like the following:

> void blah(Display &d)
> {
>  d.wid = 80;
> }

>And now suppose that we want Display to do something when
>the width is changed--- has there been any consideration of adding
>a way of doing this?  (besides changing all the direct accesses
>to function calls)

Something like this will do what you want (note that you'll still have to
recompile everything that accesses the data members):


    template <class Owner, class Type>
    class AccessControlled
    {
 typedef Type (Owner::*Filter)(const Type&);

    public:
 AccessControlled(Owner * owner, Filter read = 0, Filter write = 0)
 : This(owner)
 , readFilter(read)
 , writeFilter(write)
 {}

 operator Type(void)
 {
  if (readFilter)
   return (This->*readFilter)(value);
  else
   return value;
 }

 AccessControlled& operator= (const Type& newval)
 {
  if (writeFilter)
   value = (This->*writeFilter)(newval);
  else
   value = newval;
  return *this;
 }

    private:
 Owner* This;
 Type value;
 Filter readFilter;
 Filter writeFilter;
    };



And then you can change class Display thus:

    class Display
    {
    public:
 AccessControlled<Display,int> wid;
 AccessControlled<Display,int> hgt;
 AccessControlled<Display,int> dph;


 // NEED A CTOR TO INITIALIZE THE FILTERS FOR THE ABOVE DATA MEMBERS

 Display(void)
 : wid(this,logAccess)  // NO VALUE CHECKING FOR wgt
 , hgt(this,0,checkVal)  // NO ACCESS LOGGING FOR hgt
 , dph(this,logAccess,checkSize) // BOTH LOGGING AND CHECKING FOR dph
 {}

    private:
 int logAccess(const int& val)
 {
  // DO WHATEVER WITH CURRENT VALUE OF WID BEFORE PASSING IT OUT
  // EG: LOG THE ACCESS.....

  clog << "Accessing value " << val << endl;
  return val;
 }

 int checkVal(const int& newval)
 {
  // DO WHATEVER WITH NEW VALUE FOR VAR BEFORE PASSING IT IN
  // EG: MAKE SURE IT'S POSITIVE, NON-ZERO....

  if (newval<=0)
   return 1;
  else
   return newval;
 }

 int checkSize(const int& newval)
 {
  // DO WHATEVER WITH NEW VALUE FOR VAR BEFORE PASSING IT IN
  // EG: MAKE SURE IT'S IN THE RANGE [-10..10]

  if (newval<-10)
   return -10;
  else if (newval>10)
   return 10;
  else
   return newval;
 }
    };


>If [access functions are required], then I'd like to stick with some sort
>of standard naming convention... but I've seen all kinds of different
>variations...

>So, which of these do people think is the most acceptable?

> 1)
>  class Display {
>   int wid;
>  public:
>   int get_wid();
>   void set_wid(int);
>  }

I greatly prefer this approach.
It's clear, obvious, and says explicitly what it means.

damian
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  who: Damian Conway               email: damian@bruce.cs.monash.edu.au
where: Dept. Computer Science      phone: +61-3-565-5184
       Monash University             fax: +61-3-565-5146
       Clayton 3168                quote: "A pessimist is never disappointed."
       AUSTRALIA
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: feb6399@osfmail.isc.rit.edu (Frank Barrus)
Date: 1996/04/15
Raw View
I'm not sure if this has been previously discuessed, but so
far I've seen no mention of it, so...

Has there been any consideration of adding to the standard
a way of overloading access to instance variables, so that
code that directly accesses a variable can be made to call
an access function if the class is modified to need it?

For instance, let's say we've got:

 class Display {
 public:
  int wid, hgt;
 }

(with lots of other useful stuff too, but we'll omit that for now)

If lots of code already exists like the following:

 void blah(Display &d)
 {
  d.wid = 80;
 }

And now suppose that we want Display to do something when
the width is changed--- has there been any consideration of adding
a way of doing this?  (besides changing all the direct accesses
to function calls)
Or is there some way, within the current standard, to do this?
I toyed with some ways that involved replacing the type of 'wid'
(int) with some class that did the desired operation when assigned to,
but in order to have full access to Display, it has to be a specialized
class for each instance variable, and each class has to have special
code containing knowledge of the offset of 'wid' within 'Display'
and then it has to use that offset along with some really evil
casting to find the address of the 'Display' object it resides in.
Or is there an easier way?

Or shall all old code of this sort be simply converted to use
access methods, and should directly accessible public
instance variables be completely avoided?

If that's the case, then I'd like to stick with some sort of
standard naming convention...  but I've seen all kinds of different
variations...

So, which of these do people think is the most acceptable?

 1)
  class Display {
   int wid;
  public:
   int get_wid();
   void set_wid(int);
  }

 2)
  class Display {
   int _wid;
  public:
   int wid();
   void wid(int);
  }

 3)
  class Display {
   int wid;
  public:
   int _wid();
   void _wid(int);
  }


(Are there others I'm not aware of?)

I've used all three methods at different times over the years.
Although, lately, it seems that #2 comes closest to resembling
the normal method of accessing the instance variables, and within
the class it makes it clear when a publicly (through
the access methods) available instance variable is being accessed.


Any comments, suggestions, preferred techniques, etc?


--
Frank "Shaggy" Barrus: feb6399@osfmail.isc.rit.edu, shaggy@csh.rit.edu
http://www.csh.rit.edu/~shaggy
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: clamage@taumet.eng.sun.com (Steve Clamage)
Date: 1996/04/16
Raw View
I'm not sure if this has been previously discuessed, but so
far I've seen no mention of it, so...

Has there been any consideration of adding to the standard
a way of overloading access to instance variables, so that
code that directly accesses a variable can be made to call
an access function if the class is modified to need it?

For instance, let's say we've got:

 class Display {
 public:
  int wid, hgt;
 }

(with lots of other useful stuff too, but we'll omit that for now)

If lots of code already exists like the following:

 void blah(Display &d)
 {
  d.wid = 80;
 }

And now suppose that we want Display to do something when
the width is changed--- has there been any consideration of adding
a way of doing this?  (besides changing all the direct accesses
to function calls)
Or is there some way, within the current standard, to do this?
I toyed with some ways that involved replacing the type of 'wid'
(int) with some class that did the desired operation when assigned to,
but in order to have full access to Display, it has to be a specialized
class for each instance variable, and each class has to have special
code containing knowledge of the offset of 'wid' within 'Display'
and then it has to use that offset along with some really evil
casting to find the address of the 'Display' object it resides in.
Or is there an easier way?

Or shall all old code of this sort be simply converted to use
access methods, and should directly accessible public
instance variables be completely avoided?

If that's the case, then I'd like to stick with some sort of
standard naming convention...  but I've seen all kinds of different
variations...

So, which of these do people think is the most acceptable?

 1)
  class Display {
   int wid;
  public:
   int get_wid();
   void set_wid(int);
  }

 2)
  class Display {
   int _wid;
  public:
   int wid();
   void wid(int);
  }

 3)
  class Display {
   int wid;
  public:
   int _wid();
   void _wid(int);
  }


(Are there others I'm not aware of?)

I've used all three methods at different times over the years.
Although, lately, it seems that #2 comes closest to resembling
the normal method of accessing the instance variables, and within
the class it makes it clear when a publicly (through
the access methods) available instance variable is being accessed.


Any comments, suggestions, preferred techniques, etc?




[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Gabriel Sanchez Gutierrez <gsg@sema.es>
Date: 1996/04/16
Raw View
See also
   The Property Template
   C++ Report.
   Nov-Dec. 95. Page 29

--
--------------------------------------------------------------------------
Gabriel Sanchez Gutierrez | Phone:        +34.1.327.28.28
DIS - Sema Group sae      | Fax:          +34.1.754.32.52
Albarracin, 25            | Email:        gsg@sema.es
28037 Madrid - SPAIN      | WWW:          http://www.sema.es/~gsg



[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: abell@mindspring.com (Andrew Bell)
Date: 1996/04/16
Raw View
feb6399@osfmail.isc.rit.edu (Frank Barrus) wrote:
>Or shall all old code of this sort be simply converted to use
>access methods, and should directly accessible public
>instance variables be completely avoided?

As a general rule, directly addressable public data is to be avoided,
for a variety of reasons.

>If that's the case, then I'd like to stick with some sort of
>standard naming convention...  but I've seen all kinds of different
>variations...

Let me put in my two cents worth:

A verb in a member function name should indicate that the function is
not const, and vice versa.  It is, after all, useful to know which
you're working with at any given time.  Thus for property foo, which
may or may not be an explicit member of class Bar, we have:

class Bar
{
 public:
  int foo() const;
  void setFoo(int);
   or
  void set_foo(int)
 private:
  int myFoo;
};

I like the "my" prefix for non-static member variables, as you can
see.

Note that underscores preceding a name are often reserved by the
system.  While underscore followed by a lowercase letter is not
reserved, it is probably better to avoid using it anyway.

Andrew Bell
abell@mindspring.com

---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 1996/04/16
Raw View
The following article showed up as originated by me, but it
was actually from someone else.

>I'm not sure if this has been previously discuessed, but so
>far I've seen no mention of it, so...

>Has there been any consideration of adding to the standard
>a way of overloading access to instance variables, so that
>code that directly accesses a variable can be made to call
>an access function if the class is modified to need it?

>...
--
Steve Clamage, stephen.clamage@eng.sun.com
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]