Browse Source

+ Dynamic arrays and interfaces support (partially) documented

michael 22 years ago
parent
commit
1a9e0cc489
4 changed files with 462 additions and 12 deletions
  1. 432 10
      docs/ref.tex
  2. 6 2
      docs/syntax/typearr.syn
  3. 23 0
      docs/syntax/typeintf.syn
  4. 1 0
      docs/syntax/typestru.syn

+ 432 - 10
docs/ref.tex

@@ -286,6 +286,7 @@ library
 on
 on
 property
 property
 raise
 raise
+threadvar
 try
 try
 \end{verbatim}
 \end{verbatim}
 \end{multicols}
 \end{multicols}
@@ -1046,13 +1047,20 @@ when a type supports the \var{packed} keyword.
 In the following, each of the possible structured types is discussed.
 In the following, each of the possible structured types is discussed.
 \subsection{Arrays}
 \subsection{Arrays}
 \fpc supports arrays as in Turbo Pascal, multi-dimensional arrays
 \fpc supports arrays as in Turbo Pascal, multi-dimensional arrays
-and packed arrays are also supported:
+and packed arrays are also supported, as well as the dynamic arrays of
+Delphi:
 \input{syntax/typearr.syn}
 \input{syntax/typearr.syn}
-The following is a valid array declaration:
+\subsubsection{Static arrays}
+When the range of the array is included in the array definition, it is
+called a static array. Trying to access an element with an index that is
+outside the declared range will generate a run-time error (if range checking
+is on).  The following is an example of a valid array declaration:
 \begin{verbatim}
 \begin{verbatim}
 Type
 Type
   RealArray = Array [1..100] of Real;
   RealArray = Array [1..100] of Real;
 \end{verbatim}
 \end{verbatim}
+Valid indexes for accessing an element of the array are between 1 and 100,
+where the borders 1 and 100 are included.
 As in Turbo Pascal, if the array component type is in itself an array, it is
 As in Turbo Pascal, if the array component type is in itself an array, it is
 possible to combine the two arrays into one multi-dimensional array. The
 possible to combine the two arrays into one multi-dimensional array. The
 following declaration:
 following declaration:
@@ -1068,6 +1076,162 @@ Type
 The functions \seef{High} and \seef{Low} return the high and low bounds of
 The functions \seef{High} and \seef{Low} return the high and low bounds of
 the leftmost index type of the array. In the above case, this would be 100
 the leftmost index type of the array. In the above case, this would be 100
 and 1.
 and 1.
