Sign in Join

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

Mailing lists / fpc-pascal / 2017-01

Untyped var params

22 messages · 6 people · –

Reply by email Subscribe to this list Your subscription

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

Ryan Joseph

I’ve seen functions that use the untyped params like:

function GetSomething (var something): boolean;

This seems like something useful I would like to use but how can you assign to the parameter? I tried but I got an error message which is confusing because it’s a “var” after all.

Thanks.

Regards,
Ryan Joseph

Reply by email

Dmitry Boyarintsev
to Ryan Joseph
Ryan Joseph wrote 8 lines
I’ve seen functions that use the untyped params like: function GetSomething (var something): boolean; This seems like something useful I would like to use but how can you assign to the parameter? I tried but I got an error message which is confusing because it’s a “var” after all.

A parameter you pass, would be passed by a reference (an address in memory)

Thus
GetSomething(5)
will not work.

var
  i: integer;
begin
  i:=5;
  GetSometing(i)

Be careful using this open parameter, since you don't have any type information about "something". You either should not assume the type or pass the additional information

thanks,
Dmitry

Reply by email

Ryan Joseph
to Dmitry Boyarintsev
Show quoted text 8 lines
On Jan 4, 2017, at 10:14 PM, Dmitry Boyarintsev wrote: var i: integer; begin i:=5; GetSometing(i)

But how do you assign to “something" then if you don’t know the type? The param is “var” so shouldn’t I be able to assign to the param and return it back to the caller? In your example how could I return 5 to “i” inside GetSomething?

Regards,
Ryan Joseph

Reply by email

Dmitry Boyarintsev
to Ryan Joseph
Ryan Joseph wrote 6 lines
But how do you assign to “something" then if you don’t know the type? The param is “var” so shouldn’t I be able to assign to the param and return it back to the caller? In your example how could I return 5 to “i” inside GetSomething? Treat is as a pointer (it's an implicit pointer anyway)
function GetSomething (var something): boolean
var
  pi: PInteger;
begin
  ;
  GetSomething:=pi^>=5;
end;

or an old-school way using "absolute".

function GetSomething (var something): boolean;
var
  i: Integer absolute something;
begin
  GetSomething:=i>=5;
end;
var
  i : integer;
begin
  i:=3;
  writeln(GetSomething(i));
end.

check out "anysort" function
http://wiki.freepascal.org/Array_sort

It's using untyped parameter to perform a sort on an arbitrary type array

thanks,
Dmitry

Reply by email

