classdelphitypeswsdlredeclaration

DXE7: "type A = type B" and var x (of type A):= A.create leads to E2010 incompatible type compile error. Why?


A. Short summary of the problem:

type
  A = class(TObject)
  end;

  B = type A;

The compiler error E2010 incompatible types: 'B' and 'A' is shown, when you instantiate a variable of class B in the following style:

var
  TheB: B;
begin
     TheB:= B.Create;
     ..

I can avoid that problem by removing the second "type", so the declaration is the standard one:

type
  A = class(TObject)
  end;

  B = A;

But in my opinion, the error should not come, even WITH the second "type", because A is not directly used (The second "type" tells the compiler to see both classes as individuals, see http://docwiki.embarcadero.com/RADStudio/Seattle/en/Declaring_Types for details). Can someone explain, because of what reason the error ignores my opinion? (o;

B. Complete history and more complex details:

First of all: The error:

[dcc32 Fehler] gboDHL.pas(165): E2010 Inkompatible Typen: 'Origin' und 'CountryType' (which means "incompatible types" in english),

occurs in the following line of code:

AShipmentOrder.Shipment.Shipper.Address.Origin:= DHL_geschaeftskundenversand_api_2.Origin.Create;

Now here is the background:

I try to communicate with the "new" DHL Geschäftskundenversand API v2.2 which still uses SOAP to create a shipment order. DHL_geschaeftskundenversand_api_2 is the completely generated unit from the integrated delphi xe7 WSDL generator for that service. AShipmentOrder is the instance which represents the top level xml node of the request.

The class "Origin" is implemented/generated this way:

type    
  CountryType = class(TRemotable)
  private
    Fcountry: country2;
    Fcountry_Specified: boolean;
    FcountryISOCode: countryISOType;
    Fstate: state;
    Fstate_Specified: boolean;
    Fcountry_: country;
    Fcountry__Specified: boolean;
    FcountryISOCode_: countryISOType;
    Fstate_: state2;
    Fstate__Specified: boolean;
    procedure Setcountry(Index: Integer; const Acountry2: country2);
    function  country_Specified(Index: Integer): boolean;
    procedure Setstate(Index: Integer; const Astate: state);
    function  state_Specified(Index: Integer): boolean;
    procedure Setcountry_(Index: Integer; const Acountry: country);
    function  country__Specified(Index: Integer): boolean;
    procedure Setstate_(Index: Integer; const Astate2: state2);
    function  state__Specified(Index: Integer): boolean;
  published
    property country:         country2        Index (IS_OPTN) read Fcountry write Setcountry stored country_Specified;
    property countryISOCode:  countryISOType  read FcountryISOCode write FcountryISOCode;
    property state:           state           Index (IS_OPTN) read Fstate write Setstate stored state_Specified;
    property country_:        country         Index (IS_OPTN) read Fcountry_ write Setcountry_ stored country__Specified;
    property countryISOCode_: countryISOType  read FcountryISOCode_ write FcountryISOCode_;
    property state_:          state2          Index (IS_OPTN) read Fstate_ write Setstate_ stored state__Specified;
  end;

  Origin          =  type CountryType;      { "http://dhl.de/webservice/cisbase"[GblElm] }

The "property" Origin of AShipmentOrder.Shipment.Shipper.Address is implemented/generated this way:

type
 NativeAddressType = class(TRemotable)
 ...
 published
 ...
   property Origin: Origin  Index (IS_OPTN or IS_REF) read FOrigin write SetOrigin stored Origin_Specified;
 ...
 end;

If it is unclear, let me say, that ´AShipmentOrder.Shipment.Shipper.Address´ is of class NativeAddressType

I'm using Delphi XE7 on Windows 10, 64bit, compiling to 32bit.

The delphi WSDL generator has different problems, which I had to manage before, and it is really not "nice" that in the output the property names are identical to the class names, but that is not changeable, it seems. The class "Origin" is not the only class in that generated unit which is named as the property it belongs to, but the error only occurs, when such a class is implemented as

type
 A = type B

I tried to find a description of that special declaration variant, but that is quite hard, because the keywords are too often used.

On http://www.delphibasics.co.uk/RTL.asp?Name=Type I found the following explanation:

1.type Name = Existing type   Refers to an existing type, such as string by a new Name.   2.type Name = type Existing type   This has the same effect as above, but ensures that at run time, variables of this type are identified by their new type name, rather than the existing type name.

If I understand that correctly, that means that in my example the class Origin is not identified anymore as CountryType, but as Origin. That should be fine, because the property Origin is declared as to be of class Origin.

While going on to try to understand that problem, I manually renamed The class "Origin" in the generated unit to OriginType (delphi used that postfix "Type" with several other classes in that unit, not clear, why it has not used it with the Origin-Type). After that, I can exclude a name-conflict, because now the error is

[dcc32 Fehler] gboDHL.pas(165): E2010 Inkompatible Typen: 'OriginType' und 'CountryType'

There seems to be no reason because of what that error occurs.

After some hours without some ideas I found this Embarcadero WIKI entry: http://docwiki.embarcadero.com/RADStudio/Seattle/en/Declaring_Types

After reading and thinking about that, I understood, that the "type" in A = type B is not necessary in that case, because there is no need to handle class A in another way than class B, so I removed that manually in the generated unit and now, it works fine.

I also understand, that a special option in the generator was checked to prevent "name conflicts". If this option is not checked, this problem also should be solved (but maybe some others come around (o; ).

Maybe this helps someone to spent more time outside than with a problem like that (o;

But in the end, I do not understand what was the problem here, because all properties were of type "Origin" and later of "OriginType", also this type was created with Origin.Create and later with OriginType.Create. So the "CountryType" was never used, except for the class declaration of "Origin" / "OriginType". In my opinion this should not lead to that problem, but it does.

Can somebody explain that?

Thank you in advance

Kai


Solution

  • You are getting: E2010 Incompatible types: 'Tb' and 'Ta', which might seems odd:

    type
      Ta = class
      end;
      Tb = type Ta;
    var
      b: Tb;
    begin
      b := Tb.Create;  // E2010 Incompatible types: 'Tb' and 'Ta' 
    end.
    

    Ta and Tb are two distinct types.

    From Type Compatibility you can see that none of the conditions listed indicates that the two distinct types are compatible.

    Type Compatibility

    Every type is compatible with itself. Two distinct types are compatible if they satisfy at least one of the following conditions.

    • They are both real types.
    • They are both integer types.
    • One type is a subrange of the other.
    • Both types are subranges of the same type.
    • Both are set types with compatible base types.
    • Both are packed-string types with the same number of characters.
    • One is a string type and the other is a string, packed-string, or Char type.
    • One type is Variant and the other is an integer, real, string, character, or Boolean type.
    • Both are class, class-reference, or interface types, and one type is derived from the other.
    • One type is PAnsiChar or PWideChar and the other is a zero-based character array of the form array[0..n] of PAnsiChar or PWideChar.
    • One type is Pointer (an untyped pointer) and the other is any pointer type.
    • Both types are (typed) pointers to the same type and the {$T+} compiler directive is in effect.
    • Both are procedural types with the same result type, the same number of parameters, and type-identity between parameters in corresponding positions.

    The reason for the compiler error is thus: When you call Tb.Create, the compiler identifies that with Ta.Create and since b is of a distinct non-compatible type, it is not accepted.

    You can call that a flaw, but it follows strict type rules and can easily be corrected like shown below.


    Declaring Tb = class(Ta) would resolve the compiler error since Tb is derived from Ta.


    Also declaring Tb = Ta would resolve the compiler error, since they would denote the same type (not two distinct types) and thus assignment compatible.