+
+When static array-type variables are assigned to each other, the contents of the
+whole array is copied. This is also true for multi-dimensional arrays:
+\begin{verbatim}
+program testarray1;
+
+Type
+  TA = Array[0..9,0..9] of Integer;
+  
+var   
+  A,B : TA;
+  I,J : Integer;
+begin
+  For I:=0 to 9 do
+    For J:=0 to 9 do 
+      A[I,J]:=I*J;
+  For I:=0 to 9 do
+    begin
+    For J:=0 to 9 do 
+      Write(A[I,J]:2,' ');
+    Writeln;
+    end;
+  B:=A;
+  Writeln;
+  For I:=0 to 9 do
+    For J:=0 to 9 do 
+      A[9-I,9-J]:=I*J;
+  For I:=0 to 9 do
+    begin
+    For J:=0 to 9 do 
+      Write(B[I,J]:2,' ');
+    Writeln;
+    end;
+end.  
+\end{verbatim}
+The output will be 2 identical matrices.
+
+\subsubsection{Dynamic arrays}
+As of version 1.1, \fpc also knows dynamic arrays: In that case, the array
+range is omitted, as in the following example:
+\begin{verbatim}
+Type
+  TByteArray : Array of Byte;
+\end{verbatim}
+When declaring a variable of a dynamic array type, the initial length of the
+array is zero. The actual length of the array must be set with the standard
+\var{SetLength} function, which will allocate the memory to contain the
+array elements on the heap. The following example will set the length to
+1000:
+\begin{verbatim}
+Var 
+  A : TByteArray;
+
+begin
+  SetLength(A,1000);
+\end{verbatim}
+After a call to \var{SetLength}, valid array indexes are 0 to 999: the array
+index is always zero-based.
+
+Note that the length of the array is set in elements, not in bytes of 
+allocated mmemory (although these may be the same). The amount of 
+memory allocated is the size of the array multiplied by the size of 
+1 element in the array. The memory will be disposed of at the exit of the
+current procedure or function. 
+
+It is also possible to resize the array: in that case, as much of the 
+elements in the array as will fit in the new size, will be kept. The array
+can be resized to zero, which effectively resets the variable.
+
+At all times, trying to access an element of the array that is not in the
+current length of the array will generate a run-time error.
+
+Assignment of one dynamic array-type variable to another will let both
+variables point to the same array. Contrary to ansistrings, an 
+assignment to an element of one array will be reflected in the 
+other:
+\begin{verbatim}
+Var
+  A,B : TByteArray;
+
+begin
+  SetLength(A,10);
+  A[1]:=33;
+  B:=A;
+  A[1]:=31;
+\end{verbatim}
+After the second assignment, the first element in B will also contain 31.
+
+It can also be seen from the output of the following example:
+\begin{verbatim}
+program testarray1;
+
+Type
+  TA = Array of array of Integer;
+  
+var   
+  A,B : TA;
+  I,J : Integer;
+begin
+  Setlength(A,10,10);
+  For I:=0 to 9 do
+    For J:=0 to 9 do 
+      A[I,J]:=I*J;
+  For I:=0 to 9 do
+    begin
+    For J:=0 to 9 do 
+      Write(A[I,J]:2,' ');
+    Writeln;
+    end;
+  B:=A;
+  Writeln;
+  For I:=0 to 9 do
+    For J:=0 to 9 do 
+      A[9-I,9-J]:=I*J;
+  For I:=0 to 9 do
+    begin
+    For J:=0 to 9 do 
+      Write(B[I,J]:2,' ');
+    Writeln;
+    end;
+end.  
+\end{verbatim}
+The output will be a matrix of numbers, and then the same matrix, mirrorred.
+
+Dynamic arrays are reference counted: if in one of the previous examples A
+goes out of scope and B does not, then the array is not yet disposed of: the
+reference count of A (and B) is decreased with 1. As soon as the reference
+count reaches zero, the memory is disposed of.
+
+It is also possible to copy and/or resize the array with the standard 
+\var{Copy} function, which acts as the copy function for strings:
+\begin{verbatim}
+program testarray3;
+
+Type
+  TA = array of Integer;
+  
+var   
+  A,B : TA;
+  I,J : Integer;
+begin
+  Setlength(A,10);
+  For I:=0 to 9 do
+      A[I]:=I;
+  B:=Copy(A,3,9);    
+  For I:=0 to 5 do
+    Writeln(B[I]);
+end.  
+\end{verbatim}
+The \var{Copy} function will copy 9 elements of the array to a new array.
+Starting at the element at index 3 (i.e. the fourth element) of the array.
+
+The \var{Low} function on a dynamic array will always return 0, and the
+High function will return the value \var{Length-1}, i.e., the value of the
+highest allowed array index. The \var{Length} function will return the
+number of elements in the array.
 \subsection{Record types}
 \subsection{Record types}
 \fpc supports fixed records and records with variant parts.
 \fpc supports fixed records and records with variant parts.
 The syntax diagram for a record type is
 The syntax diagram for a record type is