Ryan Joseph
to Dmitry Boyarintsev
On Jan 4, 2017, at 11:07 PM, Dmitry Boyarintsev wrote: Treat is as a pointer (it's an implicit pointer anyway)

So I need to need to use Move to write memory directly to “var something”? That makes sense I guess and could be useful is some cases but not like I was planning. Thanks for helping.

Regards,
Ryan Joseph

Reply by email

Lars
to Ryan Joseph
Ryan Joseph wrote 14 lines
> On Jan 4, 2017, at 11:07 PM, Dmitry Boyarintsev > wrote: > > > Treat is as a pointer (it's an implicit pointer anyway) > > So I need to need to use Move to write memory directly to “var something”? That makes sense I guess and could be useful is some cases but not like I was planning. Thanks for helping.

Why do you need to deal with it directly rather than indirectly setting up something to access it...

What is the advantage of writing directly in your case..

Reply by email

Andrew Hall
to Ryan Joseph: So I need to need to use Move to write memory directly to “var something”? That makes…

If you cast your “something” to a typed pointer, the compiler will do the work for you in the usual way:

PDouble(something)^ := myDouble;
PAnsiString(something)^ := myAnsiString;
myRecordStructure  := PMyRecordStructure(something)^;

Or less elegantly:

AnsiString(Pointer(something)^) := myAnsiString;

Regards,

Ryan Joseph wrote
So I need to need to use Move to write memory directly to “var something”? That makes sense I guess and could be useful is some cases but not like I was planning. Thanks for helping.

Reply by email

Dmitry Boyarintsev
to Andrew Hall
Andrew Hall wrote 5 lines
If you cast your “something” to a typed pointer, the compiler will do the work for you in the usual way: PDouble(something)^ := myDouble;

or rather
PDouble(@something)^ := myDouble;
?

thanks,
Dmitry

Reply by email

Bart
to Dmitry Boyarintsev
Dmitry Boyarintsev wrote 5 lines
> But if you know that at forehand (and you know, since you cast it), > why then use an untyped var parameter at all? > http://www.freepascal.org/docs-html/rtl/system/fillchar.html ?

That does not realy answer my question.

It was suggested to do something like this:

procedure X(var Y);
begin
  PInteger(Y)^ := 3;  //syntax may be wrong, too lazy to test
end;

To me this completely defies the purpose of an untyped var parameter, since in this exmaple you do know, @design time, the type of Y, so why not write then

procedure X(var Y: Integer);
begin
  Y := 3;
end;

FillChar OTOH _is_ a good example of why you would use an untype var parameter.

Bart

Reply by email

Dmitry Boyarintsev
to Bart: That does not realy answer my question. It was suggested to do something like this:…
Bart wrote 15 lines
procedure X(var Y); begin PInteger(Y)^ := 3; //syntax may be wrong, too lazy to test end; To me this completely defies the purpose of an untyped var parameter, since in this exmaple you do know, @design time, the type of Y, so why not write then procedure X(var Y: Integer); begin Y := 3; end;

Think about something like a var-type variable, where the actual type of Y might vary.

procedure XX(var Y; YType: integer);
begin
  case YType  of
    T_INT: PInteger(@Y)^:= 3;
    T_SINGLE: PSingle(@Y)^:=3;
    T_DOUBLE: PDouble(@Y)^:=3;
  end;
end;

Again, earlier in the thread I gave a link to anySort() example, that could sort any array-like structure (as long as elements of the structure are placed in sequential order in memory).

As I said mentioned earlier. Untyped parameter, is an implicit pointer (since the value is always passed by reference).
But there's a compile-time difference.
If you'd declare a parameter as a pointer
procedure X( Y:Pointer);

Then it would be possible to use the function as following: X(nil)
which requires you, at least add additional sanity check into X procedure.

But if you'd declare it as X(var Y), then the compiler would not allow to pass nil, always requiring a user to provide a valid variable to be passed and writing something like X(nil) is no longer possible.

Here's an example:
http://www.freepascal.org/docs-html/rtl/system/iunknown.queryinterface.html

QueryInterface must return an interface variable. BUT:
* the actual returned interface type is unknown at compile time.
* "obj" parameter must not be nil, since the reference must be written somewhere.

It's also more convenient from syntax point of view, since a developer doesn't have to write "@" symbol when passing a parameter. The reference would be resolved by the compiler itself.

thanks,
Dmitry

Reply by email

Bart
to Dmitry Boyarintsev
Dmitry Boyarintsev wrote 11 lines
Think about something like a var-type variable, where the actual type of Y might vary. procedure XX(var Y; YType: integer); begin case YType of T_INT: PInteger(@Y)^:= 3; T_SINGLE: PSingle(@Y)^:=3; T_DOUBLE: PDouble(@Y)^:=3; end; end;

OK, I can imagine more complex examples where this may come in handy.

And thanks for the rest of the explanation.

Bart

Reply by email

Dmitry Boyarintsev
to Bart
Bart wrote
OK, I can imagine more complex examples where this may come in handy. And thanks for the rest of the explanation.

And only more complex examples should be used :)
There're much better ways to implement var-type variables.

I was always thinking that having untyped variables in Pascal is more a syntactical advantage, whenever a Pascal need to target managed platforms (i.e. Net or Java). These platforms don't any kind of a code written using pointers would not even compile on them.

Thus using open arrays (of bytes) and untyped variables would be a good replacement for pointers whenever writing a cross-platform code (meaning a code that would need to target both non-managed and managed platforms)

Not sure, but pascal JVM has its own means of dealing with pointers anyway. My knowledge is poor on the subject of jvm, but it's well explained in the wiki!

thanks,
Dmitry

Reply by email

Dmitry Boyarintsev
to Lars: Some brave soldiers once tried to reinvent generics using these tricks..
Lars wrote
Some brave soldiers once tried to reinvent generics using these tricks..

Well, Pascal run-time has been using "hidden" generics forever.

As an example:
http://www.freepascal.org/docs-html/rtl/system/val.html

Val() declares the second parameter as untyped var parameter. Unfortunately, it's not quite so. Compiler recognizes the run-time function and requires the parameter to be either an Integer or Float-point type (or an enumerated type since 2.3.1).

So it's more a generic-like behavior (with integer and float types specialized)

thanks,
Dmitry

Reply by email

Sven Barth
to Dmitry Boyarintsev

Am 08.01.2017 04:43 schrieb "Dmitry Boyarintsev" <

Show quoted text 14 lines
: On Sat, Jan 7, 2017 at 6:02 PM, Lars wrote: > > Some brave soldiers once tried to reinvent generics using these tricks.. Well, Pascal run-time has been using "hidden" generics forever. As an example: http://www.freepascal.org/docs-html/rtl/system/val.html Val() declares the second parameter as untyped var parameter. Unfortunately, it's not quite so. Compiler recognizes the run-time

function and requires the parameter to be either an Integer or Float-point type (or an enumerated type since 2.3.1).

So it's more a generic-like behavior (with integer and float types

specialized)

