Language Extensions

The VFPCompiler for .NET can compile and run your VFP programs unchanged, and that is a good start!. The main issue you'll find when compiling your VFP code is related to not yet implemented command and functions. We are working very hard on completing the VFP.Runtime so be sure to check every week if the command / function you are waiting for is already implemented.

The .NET framework also exposes constructs foreign to the VFP programmer like namespaces, structs, enums, events, delegates, method overloading and more. In order for VFPCompiler to have support for this new functionality some extensions had to be made.

Types

While in VFP your only contact with types are through classes in the .NET Framework. There are Enums, Interfaces, Structs and of course Classes.

VFPCompiler lets you define these types using a syntax familiar to you through extension to the DEFINE CLASS command.

Classes

To define a class

DEFINE CLASS MyClass [AS BaseClassName]

	PROCEDURE MethodA
	LPARAMETERS aParam, bParam

ENDDEFINE

Note that the base class is optional while in VFP it is required. If you don't specify a base class it is System::Object, the base class of the .NET Framework hierarchy.

Structs

To define a Struct, which is a Value Type, a simplified form of class:

DEFINE STRUCT MyStruct

	PROCEDURE MethodA
	LPARAMETERS aParam, bParam

ENDDEFINE

An struct can't have a explicit base class.

Enums

An enum is a collection of constant values enclosed in a class as a way to improve the readability of your code.

DEFINE ENUM MyEnum  

	MyValue1  
	MyValue2  
	MyValue3 = 6
	
ENDDEFINE

This defines a enum with three constants, MyValue with a default value of 0 (except if you specify otherwise), MyValue2 (default 1) and MyValue3 with the value of 6.

To use these constants in your code you write something like

MyEnum::MyValue1 

Namespaces

A NameSpace is a way to group related types into a coherent name hierarchy. For example the System::Windows::Forms namespace groups a lot of types related to Forms and Controls. Inside a NameSpace every Type name has to be unique.

A NameSpace also helps Programmers to avoid name collision. For example in the .NET Framework there are several classes named Control, but because these classes are contained in different NameSpaces there are not name collisions.

For example, the Checkbox type contained in the System::Windows::Forms NameSpace is referenced from VFPCompiler for .NET using its FullName: System::Windows::Forms::CheckBox.

VFPCompiler for .NET exposes namespaces extensions in several ways.

To define a namespace

DEFINE NAMESPACE OuterName::MiddleName::InnerName

	<types as classes, enums, structs are specified here>
	DEFINE CLASS MyClass
	ENDDEFINE

ENDDEFINE 

From outside the namespace to reference a class contained there you could use this syntax:

OuterName::MiddleName::InnerName::MyClass

And that is a really long name. In order to avoid having to write over and over the long name when you are going to use several types from that namespace, some syntax sugar is included:

USING NAMESPACE OuterName::MiddleName::InnerName

So instead of writing as:

TLOCAL Myvar as OuterName::MiddleName::InnerName::MyClass

You write:

TLOCAL MyVar as MyClass

Delegates and events

These are like the .NET counterparts but are different from the VFP model. A delegate is basically something you could invoke using this syntax:

oSomeObject.SomeDelegate(eSomeParameter)

You can think of a delegate like an object oriented version of the FunctionPointer you may know from other languages as C.

A delegate is declared inside a class as follows:

DEFINE CLASS SomeClass

	DELEGATE SomeDelegate AS SomeType
	LPARAMETERS aParam, bParam

ENDDEFINE

Note that there is no body inside the delegate, this is because as stated a delegate is some kind of construct you invoke. It could point to other methods as long the methods have a signature compatible (parameter and return type compatible) with the delegate.

One use of the delegates is to define the signature of events. Continuing from the sample above:

DEFINE CLASS SomeClass

	DELEGATE SomeDelegate AS SomeType
	LPARAMETERS aParam, bParam
	event SomeEvent as SomeDelegate

ENDDEFINE

Strong typing

A frequently requested feature in VFP has been the ability to use strong typing as provided in other languages like Java, C, C#. Well VFPCompiler now has this as an optional feature.

Return Types

To declare a strong typed return type in a method:

PROCEDURE SomeProcedure AS <type> 

Example to declare this method as returning an integer:

PROCEDURE SomeProcedure AS Integer

Parameters

To declare Strong typed parameters:

PROCEDURE SomeProcedure
TPARAMETERS aParam [as <type1>], bParam [AS <type2>]

Example to declare a method requiring two parameters one of type string and the other of type integer:

PROCEDURE SomeProcedure
TPARAMETERS aParam AS String, bParam AS Integer

Local variables

This syntax also applies to Local variables, they are similar in concept to the VFP LOCAL in that they are only visible in the method that declares them. But once declared with a type only assignment from compatible types can happen.

TLOCAL aVar as Integer
aVar = 5 && ok
aVar = "some string" &&error because is an integer

A nice use for this optional feature is to speed your apps. You can easily reach speeds of 5-10 times (500 - 1000 percent) faster than a VFP version with dynamic typing. Don't believe us:

Run this in VFP and in a compiled app

LOCAL nValue, i

LOCAL nSeconds

nSeconds = SECONDS()

FOR m.i = 1 TO 5000000

m.nValue = m.nValue + 1

ENDFOR

? nSeconds - SECONDS()

TLOCAL nValue as long, i as long

LOCAL nSeconds

nSeconds = SECONDS()

FOR i = 1 TO 5000000

nValue = nValue +1

ENDFOR

? nSeconds - SECONDS()

This is not meant to bash VFP performance, it is a good one. But to let you know what you can achieve with the VFPCompiler which still is not optimized but already is performant..