Scope in Visual Foxpro - Part 2 (By Andy Kramek)

We’ll continue our review of scoping in Visual FoxPro with a look at how scope affects object properties (and methods). I find it makes things easier to think of properties as “variables that are scoped to an object”. In other words, as long as an object exists, so do its properties. As soon as the object is released, its properties (and their values) are gone too. In this sense, at least, the analogy to memory variables and their scoping (Public, Private and Local) holds up. However, despite first appearances, all properties are not created equal.

VFP is a little unusual among object oriented languages in that all of the properties, events and methods (PEMs) of its classes are created as PUBLIC by default. It is important to realize that, in the context of an object, the word ‘public’ refers to the visibility of a property (or method) to other objects. In fact, properly speaking, the set of PEMs that an object exposes to the outside world is its “Public Interface”. In many object oriented languages native properties, events and methods are not exposed in the public interface and it is up to the developer to make provision for those elements that need to be exposed. VFP takes the exact opposite approach. Unless you, the developer, specifically decide otherwise, all PEMs whether native or custom, are exposed as part of the public interface of an object and so are said to be PUBLIC in scope.

This, of course, is generally a good thing in an application development tool like Visual FoxPro. Imagine what a pain it would be if every time you wanted to refer to the property of an object like a textbox (e.g. Value, Background Color, Height, Width, Font) from some other object you had either to have specifically defined that property as “public” first or had to write the required code into a special method on the object in question. This is, however, exactly how things work in many other object oriented languages. Look at properties defined in C# (or in a COM interface) and you will find that they have two methods associated with them – a “PUT” method to assign a value, and a “GET” method to return the value. Contrast that with the ease of creating and working with properties in VFP!

However, there are times when you may not want a specific property (or method) to be visible to objects outside. Why? Either because the property is essential to the inner workings of your object and you do not want it changed except under very specific and controlled circumstances or because it is a method that should only ever be called as part of, or on completion of, some other operation. For this reason VFP implements two additional key words that can be used to define the scope of PEMs.

·         PROTECTED        Protected PEMs are only accessible to objects that are instantiated from a class that actually defines the PEM, or from a class that inherits from the class that defined it. Since Visual FoxPro does not implement multiple inheritances, we can shorten the definition to: “visible only within the originating class and its sub-classes”.

·         HIDDEN                 Hidden PEMs are only accessible to objects that are instantiated directly from the class that actually defines the PEM. In other words they are: “visible only within the originating class

You may be wondering, at this point, what happens if you try and access a PEM that is either protected or hidden. The answer is simple, you get an error. Paste the following into a PRG and run it:

oTest = CREATEOBJECT( 'xObj' )

CLEAR

?

? "The next line will cause an Error - hit ignore"

? "Access Property directly to see the value: " + oTest.cProperty

?

? "Call Get Method and see the value: " + oTest.GetProperty()

 

DEFINE CLASS xObj AS Session

  cProperty = 'This is not visible'

  PROTECTED cProperty

 

  FUNCTION GetProperty()

    RETURN This.cProperty

  ENDFUNC

ENDDEFINE

As you can see, by declaring the property protected we get an “Property does not exist” error when we try to access it directly from outside. However, when we call the GetProperty() method – which is itself public remember - there is no problem. The method is defined in the class that defines the property and so it can see the property, and return its value to the caller even though the caller cannot actually see the property. Of course the method could do much more than simply return the value. Common uses for a protected property, with an exposed Get() method, like this include handling serial (sequential values), or accumulator (running total) values. Each time the method is called, it generates the next number (or adds some value) to the property and returns the new value. The point is that the ONLY way to change the value from outside of the object is to call the method and that allows us to check that the value only gets changed when it is supposed to be changed. (Contrast this with the ThisForm.Text1.Value = “xxxxx” approach).