Val() is a compiler intrinsic so there doesn't exist a declaration for it anyway, so it's quite a bit outside of the scope of var parameters.

Regards,
Sven

Reply by email

Ryan Joseph
to Andrew Hall: If you cast your “something” to a typed pointer, the compiler will do the work for…
Show quoted text 7 lines
On Jan 8, 2017, at 2:37 AM, Andrew Hall wrote: If you cast your “something” to a typed pointer, the compiler will do the work for you in the usual way: PDouble(something)^ := myDouble; PAnsiString(something)^ := myAnsiString; myRecordStructure := PMyRecordStructure(something)^;

I’m not getting any of this to work.

Here is the pattern I was attempting. It’s a “release existing, retain and assign new” function which handles nil inputs safely. I thought I could use untyped params so I don’t need to typecast “io” to TObject when I call RetainObject every time.

procedure RetainObject (var io; newObject: TObject);
var
	obj: TObject absolute io;
begin
	if obj  nil then
		obj.Release;
	if newObject  nil then
		begin
			obj := newObject;
			obj.Retain;
		end
	else
		obj := nil;
	TObjectPtr(io)^ := obj;	// crashes here
end;
var
	foo: TMyObject;
	something: TMyObject;
foo := TMyObject.Create;
RetainObject(something, foo);

Regards,
Ryan Joseph

Reply by email

Sven Barth
to Ryan Joseph
Ryan Joseph wrote 29 lines
> On Jan 8, 2017, at 2:37 AM, Andrew Hall wrote: > > If you cast your “something” to a typed pointer, the compiler will do the work for you in the usual way: > > PDouble(something)^ := myDouble; > PAnsiString(something)^ := myAnsiString; > myRecordStructure := PMyRecordStructure(something)^; I’m not getting any of this to work. Here is the pattern I was attempting. It’s a “release existing, retain and assign new” function which handles nil inputs safely. I thought I could use untyped params so I don’t need to typecast “io” to TObject when I call RetainObject every time. procedure RetainObject (var io; newObject: TObject); var obj: TObject absolute io; begin if obj nil then obj.Release; if newObject nil then begin obj := newObject; obj.Retain; end else obj := nil; TObjectPtr(io)^ := obj; // crashes here end;

1. Why are you trying to assign something to io when you already did that with "obj := ..."?
2. TObject is an implicit pointer, so "TObject(io) := ..." would be correct (see the implementation of FreeAndNil() in $fpc/rtl/objpas/sysutils/sysutils.inc) [otherwise your usage of "obj" would already crash]

Regards,
Sven

Reply by email

Ryan Joseph
to Sven Barth
On Jan 8, 2017, at 5:22 PM, Sven Barth wrote: 1. Why are you trying to assign something to io when you already did that with "obj := …"?

I used absolute here so I could know the type of io and not type cast within the function. No good? The idea is I want “io” to be assigned with the value from newObject or set to nil if the input is nil. I know io is a member of TObject but I don’t want type checking when I return the value from the function otherwise all my calls look like RetainObject(TObject(foo), newFoo). It’s a small annoyance but I thought I would take the time to learn Free Pascal more since it always pays off in the end.

Casting TObject(input) := obj; worked but the value of “io” is still not getting set. Because it’s a var I expected the value to be returned to the caller.

Regards,
Ryan Joseph

Reply by email

Ryan Joseph
to Ryan Joseph
On Jan 8, 2017, at 5:36 PM, Ryan Joseph wrote: Casting TObject(input) := obj; worked but the value of “io” is still not getting set. Because it’s a var I expected the value to be returned to the caller.

Never mind, I got it working, stupid mistake in my testing.

yes just like that function. I just learned about absolute so I was making us of it. Seems to work the same as casting in FreeAndNil. Thanks for helping.

    procedure FreeAndNil(var obj);
      var
        temp: tobject;
      begin
        temp:=tobject(obj);
        pointer(obj):=nil;
        temp.free;
      end;

Regards,
Ryan Joseph

Reply by email

Sven Barth
to Ryan Joseph: I used absolute here so I could know the type of io and not type cast within the…
Ryan Joseph wrote 7 lines
> On Jan 8, 2017, at 5:22 PM, Sven Barth wrote: > > 1. Why are you trying to assign something to io when you already did > that with "obj := …"? I used absolute here so I could know the type of io and not type cast within the function. No good? The idea is I want “io” to be assigned with the value from newObject or set to nil if the input is nil. I know io is a member of TObject but I don’t want type checking when I return the value from the function otherwise all my calls look like RetainObject(TObject(foo), newFoo). It’s a small annoyance but I thought I would take the time to learn Free Pascal more since it always pays off in the end.

The use of absolute is absolutely (ha!) fine. However the second assignment using "io" is superfluous as you already did the assignment through the absolute alias.

Regards,
Sven

Reply by email