User Changes Trunk

From Free Pascal wiki
Revision as of 17:03, 25 August 2019 by Jonas (talk | contribs) (Language Changes - Objective-C "Related Result Type")

About this page

Listed below are intentional changes made to the FPC compiler (trunk) since the next upcoming release that may break existing code. The list includes reasons why these changes have been implemented, and suggestions for how you might adapt your code if you find that previously working code has been adversely affected by these recent changes.

The list of new features that do not break existing code can be found here.

Please add revision numbers to the entries from now on. This facilitates moving merged items to the user changes of a release.

All systems

Language Changes

Objective-C "Related Result Yype"

  • Old behaviour: The type checking system always evaluated calls to Objective-C methods as them returning the declared result type.
  • New behaviour: The type checking system now takes into account the "related result type" rule from Objective-C. This means that certain methods are now assumed to always return an instance whose type is compatible with the object to which the message was sent (i.e., it's the same, or inherits from it). This is done for the following methods, provided their declared result type is also compatible with the class type in which the method is declared:
    • instance methods whose first lower case word in the message name is init or new
    • class methods whose first lower case word in the message name is autorelease, init, retain, or self
  • Reason: Compatibility with translations of more recent versions of Cocoa headers
  • Example:
{$mode objfpc}
{$modeswitch objectivec1}

  FPCMyType = objcclass
    function init: id; message 'init';
    class function alloc: FPCMyType; message 'initWithValue';
    // since boolean is not related to FPCMyType, the "related result type" rule will not apply here
    // even though the message starts with "retain" and it's a class method
    class function retainCounting: boolean; message 'retainCounting';


  a: NSArray;
  // will give an error even though FPCMyType returns 'id', because 'id' is related to
  // FPCMyType and hence the compiler will now interpret this 'init' as returning an "FPCMyType"
  // when called (note that the actual return type of "init" remains "id" in all other contexts;
  // the declaration of that method is not modified, only when calling it the result type is
  // statically assumed to be of FPCMyType)

Implementation Changes

Property field access lists no longer allows classes

  • Old behaviour: A field access list for a property is allowed to contain implicit dereferences in the form of fields of class instances.
  • New behaviour: A field access list for a property must only contain record or (TP style) object fields.
  • Reason:
    • Delphi compatibility
    • This resulted in an internal error for published properties
  • Remedy:
    • Switch the fields to records or objects
    • Use a method with inline modifier that will result in similar performance
  • svn: 40656
  • Example: The following code now fails:
unit Test;
{$mode objfpc}


  TTest1 = class
    Field: String;

  TTest2 = class
    fTest1: TTest1;
    property Prop: String read fTest1.Field; // Error "Record or object type expected"



Disabled default support for automatic conversions of regular arrays to dynamic arrays

  • Old behaviour: In FPC and ObjFPC modes, by default the compiler could automatically convert a regular array to a dynamic array.
  • New behaviour: By default, the compiler no longer automatically converts regular arrays to dynamic arrays in any syntax mode.
  • Reason: When passing a dynamic array by value, modifications to its contents by the callee are also visible on the caller side. However, if an array is implicitly converted to a dynamic array, the result is a temporary value and hence changes are lost. This issue came up when adding TStream.Read() overloads.
  • Remedy: Either change the code so it no longer assigns regular arrays to dynamic arrays, or add {$modeswitch arraytodynarray} a
  • Example: this program demonstrates the issue that appeared with the TStream.Read() overloads that were added (originally, only the the version with the untyped variable existed)
{$mode objfpc}
  tdynarray = array of byte;

procedure test(var arr); overload;

procedure test(arr: tdynarray); overload;

  regulararray: array[1..1] of byte;
  writeln(arr[0]); // writes 0, because it calls test(tdynarr)
  • svn: 42118

Range checking for enumeration constants in Delphi mode

  • Old behaviour: Out-of-range enumeration constants never caused an error in Delphi mode, because very early versions of Delphi did not either.
  • New behaviour: Out-of-range enumeration constants cause an error in Delphi mode, even if range checking is disabled. Current Delphi versions (and even older ones, such as Delphi 7) behave the same.
  • Reason: Delphi-compatibility.
  • Remedy: Fix the range errors.
  • svn: 42272, 42275

Directive clause […] no longer useable with modeswitch PrefixedAttributes

  • Old behaviour: A function/procedure/method or procedure/method variable type could be followed by a directive clause in square brackets ([…]) that contains the directives for the routine or type (e.g. calling convention).
  • New behaviour: If the modeswitch PrefixedAttributes is enabled (which is the default in modes Delphi and DelphiUnicode) the directive clause in square brackets is no longer allowed.
  • Reason: As custom attributes are bound to a type/property in a way that looks ambiguous to a directive clause and this ambiguity is not easily solved in the parser it is better to disable this feature.
  • Remedy:
    • don't set (in non-Delphi modes) or disable modeswitch PrefixedAttributes (in Delphi modes) if you don't use attributes ({$modeswitch PrefixedAttributes-})
    • rework your directive clause:
// this
procedure Test; cdecl; [public,alias:'foo']

// becomes this
procedure Test; cdecl; public; alias:'foo';
  • svn: 42402

Unit changes

System - TVariantManager

  • Old behaviour: TVariantManager.olevarfromint has a source parameter of type LongInt.
  • New behaviour: TVariantManager.olevarfromint has a source parameter of type Int64.
  • Reason for change: 64-bit values couldn't be correctly converted to an OleVariant.
  • Remedy: If you implemented your own variant manager then adjust the method signature and handle the range parameter accordingly.
  • svn: 41570

64-bit values in OleVariant

  • Old behaviour: If a 64-bit value (Int64, QWord) is assigned to an OleVariant its type is varInteger and only the lower 32-bit are available.
  • New behaviour: If a 64-bit value (Int64, QWord) is assigned to an OleVariant its type is either varInt64 or varQWord depending on the input type.
  • Reason for change: 64-bit values weren't correctly represented. This change is also Delphi compatible.
  • Remedy: Ensure that you handle 64-bit values correctly when using OleVariant.
  • svn: 41571

Classes TCollection.Move

  • Old behaviour: If a TCollection.Descendant called Move() this would invoke System.Move.
  • New behaviour: If a TCollection.Descendant called Move() this invokes TCollection.Move.
  • Reason for change: New feature in TCollection: move, for consistency with other classes.
  • Remedy: prepend the Move() call with the system unit name: System.move().
  • svn: 41795


TMSSQLConnection uses TDS protocol version 7.3 (MS SQL Server 2008)
  • Old behaviour: TMSSQLConnection used TDS protocol version 7.0 (MS SQL Server 2000).
  • New behaviour: TMSSQLConnection uses TDS protocol version 7.3 (MS SQL Server 2008).
  • Reason for change: native support for new data types introduced in MS SQL Server 2008 (like DATE, TIME, DATETIME2). FreeTDS client library version 0.95 or higher required.
  • svn: 42737

Previous release notes