Functions and Subroutines (Procedures)

 <  Day Day Up  >  

In both FoxPro and Visual Basic .NET, code is divided into modules called functions and procedures (subroutines in Visual Basic .NET). These can be modules, or they can be methods in classes. You use Name () to call a function or procedure, and obj.Name() to call a method of a class.

When you define a class, whether in a PRG or in a VCX, you can add methods, which either return a value or don't. (In Visual FoxPro there is no distinction between function methods and procedure methods.)

When you add a method to either a Visual Class Library (VCX) or a class in a PRG, you designate it as Public , Protected , or Hidden . This determines the method's visibility when instantiated . If you define the class and its methods in a PRG, that is, a procedure library, you precede method names with PROTECTED or HIDDEN (the unstated default is PUBLIC ):

  • PUBLIC methods can be called when you instantiate an object based on the class.

  • PROTECTED methods can be seen by other developers in the Class Browser and in the Properties sheet, but can't be invoked except by members of the class itself. You can even select them via IntelliSense, but any attempted call produces an error.

  • HIDDEN methods can't be seen or invoked except by members of the class itself.

When you create an object from a class definition stored in a VCX or PRG using CREATEOBJECT() or NEWOBJECT() , all of the base class properties and methods are exposed. There may be dozens of them. However, if you use a PRG that starts with the statement

 

 DEFINE CLASS <name> AS CUSTOM OLEPUBLIC 

and ends with ENDDEFINE and compile it as a single-threaded DLL (STDLL) or a multithreaded DLL (MTDLL), then when you instantiate an object from the resulting DLL, IntelliSense will only show you the PUBLIC properties and methods. It only takes two additional lines of code, and provides a cleaner way for others to use your class's methods.

Function Declarations

But even the many variations on declaring variables discussed in the preceding section don't cause as much confusion as subroutine and function declarations. For one thing, functions and subroutines in FoxPro have always been a bit amorphous; either one can return or not return a value.

Visual Basic .NET is very particular about this. Functions must return a value, and it must be of the type specified in the RETURN statement. To make matters worse , someone in Redmond (and I think I know who it was) once decided that assigning the function's value to its name was a good way to hide the RETURN statement, or save a line of code, or who knows what. So you see code like this:

 

 FUNCTION DollarsToCharacters (inputval as double) AS String DollarsToCharacters = CSTR(inputval,10,2) END FUNCTION 

Functions and Procedures in FoxPro

You can define functions and classes either in a PROCEDURE library or a program. Procedure libraries are simply collections of FUNCTION and PROCEDURE blocks stored inline in a text file ending with the extension .prg . They are opened for use as procedure libraries using the statement

 

 SET PROCEDURE TO <  filename  > ADDITIVE 

Typically this is done early in the MAIN program, after which the contained functions and procedures can be referred to as if they were FoxPro functions, that is, with no object name preceding them.

Functions are declared with the FUNCTION < name > ... ENDFUNC and PROCEDURE < name >... ENDPROC blocks. Methods in visual class libraries (VCX files) are not characterized as either functions or procedures, because fundamentally, FoxPro doesn't care whether you return a value or not.

FoxPro traditionally uses the PARAMETERS statement to collect passed values. More recent versions of FoxPro permit the use of the Visual Basic syntax. So you can now write either

 

 FUNCTION DollarsToCharacters PARAMETERS InputVal RETURN STR(InputVal,10,2) ENDFUNC 

or

 

 FUNCTION DollarsToCharacters ( InputVal as Numeric ) AS String RETURN STR(InputVal,10,2) ENDFUNC 

In FoxPro, that's about all you have to know.

Functions and Subroutines in Visual Basic .NET

Brace yourself for the Visual Basic .NET equivalent. First, I'll show you the formal definitions. (Note that the only difference between functions and subroutines is the As type clause in the function declaration, which indicates what data type will be returned.)

The following is the SUB declaration in Visual Basic .NET:

 

 [ <  attrlist  > ] [{  Overloads   Overrides   Overridable   NotOverridable   MustOverride   Shadows   Shared  }]  [{  Public   Protected   Friend   Protected Friend   Private  }]  Sub  name  [(  arglist  )] [  Implements   interface.definedname  ]    [  statements  ]    [ Exit Sub ]    [  statements  ]  End Sub  

