Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2006-04

const parameter writeable

10 messages · 5 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

L505

Are const parameters supposed to ensure read only access? If so how come one can write to a typed pointer?

program project1;
{$mode objfpc}{$H+}
  type
    PSomeRec = ^TSomeRec;
    TSomeRec = record
      a: string;
      b: string;
    end;
  procedure ChangeRec1(const Rec: PSomeRec);
  begin
    Rec^.a:= 'string A';
  end;
var
  RecPtr: PSomeRec;
begin
  new(RecPtr);
  ChangeRec1(RecPtr);
  writeln(RecPtr^.a);
  dispose(RecPtr);
  readln;
end.
Peter Vreman
to L505
Show quoted text 29 lines
Are const parameters supposed to ensure read only access? If so how come one can write to a typed pointer? program project1; {$mode objfpc}{$H+} type PSomeRec = ^TSomeRec; TSomeRec = record a: string; b: string; end; procedure ChangeRec1(const Rec: PSomeRec); begin Rec^.a:= 'string A'; end; var RecPtr: PSomeRec; begin new(RecPtr); ChangeRec1(RecPtr); writeln(RecPtr^.a); dispose(RecPtr); readln; end.

Only the pointer itself is the parameter and read-only. Where the pointer points to is irrelevant.

Michael Müller
to Peter Vreman
Peter Vreman wrote 32 lines
> > Are const parameters supposed to ensure read only access? > If so how come one can write to a typed pointer? > > program project1; > > {$mode objfpc}{$H+} > > type > PSomeRec = ^TSomeRec; > TSomeRec = record > a: string; > b: string; > end; > > procedure ChangeRec1(const Rec: PSomeRec); > begin > Rec^.a:= 'string A'; > end; > > var > RecPtr: PSomeRec; > begin > new(RecPtr); > ChangeRec1(RecPtr); > writeln(RecPtr^.a); > dispose(RecPtr); > readln; > end. Only the pointer itself is the parameter and read-only. Where the pointer points to is irrelevant.

But in this case I'm wondering why you want to give a pointer instead of the real type?

The reason for a pointer is normally in this case to avoid that the given data is copied into local variables.

From my understand the compiler handles following parameter attributes:

- 'var': call by reference => gives pointers, content writable
- 'const': gives pointer, content read-only
- '': call by value => creates a local copy of the data, content is lost after end of procedure/function
- 'out': I'm not sure if it's more similar to 'var' or ''.

This is the reason why I always declare parameters that are not 'var' with 'const'.

Are my expanations right especially related to 'const'?

Michael

Unknown author
to Michael Müller

Michael says:

- 'const': gives pointer, content read-only

In practice the compiler may[1] check for access to the value at compile time and just give you a pointer to the real thing (since it knows you won't change it). With a non-specified parameter it has to make a copy and pass that, which slows everything down. Especially for big parameters, and you shouldn't pass big structs around for that reason.

Moz
[1] I assume FPC does this, but don't know for sure.

Jonas Maebe
to Michael Müller: But in this case I'm wondering why you want to give a pointer instead of the real type?…
Michael Müller wrote
- 'const': gives pointer, content read-only

The compiler can handle const parameters in any way it wants, and it may even differ among different cpu's and calling conventions. Sometimes they are passed by value, sometimes by reference. It depends on what the compiler thinks will be most efficient, or on what a calling convention requires.

Since the content is not writable (except by using ugly tricks, in which case the programmer himself is responsible for messing up things), that does not matter.

- 'out': I'm not sure if it's more similar to 'var' or ''.

It's like var, except that in some cases the contents of the "out" parameter are erased before the function call, and that you get different warnings regarding the initialised status of an out parameter and the values that you pass to them.

Jonas

L505
to Michael Müller: But in this case I'm wondering why you want to give a pointer instead of the real type?…
> Only the pointer itself is the parameter and read-only. Where the pointer > points to is irrelevant.

I remember this from using classes where you can still access the class properties - should have thought about that before posing the question :).

But in this case I'm wondering why you want to give a pointer instead of the real type?

