diff --git a/docs/ref.tex b/docs/ref.tex index 4f73ca711b..a3497da1ac 100644 --- a/docs/ref.tex +++ b/docs/ref.tex @@ -286,6 +286,7 @@ library on property raise +threadvar try \end{verbatim} \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. \subsection{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} -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} Type RealArray = Array [1..100] of Real; \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 possible to combine the two arrays into one multi-dimensional array. The following declaration: @@ -1068,6 +1076,162 @@ Type 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 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} \fpc supports fixed records and records with variant parts. The syntax diagram for a record type is @@ -1508,8 +1672,116 @@ calling convention. \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} \label{ch:Objects} @@ -1870,7 +2142,6 @@ of an ordinary \var{record} type. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Classes - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \chapter{Classes} \label{ch:Classes} @@ -2270,10 +2541,158 @@ AIntList[26] := 1; Only one default property per class is allowed, and descendent classes 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 - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \chapter{Expressions} \label{ch:Expressions} @@ -4853,8 +5272,8 @@ DriveSeparator = ':'; PathSeparator = ':'; FileNameCaseSensitive : Boolean = True; \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: \begin{description} \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: \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} 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 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} than the byte at the same position in \var{buf2}. \end{description} @@ -6686,7 +7105,10 @@ Procedure Readln [Var F : Text], V1 [, V2, ... , Vn]); \Description \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 -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. The variables \var{V1, V2} etc. must be of type \var{Char}, \var{Integer}, \var{Real}, \var{String} or \var{PChar}. diff --git a/docs/syntax/typearr.syn b/docs/syntax/typearr.syn index df5dcebf79..0bf7f60a8e 100644 --- a/docs/syntax/typearr.syn +++ b/docs/syntax/typearr.syn @@ -1,6 +1,10 @@ \begin{psyntax}{Array types}{arraytypes} \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} -\lit*] \lit*{of} \synt{type} +\lit*] +\end{stack} + \lit*{of} \synt{type} \end{psyntax} diff --git a/docs/syntax/typeintf.syn b/docs/syntax/typeintf.syn new file mode 100644 index 0000000000..0d9ca0705b --- /dev/null +++ b/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} diff --git a/docs/syntax/typestru.syn b/docs/syntax/typestru.syn index 6de51e2128..bc957c5951 100644 --- a/docs/syntax/typestru.syn +++ b/docs/syntax/typestru.syn @@ -6,6 +6,7 @@ \synt{object\ type} \\ \synt{class\ type} \\ \synt{class\ reference\ type}\\ +\synt{interface\ type}\\ \synt{set\ type}\\ \synt{file\ type} \end{stack}