The example I gave above shows how a custom property can be defined as PROTECTED (or HIDDEN) when creating the class definition in code. First we declare the property name, and initialize it, then define its scope. (This must be done within the class definition, but outside of any Procedure or Function (method) definitions.

To protect, or hide, a native property which is already declared by default in the class, we only need to include it in the PROTECTED, or HIDDEN, list, like this:

DEFINE CLASS xObj AS session

  cProperty = ‘This is not visible’

  *** Now protect our custom, and a native, property

  PROTECTED cProperty, datasessionid

Methods, too, can be protected or hidden by simply including the appropriate key word as part of the declaration. The following examples define a hidden, and a protected, method in a class:

HIDDEN FUNCTION SetValue( tuInVal )

ENDFUNC

 

PROTECTED PROCEDURE AnotherSet

LPARAMETERS tuInVal

ENDPROC

It doesn’t really matter whether you define your methods as functions (although this is my personal preference since methods always return a value and so really are “functions”) or procedures. Nor does it matter if you use implicit parameter definition (again, my personal preference is to do it this way in classes defined in code because the method signature is also the calling prototype) or explicit parameter definition (either local or private).

Note: If you are working with visual classes, then you can define (and change) the scope of PEMs in the “Edit Property/Method” dialog which is accessed from the “Class” pad of the main system menu.

So, as we have seen, defining a PEM as either PROTECTED, or HIDDEN, prevents it from being accessed from outside of the object, so in that sense it doesn’t matter which you use. Similarly if an object is instantiated directly from the class that defines the PEM, then all PEMs are visible to any method in the object whether they are Public, Protected or Hidden. However, as soon as we begin to work with sub classes, the difference becomes significant.

The following code defines a class (“propobj”) with three custom properties, one Public, one Protected and one Hidden. A public “SelfTest()” method simply displays the values of each of the three properties. In addition it has two pairs of methods (a Get and a Set) related to each of the restricted properties.

*** Class that defines some properties

DEFINE CLASS propobj AS Session

  cPub = "This is a Public Property"

  cPro = "This is a Protected Property"

  cHid = "This is a Hidden Property"

 

  PROTECTED cPro

  HIDDEN cHid

 

  *** Function To test self

  FUNCTION SelfTest

    ACTIVATE SCREEN

    ? This.Name

    ? This.cPub

    ? This.cPro

    ? This.cHid

    ?

    RETURN "Completed Self-Test"

  ENDFUNC

   

  *** Get method to return the protected value

  FUNCTION GetcPro

    RETURN This.cPro

  ENDFUNC

 

  *** Set Method to update the protected value

  *** Notice that this restricts values to Character Strings

  *** Any other data type is simply ignored

  FUNCTION SetcPro( tcValue AS String )

    IF VARTYPE( tcValue ) = "C"

      This.cPro = tcValue

    ENDIF

  ENDFUNC

 

  *** Get method to return the Hidden value

  FUNCTION GetcHid

    RETURN This.cHid

  ENDFUNC

 

  *** Set Method to update the Hidden value

  FUNCTION SetcHid( tcValue AS String )

    IF VARTYPE( tcValue ) = "C"

      This.cHid = tcValue

    ENDIF

  ENDFUNC

ENDDEFINE

If you save this code and then instantiate an object based on this class, and call it’s SelfTest() method you will see the name of the object, the contents of the three properties and the return message displayed on screen:

SET PROCEDURE TO demo

oTest = CREATEOBJECT( 'propobj' )

? oTest.SelfTest()

Displays:

 

This next class defines a sub-class of propobj (named “SonOfProp”)

 

DEFINE CLASS SonOfProp AS propobj

  *** Function To test self

  FUNCTION TestSelf

    ACTIVATE SCREEN

    ? This.Name

    ? This.cPub

    ? This.cPro

    ? This.cHid

    ?

    RETURN "Completed TestSelf"

  ENDFUNC

ENDDEFINE

If we repeat the above test, substituting the SonOfProp class for PropObj, there is no apparent difference. The sub-class returns exactly the same result as the parent  (apart, of course, from the object name)

This should not be too surprising, because the code that is executing actually is that which is defined in the parent class. However, if now call the “TestSelf” method, which is only defined in the sub class (although it has exactly the same code as in the parent class) we do see an immediate difference! In fact, we get an error as soon as we try to access the hidden property (because the code that is executing is not defined in the same class that defined the property) and we are, therefore,  missing a line in the result.

If we override the SelfTest method in the sub class (i.e. just re-write the identical code in the sub-class) the result would be the same, an error! However, overriding the method in the subclass with different code, and using a DODEFAULT() works fine because, once again, the code which is to be executed is defined in the same class as the hidden property.

Notice that the GetcHid() and SetcHid() methods work just fine in the sub class. These public methods are defined in the parent class and so can read from, and write to, the  hidden property no matter where they are called from (also notice that they really prevent the property from being set to anything but a character string).

The final class in this little demonstration (“norelation”) is not related to the propobj class at all. Instead it defines its own public custom property (“oRef”) and, in its Init() method creates an instance of the “PropObj” class and assigns it to that property. It too has a self-test method that, when called, attempts to access the three properties of our original class. But now we get two errors! The only property that can be accessed directly is the one which was defined as Public:

DEFINE CLASS NoRelation AS Session

  oRef = NULL  && Public property to hold a reference to the Property Definition Object

  FUNCTION Init

    This.oRef = CREATEOBJECT( "propobj" )

  ENDFUNC

 

  *** Function To test self

  FUNCTION SelfTest

    ACTIVATE SCREEN

    ? This.Name

    ? This.oRef.cPub

    ? This.oRef.cPro

    ? This.oRef.cHid

    ?

    RETURN "Completed Self-Test"

  ENDFUNC

ENDDEFINE

The result is now missing two lines.

This is, of course, because the class on which the object is based does not inherit from PropObj and so it cannot even access properties that were defined as “Protected”, let alone anything that was actually “Hidden”. However, notice that it can still get access to these properties by calling the appropriate methods. This.oRef.GetcHid() and This.oRef.SetcHid() work just fine, as do the equivalent methods for the protected property.

All very interesting, but is it really useful?

You may, by now, be wondering this. The short answer is that it is extremely useful. I have already mentioned two reasons for protecting properties (sequences, and creating “strongly typed” properties). For methods, one of the biggest benefits I see is that it dramatically reduces the amount of code I need to write. Here’s what I mean:

How often do you include code in your methods to check that a parameter was correctly passed? If you are a defensive programmer like me, the answer is “pretty much every time – and especially when the parameter is saved and re-used elsewhere”. By protecting methods that do not need to be called externally you remove the necessity for checking parameters. After all, if the only place the method can be called from is inside your own code, then you can ensure (in any calling method) that the values to be passed are correct and accept them without checking again inside the method.

 

Commentaar van anderen:
ChristianLouboutin op 17-8-2010 om 3:02
Christian Louboutin Shoes, Christian Louboutin, Christian Louboutin Shoes, Wedding Shoes, Christian Louboutin Shoes, Christian Louboutin includes recently been produced in a selection with trends, designs, designs and also styles that will need achieved great decide of millions of most women several over the globally. Wedding Shoes, Christian Louboutin, Christian Louboutin Shoes, Wedding Shoes, Discount Christian Louboutin, Louboutin Sale A number of sizes are usually seriously outstanding and simply the rest are special variations among traditional general trends. Louboutin Shoes, Christian Louboutin Discount, Louboutin, Christian Louboutin Sale, Buy Christian Louboutin, Christian Louboutin Pumps, YSL Shoes sandals are known for their own particularly crafte heels, outstanding models and also high-priced and furthermore well highly regarded amongst girls cirlces. Christian Louboutin Sandals, Yves Saint Laurent Shoes, Christian Louboutin Boots, Manolo Blahnik Shoes, Yves Saint Laurent Boots, Miu Miu Shoes Sandals designs are glamorous and sexy, and they are worn by some of the world most beautiful women. Christian Dior Shoes, Christian Louboutin Flats, Christian, Louboutin Shoes, Christian Louboutin Sale, Discount Christian Louboutin Why is everyone infatuated with these red-soled shoes Read on to find out why, and you also find some of the best of Louboutin line. Herve Leger Bandage Dress, Herve Leger Dress, Herve Leger V Neck Dress, Herve Leger Bandage Dress, Herve Leger Dress Most people associate Louboutin shoes with sky-high, stiletto heels, the patent sandals with wedge heels prove that sexy and wearable can go hand-in-hand.
dfwe op 18-8-2010 om 3:43
The Largest Online Retailer of replica handbags replica watches knock off Louis Vuitton Louis Vuitton handbags replica Louis Vuitton Replica Eberhard & Co Replica Hublot Replica IWC Replica Omega Replica Tag Heuer U-boat Watches replica U-boat Replica handbags Swiss Watches swiss rolex best watchesand More! Shop our huge selection of Replica Patek Philippe Replica Tag Heuer U-BOAT watches Parmigiani watches rolex watches replica rolex Replica rolex swiss watches best watches replica chanel replica Hermes Hermes handbags prada handbags chanel handbags Swiss Watches replica rolex Breitling replica replica Tag Heuer at our website. We carry top brands like Replica Patek Philippe Replica Tag Heuer Replica U-BOAT best watches Swiss Omega Swiss Rolex Swiss Tag Heuer knock off Louis Vuitton Louis Vuitton handbags replica Louis Vuitton.Free shipping is provided. Shop for the latest styles of mens and womens replica handbags replica watches knock off Louis Vuitton Louis Vuitton handbags replica Louis Vuitton Gucci handbags replica Gucci replica chanel replica Hermes replica rolex replica watches rolex Daytona rolex Submariner replica Bell & Ross Breitling watches Breitling Bentley replica Bvlgari Replica Bell & Ross Replica Breitling Replica Cartier watches Replica chanel watches Replica Hublot watches on our online store,big surprises can be received.Provides wholesale Replica Tag Heuer U-BOAT watches Parmigiani watches rolex watches replica rolex Replica rolex swiss watches best watches Breitling replica replica Tag Heuer Replica Omega Replica U-BOAT Replica Patek Philippe Replica Hublot Replica IWC Replica Omega Replica Tag Heuer U-boat Watches replica U-boat Replica handbags Swiss Watches swiss rolex in a big discount price.Shop Online for the cheapest and high-quality replica handbags replica watches,we guarantee all our bags are genuine leather. Low discount price, safe payment and fast shipping, it will saves your pocket and get perfect replica handbags replica watches .All of them are paid a lot attention in manufacturing, and inspected carefully before they are taken out of the warehouse.Please feel free to choose any style you like from our site.
Geef feedback:

CAPTCHA image
Vul de bovenstaande code hieronder in
Verzend Commentaar