The following is the FUNCTION declaration in Visual Basic .NET:

 

 [ <  attrlist  > ] [{  Overloads   Overrides   Overridable   NotOverridable   MustOverride   Shadows   Shared  }]  [{  Public   Protected   Friend   Protected Friend   Private  }]  Function  name  [(  arglist  )] [ As  type  ] [  Implements   interface.definedname  ]    [  statements  ]    [ Exit Function ]    [  statements  ]  End Function  

The first group of options in a function or subroutine declaration determine how the routine relates to any identically named function in the base class. An explanation of each of these options follows . However, you probably don't need any of this. I'll explain at the end of this section:

  • Overloads ” This and several other functions with the same but different parameter lists (called signatures in .NET) will be defined in the class or module, and all of them will do the same thing using different parameters. This is good if you're building a compiler, but is not important for database applications.

  • Overrides ” This function procedure overrides an identically named procedure in a base class. The number and data types of the arguments, and the data type of the return value, must exactly match those of the base class procedure.

  • Overridable ” This function procedure can be overridden by an identically named procedure in a derived class. This is the default setting for a procedure that itself overrides a base class procedure.

  • NotOverridable ” This function procedure cannot be overridden in a derived class. This is the default setting for a procedure that does not itself override a base class procedure.

  • MustOverride ” This function procedure is not implemented in this class, and must be implemented in a derived class for that class to be creatable. Use this as a reminder to another member of the programming team to build his own function.

  • Shadows ” Like Overrides , except that parameters don't have to match. This means "Ignore the method of the same name in the base class and use this one instead."

  • Shared ” This can be called either directly from the class (without instantiating an object from the class) or by instantiating an object based on the class.

The second qualifier determine visibility , that is, where the function or procedure can be seen.

  • Public ” No restrictions on the accessibility of public procedures.

  • Protected ” Accessible only from within their own class or from a derived class. Can be specified only on members of classes.

  • Friend ” Accessible from anywhere in the same program.

  • Protected Friend ” Union of protected and friend access. Can be specified only on members of classes.

  • Private ” Accessible only from within their declaration context.

Constructors: Init vs. New

In FoxPro, you can include a PARAMETERS or LPARAMETERS statement as the first line of code in a class's Init procedure, then pass parameters to it in the CreateObject() or NewObject() function call that instantiates an object based on the class. Init is called the class constructor.

In .NET, the New() function is the constructor, and it can also be used to pass parameters while creating an instance of a class. However, it's common in the .NET Namespaces to have several overloads of the New method, so that you can instantiate an object and pass it several types of parameters. The only difference between different overloads is their parameter lists; for example, when creating a DataAdapter object, you can either pass it a SQL select statement and a connection string, like this:

 

 Dim da as New SQLDataAdapter("SELECT * FROM Customers", "server=(local);database=NorthWind graphics/ccc.gif , PWD=sa;") 

or a SQL select statement and an object reference to an open connection, like this:

 

 Dim cn as New SQLConnection("server=(local);database=NorthWind, PWD=sa;") Cn.Open() Dim da as New SQLDataAdapter("SELECT * FROM Customers", cn) 

So even if you don't ever overload any of your own methods, you'll use overloaded .NET methods every day. When you do so, you'll need to add the statement

 

 MyBase.New() 

as the first line of your overloaded method, to call the object's original constructor.

Implementing Interfaces

Finally, you can declare a function signature (a collection of properties and methods) known as an interface , and then include an Implements clause in your function or subroutine declaration that checks to see that you did it right. It's a sort of project control feature.

Implement s ” Indicates that this function procedure implements a function procedure defined by an interface.

If you're asked to add a specific functionality to your class that's been implemented elsewhere, you can build a list of the properties and methods you want to expose and include them in an Interface declaration. You can then include the statement Implements ( interface name ) in another class, and the compiler will report an error if the class doesn't reference all of the properties and methods in the interface.

For example, define a class called Class1 as shown in Listing 1.1.