did you mean this ? :

   procedure ChangeRec1(const Rec: TSomeRec);
   begin
     Rec.a:= 'string A';
   end;

Because I can't pass a PSomeRec to that function, only a TSomeRec

Otherwise, I don't know what you mean..

Jonas Maebe
to L505
L505 wrote 8 lines
did you mean this ? : procedure ChangeRec1(const Rec: TSomeRec); begin Rec.a:= 'string A'; end; Because I can't pass a PSomeRec to that function, only a TSomeRec

Then pass a PSomeRec^ to it if you don't intend to change the pointer anyway.

Jonas

L505
to Jonas Maebe
Show quoted text 13 lines
> did you mean this ? : > > procedure ChangeRec1(const Rec: TSomeRec); > begin > Rec.a:= 'string A'; > end; > > Because I can't pass a PSomeRec to that function, only a TSomeRec Then pass a PSomeRec^ to it if you don't intend to change the pointer anyway.

That works, I was getting sloppy with Delphi style code who doesn't always require the ^

Michael Müller
to L505: I remember this from using classes where you can still access the class properties -…
L505 wrote 18 lines
> > Only the pointer itself is the parameter and read-only. Where the pointer > > points to is irrelevant. I remember this from using classes where you can still access the class properties - should have thought about that before posing the question :). > > But in this case I'm wondering why you want to give a pointer instead > of the real type? did you mean this ? : procedure ChangeRec1(const Rec: TSomeRec); begin Rec.a:= 'string A'; end;

Yes.

Because I can't pass a PSomeRec to that function, only a TSomeRec

Where is the problem? If you allocated the memory by new() as in your example you could call
ChangeRec1(RecPtr^);
and the compile (hopefully) uses the pointer.

But in this case you will get an compiler error because you can't change a constant value.

It seemed that I didn't get the point from your original mail: Name the procedure CHANGERec1 and change a value but declare the parameter as constant.

Otherwise, I don't know what you mean..

Now _I_'m a little bit confused.

Michael

L505
to Michael Müller
Show quoted text 13 lines
> > > > But in this case I'm wondering why you want to give a pointer instead > > of the real type? > > > did you mean this ? : > > procedure ChangeRec1(const Rec: TSomeRec); > begin > Rec.a:= 'string A'; > end; Yes.

Well, this is a Precord. That doesn't work. That is why I was confused.

Show quoted text 7 lines
> Because I can't pass a PSomeRec to that function, only a TSomeRec Where is the problem? If you allocated the memory by new() as in your example you could call ChangeRec1(RecPtr^); and the compile (hopefully) uses the pointer.

Yes, but you are repeating what Jonas says - if you would have told me this first, you would have gotten the brownie points. But Jonas gets them. :-)

Show quoted text 7 lines
But in this case you will get an compiler error because you can't change a constant value. It seemed that I didn't get the point from your original mail: Name the procedure CHANGERec1 and change a value but declare the parameter as constant.

I was asking why I could write to a const. But in fact I was not writing to the CONST, I was actually writing to the const data it pointed to. With SomeRec^ I cannot write to const. Problem solved.

I was using sloppy Delphi style code without ^ since Delphi enforces this sloppy style of coding, and now I know why not to use sloppy delphi style code.

What I was confused about was why you recommended TSomeRec when we are dealing with PSomeRec.

I also stated that I knew you can pass TSomeClass as a const, you can still access it's properties even though it is a const.

 program project1;
 {$mode objfpc}{$H+}
   type
     TSomeClass = class
       a: string;
       b: string;
     end;
   procedure ChangeClass(const SomeClass: TSomeClass);
   begin
     SomeClass.a:= 'string A';
   end;
 var
   SomeClass: TSomeClass;
 begin
   someclass:= TSomeClass.create;
   ChangeClass(someclass);
   writeln(someclass.a);
   someclass.free;
   readln;
 end.

This is normal, because we are passing a pointer when dealing with a class - not passing the class contents. Which is really what I should have thought about before asking the question, because I have discovered you can write to a const class *contents* before.