Dear all,
while porting from CodeWarrior Object Pascal to GPC I noticed the following differences which might be worthwhile to address in GPC.
1) Mutual recursive object type declaration program prog1; { compile with gpc --mac-pascal prog1.pas } type t1 = object function f: t2; { error: unknown identifier `t2' } { above works in CodeWarrior Object Pascal as objects are always references } end;
t2 = object function g: t1; end;
function t1.f: t2; begin f := nil; end; function t2.g: t1; begin g := nil; end; begin end.
As a workaround this can be solved by introducing a common super class and subsequent casting.
2) Procedure type assignment compatibility with specialized parameters program prog2; { compile with gpc --mac-pascal prog2.pas } type baseType = object end;
derivedType = object(baseType) end;
procedure p1(x: baseType); begin end; procedure p2(x: derivedType); begin end; var pv: procedure(x: baseType); begin pv := p1; pv := p2; { error: incompatible types in assignment } end.
A workaround is to declare the x in p2 as baseType and perform a cast in the body of p2.
3) Cast in with statement program prog3; { compile with gpc --mac-pascal prog3.pas } type baseType = object end;
derivedType = object(baseType) procedure f; end;
procedure derivedType.f; begin end;
var a: baseType; b: derivedType;
begin new(b); a := b; derivedType(a).f; { ok } with derivedType(a) do { warning: `with' element is not a constant or an lvalue } f; { error: invalid lvalue in method call } { error: function call used as a statement } end.
A workaround is to use a temporary variable for the with statement.
Peter Schorn wrote:
- Procedure type assignment compatibility with specialized parameters
program prog2; { compile with gpc --mac-pascal prog2.pas } type baseType = object end;
derivedType = object(baseType) end;
procedure p1(x: baseType); begin end; procedure p2(x: derivedType); begin end; var pv: procedure(x: baseType); begin pv := p1; pv := p2; { error: incompatible types in assignment } end.
A similar problem occurs when using procedural parameters with untyped parameters:
program testsort1;
procedure qsort( const var data; membercount, membersize: sizetype; function comparator( const var e, f): cinteger); external name 'qsort';
type elementtype = integer;
function compare( const var i, j : elementtype): cinteger; begin if i = j then compare:= 0 else if i < j then compare:= -1 else compare:= +1 end;
const k = 10; var a: array[ 1..k] of elementtype value ( 4, 9, 6, 1 ,3, 4, 4, 6, 8, 7); n: integer; begin writeln( 'unsorted'); for n:= 1 to k do writeln( a[ n]); qsort( a, k, SizeOf( elementtype), compare); writeln( 'sorted'); for n:= 1 to k do writeln( a[ n]) end.
or the generic Pointer type:
program testsort2;
procedure qsort( pdata: pointer; membercount, membersize: sizetype; function comparator( p1, p2: pointer): cinteger); external name 'qsort';
type elementtype = integer; elementptr = ^elementtype;
function compare( p1, p2: elementptr): cinteger; begin if p1^ = p2^ then compare:= 0 else if p1^ < p2^ then compare:= -1 else compare:= +1 end;
const k = 10; var a: array[ 1..k] of elementtype value ( 4, 9, 6, 1 ,3, 4, 4, 6, 8, 7); n: integer; begin writeln( 'unsorted'); for n:= 1 to k do writeln( a[ n]); qsort( @a, k, SizeOf( elementtype), compare); writeln( 'sorted'); for n:= 1 to k do writeln( a[ n]) end.
The first program also shows another problem
program testsort1; {<- syntax error before `;'}
which may be due to a compiler problem with untyped "const var" parameters.
Regards.
Adriaan van OS
Adriaan van Os wrote:
A similar problem occurs when using procedural parameters with untyped parameters:
program testsort1;
procedure qsort( const var data; membercount, membersize: sizetype; function comparator( const var e, f): cinteger); external name 'qsort';
<snip>
The first program also shows another problem
program testsort1; {<- syntax error before `;'}
which may be due to a compiler problem with untyped "const var" parameters.
Untyped "const" parameters are always passed by reference, so "const var" in this case is useless. So the compiler rejects untyped "const var" parameters.
Peter Schorn wrote:
Dear all,
while porting from CodeWarrior Object Pascal to GPC I noticed the following differences which might be worthwhile to address in GPC.
- Mutual recursive object type declaration
As long as you aren't inheritting from another object, you can use a forward object type declaration in both GPC and CodeWarrior Pascal for mutually recursive onject type declarations.
program prog1; { compile with gpc --mac-pascal prog1.pas } type
t2 = object; forward;
t1 = object function f: t2; { error: unknown identifier `t2' }
{ above works in CodeWarrior Object Pascal as objects are always references } end;
t2 = object function g: t1; end;
function t1.f: t2; begin f := nil; end; function t2.g: t1; begin g := nil; end; begin end.
As a workaround this can be solved by introducing a common super class and subsequent casting.
With the added forward object declaration for t2, GPC compiles the example with no errors.
Gale Paeper gpaeper@empirenet.com
Peter Schorn wrote:
Dear all,
while porting from CodeWarrior Object Pascal to GPC I noticed the following differences which might be worthwhile to address in GPC.
- Mutual recursive object type declaration
program prog1; { compile with gpc --mac-pascal prog1.pas } type t1 = object function f: t2; { error: unknown identifier `t2' } { above works in CodeWarrior Object Pascal as objects are always references } end;
t2 = object function g: t1; end;
function t1.f: t2; begin f := nil; end; function t2.g: t1; begin g := nil; end; begin end.
As a workaround this can be solved by introducing a common super class and subsequent casting.
The object can be declared forward (also see the mailing list archives)
{$mac-objects} program prog1; type t2 = object; forward; t1 = object function f: t2; end; t2 = object function g: t1; end;
function t1.f: t2; begin f := nil; end; function t2.g: t1; begin g := nil; end; begin end.
Regards,
Adriaan van Os
Peter Schorn wrote:
- Cast in with statement
program prog3; { compile with gpc --mac-pascal prog3.pas } type baseType = object end;
derivedType = object(baseType) procedure f; end;
procedure derivedType.f; begin end;
var a: baseType; b: derivedType;
begin new(b); a := b; derivedType(a).f; { ok } with derivedType(a) do { warning: `with' element is not a constant or an lvalue } f; { error: invalid lvalue in method call } { error: function call used as a statement } end.
A workaround is to use a temporary variable for the with statement.
This compiles with gpc-20060325 (but not with the compiler at my website, based on gpc-20051116)
Regards,
Adriaan van Os
Peter Schorn wrote:
Dear all,
while porting from CodeWarrior Object Pascal to GPC I noticed the following differences which might be worthwhile to address in GPC.
- Procedure type assignment compatibility with specialized parameters
program prog2; { compile with gpc --mac-pascal prog2.pas } type baseType = object end;
derivedType = object(baseType) end;
procedure p1(x: baseType); begin end; procedure p2(x: derivedType); begin end; var pv: procedure(x: baseType); begin pv := p1; pv := p2; { error: incompatible types in assignment } end.
A workaround is to declare the x in p2 as baseType and perform a cast in the body of p2.
Assigning p2 to pv is unsafe (I allows breaking type rules). Consider:
program unsafe; type baseType = object end;
derivedType = object(baseType) procedure m; end;
procedure derivedType.m; begin end;
var pv: procedure(x: baseType); v: baseType;
procedure p2(x: derivedType); begin x.m end;
begin new(v); pv := p2; { error: prevents wrong call } pv(v) end .
The only place which prevents wrong call is assignment to pv. Do CodeWarrior accept the program above? Safe rule for procedural assignment like:
pv := p;
require types of arguments of pv be a supertype of arguments of p, so if pv has argument of derivedType and p has argument of baseType then the assignment is safe. ATM we require matching types, but in principle we could use weaker rule. It is not clear how usefull weaker rule is. OTOH Pascal requires matching types in some other context where weaker rules are safe (notably for array and pointer assignments), so it is not clear if it is worth the effort to implement weaker rule.
Waldek Hebisch wrote:
Peter Schorn wrote:
Dear all,
while porting from CodeWarrior Object Pascal to GPC I noticed the following differences which might be worthwhile to address in GPC.
- Procedure type assignment compatibility with specialized parameters
program prog2; { compile with gpc --mac-pascal prog2.pas } type baseType = object end;
derivedType = object(baseType) end;
procedure p1(x: baseType); begin end; procedure p2(x: derivedType); begin end; var pv: procedure(x: baseType); begin pv := p1; pv := p2; { error: incompatible types in assignment } end.
A workaround is to declare the x in p2 as baseType and perform a cast in the body of p2.
Assigning p2 to pv is unsafe (I allows breaking type rules). Consider:
program unsafe; type baseType = object end;
derivedType = object(baseType) procedure m; end;
procedure derivedType.m; begin end;
var pv: procedure(x: baseType); v: baseType;
procedure p2(x: derivedType); begin x.m end;
begin new(v); pv := p2; { error: prevents wrong call } pv(v) end .
The only place which prevents wrong call is assignment to pv. Do CodeWarrior accept the program above?
[ ... ]
Thanks - I see. CodeWarrior compiles the program above without any error message but the program crashes when executed (not surprisingly anymore).
Peter Schorn mailto:peter.schorn@acm.org