> On Jun 20, 2024, at 4:02 AM, Martin via Dwarf-discuss 
> <dwarf-discuss@lists.dwarfstd.org> wrote:
> 
> Sorry for the late reply. I've been away.
> 
> > - What does it mean for a property to be default? I couldn't find that
> > defined in the linked FreePascal documentation.
> 
> The property can be accessed without its name being specified.
> 
> This currently exists for (array-like) indexed properties.
> 
> `   property Foo [AnIndex: TSomeType]: TPropType read GetVal; default;`
> 
> If variable Bar is of a type having above property, then instead of
>  `Bar.Foo[SomeVal]`
> The code/expression can read
>  `Bar[SomeVal]`
> 
> Bar as on object itself does not have an index. So by giving an index it is 
> clear that the expression accesses the property.
> 
> Currently this is limited to array-like properties. There are some ideas to 
> extend this, but nothing concrete.
> The determination, if an expression accesses a "default property" does not 
> belong to the DWARF specs, it has to be done by a language specific 
> expression parser.

> Also right now, only one indexed property can be marked default, but this may 
> get extended. Multiply properties with different index-types could be each 
> default.
> 

Thanks for the explanation, that makes sense!

> 
> > - Why is there both a DW_AT_Default_Property and
> > a DW_TAG_Property_Default?
> 
> 1) DW_AT_Default_Property
> Above "default property".

It really looks like this might need to be a new attribute, since neither the 
existing DW_AT_default_value and DW_AT_defaulted seem to be appropriate here.

> 2) DW_TAG_Property_Default
> "default value" of a property.
> 
> property Foo: integer read FFoo default 1;
> // In Pascal, there is no semicolon before "default" for this.
> 
> The latter can (in Pascal) be accessed via Run-Time-Type-Information. It is 
> e.g. used in streaming of objects.
> The property can be omitted from the stream, if it has its default value. Or 
> when reading a stream, the default value will be assigned, if no value is 
> present in the stream.
> The compiler only generate the RTTI. Streaming can be implemented by the 
> user, but the RTL provides functionality using the "default" as described.
> 
> On 2nd thought: I don't know if (or in which form) such info exists in other 
> languages. And the amount/kind of such info available may be subject to 
> change. I included it, as default-value and stored (below) in Pascal are 
> commonly used. But there is room to discuss them as an extension (and 
> possible more generic: some form of attributes that can be associated with 
> any value/type)

Here I think it would be appropriate to use DW_AT_default_value (the new 
variant defined in https://dwarfstd.org/issues/141117.1.html that takes an 
arbitrary string).

> > - What is the purpose of DW_TAG_Property_Stored?
> > Maybe also add an example for this.
> 
> The DW_TAG_Property_Stored is used in a similar fashion as default. But 
> provide just a boolean.
> 
> It is also accessible via RTTI. It can be a constant but often is a function.
> 
> property Foo: integer read FFoo stored GetFooStored;
> 
> If the properties value is only meaningful when the object is in a specific 
> state, then GetFooStored could return true/false depending on that state.
> 
> E.g. if a RGBA color has a flag "Solid", then when it is solid, it needs no 
> alpha channel. The object may not want the unused alpha value to appear in a 
> stream. It could then implement a stored-function for the Alpha property.

