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
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.