Listing 1.1. Declaring an Interface
 Public Class Class1     Public Interface Foo         Property Banana() As String         Sub One(ByVal a As String)         Function Two(ByVal b As String) As String     End Interface End Class 

Now, open another class named Class2 , and on line 2, type Implements Class1.Foo . (The "Foo" will appear thanks to IntelliSense when you press the period key.) Prototyped declarations for the property, the subroutine, and the function will automatically be inserted into your code (see Listing 1.2).

Listing 1.2. Implementing an Interface in a Class
 Public Class Class2     Implements Class1.Foo     Public Property Banana() As String Implements Class1.Foo.Banana         Get         End Get         Set(ByVal Value As String)         End Set     End Property     Public Sub One(ByVal a As String) Implements Class1.Foo.One     End Sub     Public Function Two(ByVal b As String) As String Implements Class1.Foo.Two     End Function End Class 

It's pretty hard to screw this up if you use these declarations. And as an added bonus, if the Interface definition in Class1 is changed, its implementation in Class2 produces a compiler error. On the other hand, you have to be pretty sure what you want Class1 to do before you define the Foo interface.

Defining interfaces and then using the Implements keyword to check your math is not a bad idea. You can do it in FoxPro as well (when working with Component Object Model [COM] objects), although I've never had occasion to do so. It's helpful, but it's not necessary. So unless someone tells you to use them, ignore Interface declarations and Implements clauses. In a team environment, they become more useful.

Summary of Visual Basic Declarations

The following summary of function scope declarations describes the available options. After I describe them, I'll suggest a simple approach.

  • Public and Friend can refer to any of the following elements: Class , Const , Declare , Delegate , Dim , Enum , Event , Function , Interface , Module , Property , Structure , or Sub ; Protected and Private can be used with all of these except Module , which can only be Public or Friend (the default).

  • Static means that the variable continues to exist after the routine in which it was created is over. In that sense it's like FoxPro's PUBLIC declaration. Note that you can't specify Static with either Shared or Shadows .

  • Shared means that you can refer to the property without instantiating an object based on the class. It allows you to use the class itself as an object based on the class. We don't have that in FoxPro.

  • Shadows means that a variable completely replaces the identically named element in a base class. This is the default in FoxPro: If you write code in the method code window of a derived form class, it completely replaces the code that was written in the base form class. FoxPro doesn't check whether the signatures match or not. Ever.

So What Should I Use?

It's very, very simple. In FoxPro, put the initial assignment of variables in MAIN to default them to PUBLIC scope, and then declare variables as PRIVATE in all called routines that themselves might call other routines that might need the private values ”for example, a screen that set up titles for a report. Use LOCAL for all variables that are definitely used only in a single routine (for example, loop counters). You can completely ignore method scope and make them all PUBLIC , the default. And remember that in general, variables that are used only by methods of a class should be public properties of that class, not PUBLIC variables in MAIN.

In Visual Basic, you can do the same thing. The greater variety of declarations in Visual Basic .NET implies that it's desirable to take advantage of every one of the options. However, as database developers, we don't need most of them.

Make all methods of your classes Shared Public , and ignore all of the nuances . Don't use Overrides and Overloads . And if you find yourself using Shadows a lot, consider redesigning your base class or writing two different classes.

A footnote on overloaded methods in .NET

The fact that you don't need to create multiple overloads of subs and functions doesn't mean, however, that you won't see them every day of your programming life. A great many of the .NET classes have overloaded methods. Let's say you want to create a connection to SQL Server. If you do this

Dim cn As SQLClient.SQLConnection(

when you press the left parenthesis, nothing happens. However, if you type this:

Dim cn As New SQLClient.SQLConnection(

you will be presented with a little tooltip box that informs you that you're about to use overload 2 (of 2 available overloads), which accepts a connection string. Multiple overloads of New() methods for .NET classes are ubiquitous, and rather helpful. I still don't think you need to overload your own methods, but you'll use overloaded methods every day.

 <  Day Day Up  >  


Visual Fox Pro to Visual Basic.NET
Visual FoxPro to Visual Basic .NET
ISBN: 0672326493
EAN: 2147483647
Year: 2004
Pages: 130
Authors: Les Pinter

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net