Interesting, am I misunderstanding or does Pascal use the exact inverse 
nomenclature that Swift uses 
(https://docs.swift.org/swift-book/documentation/the-swift-programming-language/properties/)?
In Swift a stored property is one that is backed by a field in the record, and 
a computed property is value produced by a function. It sounds like in Pascal 
it's the exact opposite? Or does "stored function" mean something different?

> 
> > - DW_TAG_Property_Argument_List would also benefit from an example.
> 
> The current use case would be several properties using the same getter.
> Each property has an "index" (not the array-like index sorry another naming 
> conflict, will call this one "property-index").
> 
> ```
> class TMyClass
> function GetProp(AIndex: Integer): integer;
>  property MyProp1: integer index 1 read GetProp;
>  property MyProp2: integer index 2 read GetProp
> end;
> 
> class TMyOtherClass
> function GetOtherProp(a: boolean; AIndex: Integer): integer;
>  property MyProp1[a:integer]: integer index 1 read GetOtherProp;
>  property MyProp2[a:integer]: integer index 2 read GetOtherProp;
> end;
> ```
> 
> The property-index is passed as one of the arguments to the function.

Oh interesting, so here you declare on getter that handles multiple properties 
and the language provides syntax for passing fixed or dynamic arguments to that 
function. Yes, this will need special support in the form of a custom 
Tag/Attribute. I'll think about this some more, but it might be nice to come up 
with a representation that also works for other languages that allow an 
arbitrary function to be used as a getter/setter (like Objective-C) and maybe 
it can be combined with the existing DW_AT_default_value, to represent the 
property index, but I'm not sure about the subscript index.

> 
> In general, this may also be useful for other languages, if they pass 
> multiple arguments to a getter/setter, and the order of arguments needs to be 
> clarified.
> 
> For the above, it avoids a (probably) Pascal specific 
> `DW_AT_pascal_property_index_value`.
> 
> The proposal has some notes on this in the "function parameters" section.
> 
> Example, the default parameters (without the property-index) for
> - GetProp is (_this)
> - GetOtherProp are (_this, a)
> And setters
> - SetProp is (_this, NewValue)
> - SetOtherProp are (_this, a, NewValue)
> 
> The position for the value of 1 or 2 (for the property-index) must be 
> specified.
> 
> Alternatively, it could be hard-specified in the DWARF spec, as a language 
> specific order...
> But then, there would be a need for `DW_AT_pascal_property_index_value`.
> And other languages may need their own extra values.
> 
> The idea is, that having a property, it can be translated into a 
> function/method call as follows:
> - 'Foo.MyProp' = `Foo.MyPropGetter()`
> - global/non-class: 'MyProp' = `MyPropGetter()`
> - 'Foo.MyProp[1,2]' = `Foo.MyPropGetter(1,2)`
> 
> Any arguments not specified by the user (and not _this) will be given as a 
> list of: argument-position / argument-value
> 
> 
> For the classes above
> 
> ```
>  DW_TAG_Structure_type
>    DW_AT_Name :  "TMyClass"
> L1:
>    DW_TAG_subprogram
>        DW_AT_Name            :  "GetProp"
>        DW_AT_Type            :  <...>
>      DW_TAG_formal_parameter
>          DW_AT_Name            :  "_this"
>      DW_TAG_formal_parameter
>          DW_AT_Name            :  "AIndex"
>    DW_TAG_Property
>        DW_AT_Name             :  "MyProp1"
>        DW_AT_Type             :  <...>
>      DW_TAG_Property_Getter
>          DW_AT_Property_Forward :  reference to L1

Any reason not to use DW_AT_specification for this?

>        DW_TAG_Property_Argument_List
>            DW_AT_Property_Argument_Number : 1
>                         ! DW_TAG_formal_parameter at pos 1 "AIndex"
>            DW_AT_Property_Argument_Value : 1    ! the index value

We may be able to reuse a sequence of DW_TAG_format_parameter with 
DW_AT_default_value here to avoid introducing multiple specialized 
tags/attributes.

> ```
> For MyProp2, DW_AT_Property_Argument_Value will be 2.
> 
> For `GetOtherProp` the `DW_AT_Property_Argument_Number` would be position 2
> ```
>  DW_TAG_Structure_type
>    DW_AT_Name :  "TMyOtherClass"
> L1:
>    DW_TAG_subprogram
>        DW_AT_Name            :  "GetProp"
>        DW_AT_Type            :  <...>
>      DW_TAG_formal_parameter
>          DW_AT_Name            :  "_this"
>      DW_TAG_formal_parameter
>          DW_AT_Name            :  "a"
>      DW_TAG_formal_parameter     ! argument number 2 (zero based)
>          DW_AT_Name            :  "AIndex"
>    DW_TAG_Property
>        DW_AT_Name             :  "MyProp1"
>        DW_AT_Type             :  <...>
>      DW_TAG_Property_Getter
>          DW_AT_Property_Forward :  reference to L1
>        DW_TAG_Property_Argument_List
>            DW_AT_Property_Argument_Number : 2
>                         ! DW_TAG_formal_parameter at pos 2 "AIndex"
>            DW_AT_Property_Argument_Value : 1    ! the index value
> 
> ```
> 
> 
> If a setter is called, then the new value is the last argument to the 
> function. If any language has a different position it can specify
> DW_AT_Property_Value_Argument_Number
> Which is a direct child of DW_TAG_Property_Setter (not in 
> DW_TAG_Property_Argument_List)
> 
> For the hypothetical / non-Pascal
>  procedure SetOtherProp(NewVal: integer; a: boolean; AIndex: Integer);
> 
> ```
>      DW_TAG_Property_Setter
>          DW_AT_Property_Forward :  reference
>          DW_AT_Property_Value_Argument_Number : 1   ! pos of "NewVal"
>        DW_TAG_Property_Argument_List
>            DW_AT_Property_Argument_Number : 3   ! pos of "AIndex"
>            DW_AT_Property_Argument_Value : 1    ! the index value
> ```
> 
> The _this argument is passed according to normal function calling rules.
> If the _this DW_TAG_formal_parameter (or DW_AT_Property_Argument_Number) has 
> been used by any DW_AT_Property_Argument_Number, then it needs to be decided
> - don't pass it (assume it has been set already)
> - pass it in the next available param?
> 
> The arguments for the array-like index will be passed left to right in any 
> DW_TAG_formal_parameter that has not been used.
> E.g. with DW_AT_Property_Value_Argument_Number=1
> DW_TAG_formal_parameter(0): _this
> DW_TAG_formal_parameter(1): new value
> DW_TAG_formal_parameter(2): array-like "a" (leftmost unused param)
> DW_TAG_formal_parameter(3): property-index "AIndex"
> 
> 
> 
> > - If I understand correctly, the purpose of DW_AT_Property_Forward
> > is to reference a getter or setter DW_TAG_subprogram.
> >  Is there a specific reason you decided for this representation
> >  over nesting a DW_TAG_subprogram with a DW_AT_property_getter (true) 
> > inside the DW_TAG_property?
> 
> Actually it can refer any other (non-property) member of an object. 
> (function, member, or variable (static member).
> Or for properties outside a class, it can refer a function or variable.

I see, so it needs to be a DIE reference. We might be able to reuse 
DW_AT_specification for this purpose though.

> 
> The proposal allows a choice of either
> - DW_AT_Property_Forward
> - DW_TAG_Member, DW_TAG_Variable, DW_TAG_subprogram
> 
> So, it is possible to have anonymous accessors/storage.
> 
> The forward would simple allow the debugger to identify the named member that 
> provides the value, if any debugger wants to maybe show that.
> 
> IMHO, if the field/accessor is on another object then the forward seems more 
> natural. But that is my personal preference.

I think that's reasonable to keep them separate.

> If there will be functions on nested objects, the directly specifying 
> DW_TAG_subprogram may be misleading with regards to the correct _this 
> parameter (though it will work, as the param can be given by 
> DW_AT_Property_Object)
> 
> 
> 
> > - Why isn't the accessibility attribute
> > on the linked DW_TAG_subprogram?
> 
> They can have different visibility.
> 
> ```
> TMyClass = class
> private
>  function Getbar: boolean;
> public
>  property bar: boolean read Getbar;
> end;
> ```

Makes sense.

> 
> // or even
> ```
> TMyClass = class
> private
>  function Getbar: boolean;
> protected
>  property bar: boolean read Getbar;
> end;
> 
> TMySubClass = class(TMyClass)
> public
>  property bar; // only change visibility
>  procedure GetBar: boolean; reintroduce;
> end;
> ```
> 
> In TMySubClass the property "bar" still calls the inherited GetBar from the 
> parent.
> The GetBar isn't virtual, and so the new GetBar hides the parent GetBar for 
> any code calling GetBar directly (without the property)
> 
> 
> > - Why is DW_AT_property_object needed?
> 
> //Example
> TPoint = record x,y: integer; end;
> TLine = class
> private
>  FStart,FStop: TPoint;
> public
>  property StartX: integer read FStart.X;
> end;
> 
> In the DWARF description we would need to know if "X" is in FStart or FStop.
> 
> The DW_AT_Property_Forward would refer to the field "x" in the 
> DW_TAG_Structure for TPoint. So it would not indicate if that is FStart or 
> FStop. (since both will refer the type "TPoint")

How complex can these expressions get? Alternatively we could embed a string 
with the access path here like in DW_AT_default_value.
> 
> At the moment Pascal only supports such redirects for "records" (i.e. 
> structures without reference, that are inlined into the parents memory).
> For such structures the structure could be found from the memory location.
> 
> But for a generic approach the DW_AT_Property_Forward   would point to "X" in 
> "TPoint", and "X" would have a DW_AT_member_location. So the address of 
> FStart would be needed.
> 
> Of course if DW_AT_Location pointed to the address of FStart.X then that 
> provides the final location.
> 
> Currently - in Pascal - such redirects only work for fields. In future this 
> may support functions in nested object (Though there are no current plans). A 
> function would need a self parameter, therefore need to know the address of 
> the enclosing object.
> 
> Of course the address of the object can be a DW_AT_location.
> Its a matter of understanding the purpose of that location (it is not the 
> value itself).
> And also, while I can't think of any other location that could in future be 
> referred from a DW_TAG_Property_[GS]etter, there may be a chance for that to 
> happen.

Thanks for all the clarification, I think I have a good enough understanding of 
the problem now. I'll make another pass through the proposal to lock down 
design alternatives and see if it can be made congruent with Objective-C and 
Swift properties and post an update here and if you're happy with that we'll 
discuss it in plenary.

thanks,
Adrian


> 
> 
> 
> 
> 
> On 08/06/2024 01:12, Adrian Prantl wrote:
>> Hello Martin,
>> Thanks for submitting your proposal! In order to prepare it for discussion I 
>> would suggest to first try pick a first choice for all the design options in 
>> the proposal and then once the direction is clear, distill the normative 
>> text changes that would need to be made in the DWARF specification.
>> Adding a new TAG called DW_TAG_property seems like a good approach. There is 
>> nothing that's overly specific about Pascal in the proposal, so using the 
>> generic name seems like a good choice.
>> I had a couple of initial questions that came up while reading through the 
>> proposal:
>> - What does it mean for a property to be default? I couldn't find that 
>> defined in the linked FreePascal documentation.
>> - Why is there both a DW_AT_Default_Property and a DW_TAG_Property_Default?
>> - What is the purpose of DW_TAG_Property_Stored? Maybe also add an example 
>> for this.
>> - DW_TAG_Property_Argument_List would also benefit from an example.
>> - If I understand correctly, the purpose of DW_AT_Property_Forward is to 
>> reference a getter or setter DW_TAG_subprogram.
>>   Is there a specific reason you decided for this representation over 
>> nesting a DW_TAG_subprogram with a DW_AT_property_getter (true) inside the 
>> DW_TAG_property?
>> - Why isn't the accessibility attribute on the linked DW_TAG_subprogram?
>> After having read the last example, I think I can answer my question from 
>> above: Pascal allows to specify an access path to a (nested) field as the 
>> read accessor.
>> - Why is DW_AT_property_object needed? Couldn't the debugger determine the 
>> location from following the DW_AT_Property_Forward link? Related: Does this 
>> need to be a new attribute, or could this be DW_AT_location?
> -- 
> Dwarf-discuss mailing list
> Dwarf-discuss@lists.dwarfstd.org
> https://lists.dwarfstd.org/mailman/listinfo/dwarf-discuss

-- 
Dwarf-discuss mailing list
Dwarf-discuss@lists.dwarfstd.org
https://lists.dwarfstd.org/mailman/listinfo/dwarf-discuss

Reply via email to