@@ -1508,8 +1672,116 @@ calling convention.
 \end{remark}
 \end{remark}
 
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Objects
+% Variant types
+\section{Variant types}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Definition
+\subsection{Definition}
+As of version 1.1, FPC has support for variants. For variant support to be
+enabled, the \file{variants} unit must be included in every unit that uses
+variants in some way. Furthermore, the compiler must be in \var{Delphi} or
+\var{ObjFPC} mode.
+
+The type of a value stored in a variant is only determined at runtime: 
+it depends what has been assigned to the to the variant. Almost any type 
+can be assigned to variants: ordinal types, string types, int64 types.
+Structured types such as sets, records, arrays, files, objects and classes 
+are not assign-compatible with a variant, as well as pointers. Interfaces
+and COM or CORBA objects can be assigned to a variant.
+
+This means that the following assignments are valid:
+\begin{verbatim}
+Type
+  TMyEnum = (One,Two,Three);
+
+Var
+  V : Variant;
+  I : Integer;
+  B : Byte;
+  W : Word;
+  Q : Int64;
+  E : Extended;
+  D : Double;
+  En : TMyEnum;
+  AS : AnsiString;
+  WS : WideString;
+
+begin
+  V:=I;
+  V:=B;
+  V:=W;
+  V:=Q;
+  V:=E;
+  V:=En;
+  V:=D:
+  V:=AS;
+  V:=WS;
+end;
+\end{verbatim}
+And of course vice-versa as well.
+\begin{remark}
+The enumerated type assignment is broken in the early 1.1 development series of the
+compiler. It is expected that this is fixed soon.
+\end{remark}
+
+A variant can hold an an array of values: All elements in the array have the
+same type (but can be of type 'variant'). For a variant that contains an
+array, the variant can be indexed:
+\begin{verbatim}
+Program testv;
+
+uses variants;
+
+Var
+  A : Variant;
+  I : integer;
 
 
+begin
+  A:=VarArrayCreate([1,10],varInteger);
+  For I:=1 to 10 do
+    A[I]:=I;
+end.
+\end{verbatim}
+(for the explanation of \var{VarArrayCreate}, see \unitsref.)
+
+Note that when the array contains a string, this is not considered an 'array
+of characters', and so the variant cannot be indexed to retrieve a character
+at a certain position in the string.
+
+\begin{remark}
+The array functionality is broken in the early 1.1 development series of the
+compiler. It is expected that this is fixed soon.
+\end{remark}
+
+\subsection{Variants in assignments and expressions}
+As can be seen from the definition above, most simple types can be assigned
+to a variant. Likewise, a variant can be assigned to a simple type: If
+possible, the value of the variant will be converted to the type that is
+being assigned to. This may fail: Assigning a variant containing a string 
+to an integer will fail unless the string represents a valid integer. In the
+following example, the first assignment will work, the second will fail:
+\begin{verbatim}
+program testv3;
+
+uses Variants;
+
+Var
+  V : Variant;
+  I : Integer;
+
+begin
+  V:='100';
+  I:=V;
+  Writeln('I : ',I);
+  V:='Something else';
+  I:=V;
+  Writeln('I : ',I);
+end.
+\end{verbatim}
+The first assignment will work
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Objects
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \chapter{Objects}
 \chapter{Objects}
 \label{ch:Objects}
 \label{ch:Objects}
@@ -1870,7 +2142,6 @@ of an ordinary \var{record} type.
 
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 % Classes
 % Classes
-
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \chapter{Classes}
 \chapter{Classes}
 \label{ch:Classes}
 \label{ch:Classes}
