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.


> - Why is there both a DW_AT_Default_Property and
> a DW_TAG_Property_Default?

1) DW_AT_Default_Property
Above "default property".

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)


> - 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.


> - 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.

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
        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

```
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.

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. 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;
```

// 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")


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.





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

Reply via email to