[fpc-devel] "Default" discussion for SmartPointers etc

Sven Barth pascaldragon at googlemail.com
Tue Jul 26 21:59:04 CEST 2016


On 26.07.2016 14:51, Maciej Izak wrote:
> Hi,
> 
> Finally I have a working implementation (not published yet) of Smart
> Pointers/ARC objects and Nullable (Nilable?) types. I think is worth to
> discuss a little about new "default modifier" (which is strictly related
> to mentioned structures). If needed I can correct details.
>

First of let me tell you that in essence and in general I'm in support
of your "default" idea (and the resulting idea to use this for smart
pointers), though I have a few points, but I hope that we'll be able to
solve these. :)

> As you know (or not) all is based on new modifier - "default" for
> fields. Overriding operators like "." or "^" is complicated and not
> obvious in Pascal world.

Agreed.

> The "default" modifier is inspired by "default" modifier for indexed
> properties. All of my work is (I hope so) natural for Pascal language.
> All FPC tests pass fine (phew!). The idea is quiet simple:
> 
> "If all fails - try to use default field".
> 
> Example implementation of SmartPointers and SmartObjects available at:
> 
> https://github.com/maciej-izak/PascalSmartPointers (see OUTPUT on the
> end of each of file)

First of it might be better not to name the tests "tdefaultX.pp" as that
is already used for the Default() intrinsic... :/

Second I don't know whether it's a good idea to use this with fields
(though kudos for omitting the ";" between type and "default" ;) ).
Maybe it would be better - to stay with the source of your idea - to
only allow this for properties. This would allow to keep the field
itself private for example and control its access through the setter
(and ordinary as well as management operators), something that one
couldn't do if one would need to use operators as the field would need
to be public to be really useful outside of the record instance.

Third I don't really agree with the notion that the record methods,
fields, etc. take precedence to the default field. See further down for
my suggestion to solve this (though that idea isn't without its flaws
either).

Question: can "default" only be used in "record" or also in "object" and
"class"?

> 
> Tests (very good way to see how it works. NOTE: I need to add few other
> tests for functions with var/const/out, "for in do" loop and for arrays
> and indexed properties - help with additional tests is welcome):
> 
> https://github.com/maciej-izak/PascalSmartPointers/tree/master/tests

Note: tests for visibility.

> 
> The way how to obtain pointer can be a little confusing for most of
> Pascal programmers. Anyway nothing new for Pascal language. In Pascal we
> have little known @@ operator to get pointer to variable which handle
> pointer to procedure/function. For records with "default field" @ means
> "get pointer to default field" and @@ means "get pointer to record".

While I have to admit that I haven't known the @@-operator I don't
necessarily agree with its use. Take tdefault7 and tdefault8 for example
where you let the left hand side of the assignment determine which
pointer is used. In tdefault7 it's the pointer to "a" while in tdefault8
it's the pointer to "a.DefaultValue". Since normally in Pascal the
result type of an expression is *not* determined by the left hand side
of an assignment that's rather confusing (yes, there are exceptions, but
that doesn't mean that one needs to add a new one).

My idea to solve this coincides with my idea to solve the problem to
access the record instead of the default field: typecasts.

Take tdefault11 for example (which suffers from the same problem I
mentioned above):

=== code begin ===

program tdefault11;

{$MODE DELPHI}

type
  TFoo<T> = record
    Field1: Integer;
    DefaultValue: T default;
    Field2: Integer;
  end;

  TFooInt = TFoo<Integer>;
  TFooFooInt = TFoo<TFooInt>;

var
  a: TFooFooInt;
  pi: PInteger;
  pfi: ^TFooInt;
  pffi: ^TFooFooInt;
begin
  a := 123;

  pi := @a; // accesses a.DefaultValue.DefaultValue
  pfi := @TFooInt(a); // forces access to a.DefaultValue
  pffi := @TFooFooInt(a); // forces access to a

  if Pointer(pi) = Pointer(pfi) then
    Halt(1);

  if Pointer(pi) = Pointer(pffi) then
    Halt(2);

  if Pointer(pfi) = Pointer(pffi) then
    Halt(3);

  if pi^ <> 123 then
    Halt(4);

  if pfi^ <> 123 then
    Halt(5);

  if pffi^ <> 123 then
    Halt(6);
end.

=== code end ===

Essentially a typecast would disable the default field for the type it
had been casted to.

Of course this idea with the default field taking precedence becomes
tainted a bit if one considers the management operators or the
assignment operators as these would be part of the record and not the
default field, but would still need to work...

Note: don't forget to test with global operator overloads ;)

Regards,
Sven



More information about the fpc-devel mailing list