2016-07-26 21:59 GMT+02:00 Sven Barth :
Show quoted text 5 lines
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. :)
Note: Generally I am working on boost-spirit like solution for Pascal so one single bad move will destroy my further plans...
First of it might be better not to name the tests "tdefaultX.pp" as that
is already used for the Default() intrinsic... :/
No problem with that - we can change this ;)
Show quoted text 9 lines
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.
Property was considered for "default" as main option but has many weakness. Sure, default "non indexed" property can be added as addition but definitely not as main idea, because:
1. It breaks tdefault17 :
https://github.com/maciej-izak/PascalSmartPointers/blob/master/tests/tdefault17.pp http://forum.lazarus.freepascal.org/index.php/topic,32482.msg209584.html#msg209584
(yes I know we can use property for this but you need to declare additional getter/setter which is not much elegant in that case)
2. "default" for field is unique for [Nil|Null]able types (fastest possible implementation, and very correct for Pascal language. Nilable type works exactly like pointers with nice additions):
=== code begin ===
type
// record constraint is designed for nullable types :P see #24073
// #24073 Is already fixed in my implementation. record constraint accepts
// all not nilable types (including sets and strings - empty string as
logical entity is not nil at all)
TNullable<T: record> = record
public type
PT = ^T;
strict private
Instance: ^T default;
function GetValue: T;
public
property Value: T read GetValue;
function HasValue: Boolean; inline;
function GetValueOrDefault: T;
class operator Implicit(A: T): TNullable<T>;
class operator Implicit(A: TNullable<T>): T;
class operator Implicit(A: PT): TNullable<T>;
class operator Equal(A: TNullable<T>; B: PT): Boolean;
class operator Initialize(var A: TNullable<T>);
class operator Finalize(var A: TNullable<T>);
class operator Clone(constref Src: TNullable<T>; var Dest:
TNullable<T>);
class operator Copy(var Rec: TNullable<T>);
end;
=== code end ===
3. "default" need to be transparent and usable with existing code base, some compiler magic is part of my further compiler development (I mean here "Storage Modifiers" and ARC objects in DelphiNextgen mode). With current approach is possible to pass record with default field as var/out/constref parameter. With property that is impossible.
4. for property for records there exist well know problems for "with"
5. "default" is designed as specialized helpers for TArray<T> and for Interfaces, property will block passing "default field" as var/out/constref parameter (similar to point 3).
Show quoted text 8 lines
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"?
Current implementation allows "default" only for "records".
Show quoted text 10 lines
Right, but note that "default" is implicitly used even when is declared as strict private (which is correct and by design - for example see TNullable above). For "default" non indexed properties that rule might be incorrect.
Show quoted text 11 lines
> 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".
@@ operator is very simple way to determine where you point. In any other case we have casting hell. See below (and more below). @@ exist rather as fulfillment to pa := @a; form tdefault7.pp (anyway is necessary for untyped pointers). You might not like @@ operator but @@ is part of long tradition. In practice works like a charm and is very clear.
Show quoted text 5 lines
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).
That is also by design. That is because you can't declare as "default field" nor "normal field" the field of owner type, so as logical consequence the syntax needs to be allowed (I mean here pa := @a; form tdefault7.pp). In daily usage it works very well and any other compiler behavior is irrational. Thank this feature most of programmers don't need to use @@ syntax (btw. the idea of introducing this was not forcing others to use @@). Additionally is necessary to get ride of untyped/typed pointers so we have rules presented in example tdefault8. Anyway for complex solution @@ is needed.
Show quoted text 7 lines
My idea to solve this coincides with my idea to solve the problem to
access the record instead of the default field: typecasts.
...
Essentially a typecast would disable the default field for the type it
had been casted to.
That was my first implementation (!!!). Which is definitely bad. :\ It breaks a lot of other important rules. For example is impossible to get ride of Implicit/Explicit operators when as "default field" is declared record which has Implicit/Explicit operators. Really, really bad idea, end-user code looks terrible and is unclear.
Show quoted text 5 lines
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...
Remember that "default" is designed not "only" for SmartPtr/Obj and for Nilable types but also for "specialized" helpers for any type (for example for TArray<T>, for Interfaces etc). We can't do exception only for management operators and for assignment operators - unclear rule.
Note: don't forget to test with global operator overloads ;)
I will try to remember ;)
Best regards,
Maciej Izak