@@ -2270,10 +2541,158 @@ AIntList[26] := 1;
 Only one default property per class is allowed, and descendent classes
 Only one default property per class is allowed, and descendent classes
 cannot redeclare the default property.
 cannot redeclare the default property.
 
 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Interfaces
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\chapter{Interfaces}
+\label{ch:Interfaces}
+\section{Definition}
+As of version 1.1, FPC supports interfaces. Interfaces are an 
+alternative to multiple inheritance (where a class can have multiple
+parent classes) as implemented for instance in C++.  An interface is
+basically a named set of methods and properties: A class that 
+{\em implements} the interface provides {\em all} the methods as 
+they are enumerated in the Interface definition. It is not possible for a
+class to implement only part of the interface: it is all or nothing.
+
+Interfaces can also be ordered in a hierarchy, exactly as classes:
+An interface definition that inherits from another interface definition
+contains all the methods from the parent interface, as well as the methods
+explicitly named in the interface definition. A class implementing an
+interface must then implement all members of the interface as well as the
+methods of the parent interface(s).
+
+An interface can be uniquely identified by a GUID (GUID is an acronym for
+Globally Unique Identifier, a 128-bit integer guaranteed always to be 
+unique\footnote{In theory, of course.}. Especially on Windows systems, the
+GUID of an interface can and most be used when using COM.
+
+The definition of an Interface has the following form:
+\input{syntax/typeintf.syn}
+Along with this definition the following must be noted:
+\begin{itemize}
+\item Interfaces can only be used in \var{DELPHI} mode or in \var{OBJFPC}
+mode.
+\item There are no visibility specifiers. All members are public (indeed,
+it would make little sense to make them private or protected).
+\item The properties declared in an interface can only have methods as read and
+write specifiers.
+\item There are no constructors or destructors. Instances of interfaces
+cannot be created directly: instead, an instance of a class implementing 
+the interface must be created.
+\item Only calling convention modifiers may be present in the definition of
+a method. Modifiers as \var{virtual}, \var{abstract} or \var{dynamic}, and
+hence also \var{override} cannot be present in the definition of a interface
+definition.
+\end{itemize}
+
+\section{Identification: A GUID}
+An interface can be identified by a GUID. This is a 128-bit number, which is
+represented in a text representation (a string literal):
+\begin{verbatim}
+['{HHHHHHHH-HHHH-HHHH-HHHH-HHHHHHHHHHHH}']
+\end{verbatim}
+Each \var{H} character represents a hexadecimal number (0-9,A-F). The format
+contains 8-4-4-4-12 numbers. A GUID can also be represented by the following
+record, defined in the \file{objpas} unit (included automatically when in
+\var{DELPHI} or \var{OBJFPC} mode:
+\begin{verbatim}
+PGuid = ^TGuid;
+TGuid = packed record
+   case integer of
+      1 : (
+           Data1 : DWord;
+           Data2 : word;
+           Data3 : word;
+           Data4 : array[0..7] of byte;
+          );
+      2 : (
+           D1 : DWord;
+           D2 : word;
+           D3 : word;
+           D4 : array[0..7] of byte;
+          );
+end;
+\end{verbatim}
+A constant of type TGUID can be specified using a string literal:
+\begin{verbatim}
+{$mode objfpc}
+program testuid;
+
+Const
+  MyGUID : TGUID = '{10101010-1010-0101-1001-110110110110}';
+
+begin
+end.
+\end{verbatim}
+
+\section{Interfaces and COM}
+When using interfaces on Windows which should be available to the COM
+subsystem, the calling convention should be \var{stdcall} - this is not the
+default \fpc calling convention, so it should be specified explicitly.
+
+COM does not know properties. It only knows methods. So when specifying
+property definitions as part of an interface definition, be aware that the
+properties will only be known in the \fpc compiled program: other Windows
+programs will not be aware of the property definitions. For this reason,
+property definitions must always have interface methods as the read/write
+specifiers.
+
+\section*{Interface implementations}
+When a class implements an interface, it should implement all methods of the
+interface. If a method of an interface is not implemented, then the compiler
+will give an error. For example:
+\begin{verbatim}
+Type
+  IMyInterface = Interface
+    Function MyFunc : Integer;
+    Function MySecondFunc : Integer;
+  end;
+
+  TMyClass = Class(TInterfacedObject,IMyInterface)
+    Function MyFunc : Integer;
+    Function MyOtherFunc : Integer;
+  end;
+
+Function TMyClass.MyFunc : Integer;
+
+begin
+  Result:=23;
+end;
+
+Function TMyClass.MyOtherFunc : Integer;
+
+begin
+  Result:=24;
+end;
+\end{verbatim}
+will result in a compiler error:
+\begin{verbatim}
+Error: No matching implementation for interface method
+"IMyInterface.MySecondFunc:LongInt" found
+\end{verbatim}
+
+At the moment of writing, the compiler does not yet support providing
+aliases for an interface as in Delphi. i.e. the following will not yet 
+compile:
+\begin{verbatim}
+ype
+  IMyInterface = Interface
+    Function MyFunc : Integer;
+  end;
+
+  TMyClass = Class(TInterfacedObject,IMyInterface)
+    Function MyOtherFunction : Integer;
+    // The following fails in FPC.
+    Function IMyInterface.MyFunc = MyOtherFunction;
+  end;
+\end{verbatim}
+This declaration should tell the compiler that the \var{MyFunc} method of
+the \var{IMyInterface} interface is implemented in the \var{MyOtherFunction}
+method of the \var{TMyClass} class.
 
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 % Expressions
 % Expressions
-
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \chapter{Expressions}
 \chapter{Expressions}
 \label{ch:Expressions}
 \label{ch:Expressions}
@@ -4853,8 +5272,8 @@ DriveSeparator = ':';
 PathSeparator = ':';
 PathSeparator = ':';
 FileNameCaseSensitive : Boolean = True;
 FileNameCaseSensitive : Boolean = True;
 \end{verbatim}
 \end{verbatim}
-(the shown values are for \unix platforms, but will be different on other
-platforms)
+The shown values are for \unix platforms, but will be different on other
+platforms.
 The meaning of the constants is the following:
 The meaning of the constants is the following:
 \begin{description}
 \begin{description}
 \item[LineEnding] End of line marker. This constant is used when writing end
 \item[LineEnding] End of line marker. This constant is used when writing end
@@ -5371,12 +5790,12 @@ byte-per-byte basis for a total of \var{len} bytes.
 
 
 The function returns one of the following values:
 The function returns one of the following values:
 \begin{description}
 \begin{description}
-\item[-1] if \var{buf1} and \var{buf2} contain different bytes
+\item[less than 0] if \var{buf1} and \var{buf2} contain different bytes
 in the first \var{len} bytes, and the first such byte is smaller in \var{buf1}
 in the first \var{len} bytes, and the first such byte is smaller in \var{buf1}
 than the byte at the same position in \var{buf2}.
 than the byte at the same position in \var{buf2}.
 \item[0]  if the first \var{len} bytes in \var{buf1} and \var{buf2} are
 \item[0]  if the first \var{len} bytes in \var{buf1} and \var{buf2} are
 equal.
 equal.
-\item [1] if \var{buf1} and \var{buf2} contain different bytes
+\item [greater than 0] if \var{buf1} and \var{buf2} contain different bytes
 in the first \var{len} bytes, and the first such byte is larger in \var{buf1}
 in the first \var{len} bytes, and the first such byte is larger in \var{buf1}
 than the byte at the same position in \var{buf2}.
 than the byte at the same position in \var{buf2}.
 \end{description}
 \end{description}
@@ -6686,7 +7105,10 @@ Procedure Readln [Var F : Text], V1 [, V2, ... , Vn]);
 \Description
 \Description
 \var{Read} reads one or more values from a file \var{F}, and stores the
 \var{Read} reads one or more values from a file \var{F}, and stores the
 result in \var{V1}, \var{V2}, etc. After that it goes to the next line in
 result in \var{V1}, \var{V2}, etc. After that it goes to the next line in
-the file (defined by the \var{LineFeed (\#10)} character).
+the file. The end of the line is marked by the \var{LineEnding}
+character sequence (which is platform dependent). The end-of-line marker is
+not considered part of the line and is ignored.
+
 If no file \var{F} is specified, then standard input is read.
 If no file \var{F} is specified, then standard input is read.
 The variables \var{V1, V2} etc. must be of type \var{Char}, \var{Integer},
 The variables \var{V1, V2} etc. must be of type \var{Char}, \var{Integer},
 \var{Real}, \var{String} or \var{PChar}.
 \var{Real}, \var{String} or \var{PChar}.

+ 6 - 2
docs/syntax/typearr.syn

@@ -1,6 +1,10 @@
 \begin{psyntax}{Array types}{arraytypes}
 \begin{psyntax}{Array types}{arraytypes}
 \synt{array\ type}
 \synt{array\ type}
-\begin{stack}\\ \lit*{packed} \end{stack} \lit*{array}\lit*[ 
+\begin{stack}\\ \lit*{packed} \end{stack} \lit*{array}
+\begin{stack}\\
+\lit*[ 
 \begin{rep}[b] \synt{ordinal\ type} \\ \lit*, \end{rep} 
 \begin{rep}[b] \synt{ordinal\ type} \\ \lit*, \end{rep} 
-\lit*] \lit*{of} \synt{type}
+\lit*]
+\end{stack}
+ \lit*{of} \synt{type}
 \end{psyntax}
 \end{psyntax}

+ 23 - 0
docs/syntax/typeintf.syn

@@ -0,0 +1,23 @@
+\begin{diagram}{Interface type}{interfacetype}
+\begin{mysyntdiag}
+\lit*{Interface} 
+\begin{stack}\\ heritage \end{stack}
+\begin{stack}\\ \lit*{['} GUID \lit*{']} \end{stack}
+\begin{stack}\\ 
+\synt{component\ list} 
+\end{stack}
+\lit*{end} 
+\end{mysyntdiag}
+\begin{mysyntdiag}
+\synt{heritage} \lit*( \synt{interface\ type\ identifier} \lit* )
+\end{mysyntdiag}
+\begin{mysyntdiag}
+\synt{component\ list} 
+  \begin{rep}[b] 
+    \begin{stack} 
+      \synt{method\ definition} \\
+      \synt{property\ definition}
+    \end{stack} \\ 
+  \end{rep} 
+\end{mysyntdiag}
+\end{diagram}

+ 1 - 0
docs/syntax/typestru.syn

@@ -6,6 +6,7 @@
 \synt{object\ type} \\
 \synt{object\ type} \\
 \synt{class\ type} \\
 \synt{class\ type} \\
 \synt{class\ reference\ type}\\
 \synt{class\ reference\ type}\\
+\synt{interface\ type}\\
 \synt{set\ type}\\
 \synt{set\ type}\\
 \synt{file\ type}
 \synt{file\ type}
 \end{stack}
 \end{stack}