Sign in Join

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

Mailing lists / fpc-pascal / 2018-11

Default record const values

19 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

Should’t this work? This would be a good way to set default record values but it doesn’t seem to be supported.

type
	TMyRecord = record
		public
			a: integer;
			b: string;
		const
			default: TMyRecord = (a: 100; b: 'foo');
	end;
var
	r: TMyRecord = TMyRecord.default;

Regards,
Ryan Joseph

Sven Barth
to Ryan Joseph

Am Sa., 10. Nov. 2018, 10:06 hat Ryan Joseph
geschrieben:

Should’t this work? This would be a good way to set default record values but it doesn’t seem to be supported.

TMyRecord is not yet completely parsed. There could be another field located behind the "default" constant. Thus using the type of the record aside from Pointers and method parameters and result is not allowed.

Regards,
Sven

Ryan Joseph
to Sven Barth

Not quite understanding how that’s not entirely parsed by the time you assign outside of the record. Even so I would expect it to copy what the const was able to capture, fully parsed or not.

Also, why does it work to do

begin
  r := TMyRecord.default;

in the main block?

On Nov 10, 2018, at 4:55 PM, Sven Barth via fpc-pascal wrote: TMyRecord is not yet completely parsed. There could be another field located behind the "default" constant. Thus using the type of the record aside from Pointers and method parameters and result is not allowed.

Regards,
Ryan Joseph

Ryan Joseph
to Sven Barth: Am Sa., 10. Nov. 2018, 10:06 hat Ryan Joseph geschrieben: TMyRecord is not yet completely…

This also fails.

type
	TMyRecord = record
		public
			a: integer;
			b: string;
	end;
const
	TMyRecord_Default: TMyRecord = (a: 100; b: 'foo');
var
	r: TMyRecord = TMyRecord_Default;
On Nov 10, 2018, at 4:55 PM, Sven Barth via fpc-pascal wrote: TMyRecord is not yet completely parsed. There could be another field located behind the "default" constant. Thus using the type of the record aside from Pointers and method parameters and result is not allowed.

Regards,
Ryan Joseph

Sven Barth
to Ryan Joseph: Not quite understanding how that’s not entirely parsed by the time you assign outside…

Am Sa., 10. Nov. 2018, 12:44 hat Ryan Joseph
geschrieben:

Not quite understanding how that’s not entirely parsed by the time you assign outside of the record. Even so I would expect it to copy what the const was able to capture, fully parsed or not.

It's not entirely parsed by the time the constant is declared. That is simply illegal code.

Show quoted text 7 lines
Also, why does it work to do begin r := TMyRecord.default; in the main block?

It's not possible to use typed constants as initializers for variables.

Regards,
Sven

Ryan Joseph
to Ben Grasset
On Nov 11, 2018, at 6:51 AM, Ben Grasset wrote: Personally I think the answer here is keep working on your new/alternate implementation of default field functionality! It's a missing puzzle piece for FPC generics in many ways.

Not sure how default fields in generics help here. I just thought it would be nice if FPC supported this so we can init records at compile time easier. I’d prefer default struct fields like C++ has but typed const defaults would be an improvement.

I looked at the sources and in ttypedconstbuilder.read_typed_const_data (I think) it simply doesn’t support default record values with typed consts, only the = (a:x;b:x) style syntax. The typed const in the class was clearly defined as a hidden static var but I couldn’t figure out how to assign the values. Maybe I’ll look into it later.

Regards,
Ryan Joseph

Ben Grasset
to Ryan Joseph
PM Ryan Joseph wrote 5 lines
Not sure how default fields in generics help here. I just thought it would be nice if FPC supported this so we can init records at compile time easier. I’d prefer default struct fields like C++ has but typed const defaults would be an improvement.

I guess I just meant that the other work you did recently seems (to me) to be in roughly the same "category" of functionality, and that it was also proof that there's not a whole lot of distance to close as far as the actual code required to implement it in FPC with regards to that kind of thing.

Ryan Joseph
to Sven Barth
On Nov 12, 2018, at 5:06 AM, Sven Barth via fpc-pascal wrote: The compiler now correctly rejects such declarations with a "Type is not completely defined error".

But this syntax worked if you assigned it within blocks. Why does it need to be removed? Since I discovered it I was planning on using it instead of class functions with default values which require an implementation and are much longer to write.

Regards,
Ryan Joseph

Ryan Joseph
to Ryan Joseph
On Nov 12, 2018, at 8:08 AM, Ryan Joseph wrote: But this syntax worked if you assigned it within blocks. Why does it need to be removed? Since I discovered it I was planning on using it instead of class functions with default values which require an implementation and are much longer to write.

Here’s an example of what I was doing before. A constant is so much better and doesn’t require the implementation and we still get the same . syntax, i.e., TPoint.Up.

Instead of removing it maybe give the error unless it’s the last field of the record and in which case can assumed to be fully defined.

type
  TPoint = record
    x: TFloat;
    y: TFloat;
    class function Up (_x: TFloat = 0; _y: TFloat = -1): TPoint; static; inline;

Regards,
Ryan Joseph

Sven Barth
to Ryan Joseph

Am Mo., 12. Nov. 2018, 02:56 hat Ryan Joseph
geschrieben:

Show quoted text 17 lines
> On Nov 12, 2018, at 8:08 AM, Ryan Joseph wrote: > > But this syntax worked if you assigned it within blocks. Why does it need to be removed? Since I discovered it I was planning on using it instead of class functions with default values which require an implementation and are much longer to write. Here’s an example of what I was doing before. A constant is so much better and doesn’t require the implementation and we still get the same . syntax, i.e., TPoint.Up. Instead of removing it maybe give the error unless it’s the last field of the record and in which case can assumed to be fully defined.

No, that is too random for a language.
This change is not up for discussion as it could lead to incorrect code.

Regards,
Sven

Martok
to Ryan Joseph: This also fails. type TMyRecord = record public a: integer; b: string; end; const…
Ryan Joseph wrote
This also fails.

I personally find this case much more limiting.

Another implication is that you can't build up consts from other record consts, such as:

------------------------------
type
	TMyRecord = record
			a: integer;
			b: string;
	end;
const
	TMyRecord_Default: TMyRecord = (a: 100; b: 'foo');
	TMyRecord_Another: TMyRecord = (a: 200; b: 'bar');

SomeRecords: array[0..1] of TMyRecord = (
TMyRecord_Default,

	  TMyRecord_Another);

------------------------------
There is a pointer hack to get around that, but it would be really useful if this worked out of the box.

And yes, I know this is because record consts are (writeable, at worst) typed consts and as such are only preinitialized global variables, not true consts, but it still bothers me...

Regards, Martok
John Doe
to Sven Barth: Am Mo., 12. Nov. 2018, 02:56 hat Ryan Joseph geschrieben: No, that is too random for a…

On Mon, Nov 12, 2018 at 1:51 AM Sven Barth via fpc-pascal <

Show quoted text 5 lines
wrote: The compiler now correctly rejects such declarations with a "Type is not completely defined error".

Making this not work is a ridiculous removal of a feature for no logical reason that serves no benefit to anyone whatsoever. It just makes records less useful, and that's it.

I've already encountered several large libraries that are pretty massively broken by this pointless change. You're very visibly just making up arbitrary "rules" out of nowhere that certainly aren't actually defined anywhere and implementing (or de-implementing) whatever strikes your fancy on a given day.

Also:

On Sat, Nov 10, 2018 at 4:56 AM Sven Barth via fpc-pascal <

wrote: It's not possible to use typed constants as initializers for variables.

What are you talking about? Of course that's possible. People do it literally all the time.

Sven Barth
to John Doe
John Doe wrote 11 lines
On Mon, Nov 12, 2018 at 1:51 AM Sven Barth via fpc-pascal < > wrote: The compiler now correctly rejects such declarations with a "Type is not completely defined error". Making this not work is a ridiculous removal of a feature for no logical reason that serves no benefit to anyone whatsoever. It just makes records less useful, and that's it.

Just to avoid any confusion: I am talking about a typed constant declared inside a record's declaration of the same type as the record. Constants outside a record, even inside other records work as before. Also there can't be that many libraries affected, because this only ever worked in trunk. In 3.0.x the compiler simply crashed when encountering such a constant.

Show quoted text 19 lines
I've already encountered several large libraries that are pretty massively broken by this pointless change. You're very visibly just making up arbitrary "rules" out of nowhere that certainly aren't actually defined anywhere and implementing (or de-implementing) whatever strikes your fancy on a given day. Also: On Sat, Nov 10, 2018 at 4:56 AM Sven Barth via fpc-pascal < > wrote: It's not possible to use typed constants as initializers for variables. What are you talking about? Of course that's possible. People do it literally all the time.

=== code begin ===

type
   TTest = record
   public
     a: LongInt;
     b: LongInt;
   public //const
     //Default: array of TTest;// = (a: 42; b: 21);
   end;
const
   Test: TTest = (a: 42; b: 21);
var
   TestVar: TTest = Test; // <<<< this fails, because typed constants
can't be used as initializers (would also be the case if Test and
TestVar had any other type; only untyped constants are supported here)

=== code end ===

Regards,
Sven

Benjamin Rosseaux
to Ryan Joseph: Should’t this work? This would be a good way to set default record values but it…
program Test123;
{$ifdef fpc}
  {$mode delphi}
{$endif}
type
  TTest = record
  public
    a: LongInt;
    b: LongInt;
  end;
  TTestHelper = record helper for TTest
  public
    const Default: TTest = (a: 1; b: 2);
  end;
var
  Test: TTest;
begin
  Test := TTest.Default;
end.
AM Ryan Joseph wrote 23 lines
Should’t this work? This would be a good way to set default record values but it doesn’t seem to be supported. type TMyRecord = record public a: integer; b: string; const default: TMyRecord = (a: 100; b: 'foo'); end; var r: TMyRecord = TMyRecord.default; Regards, Ryan Joseph _______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Sven Barth
to Benjamin Rosseaux
Benjamin Rosseaux wrote 23 lines
program Test123; {$ifdef fpc}   {$mode delphi} {$endif} type   TTest = record   public     a: LongInt;     b: LongInt;   end;   TTestHelper = record helper for TTest   public     const Default: TTest = (a: 1; b: 2);   end; var   Test: TTest; begin   Test := TTest.Default; end.

That is indeed a good idea and with the extension to allow multiple helpers there wouldn't even be a negative impact... 🤔

Regards,
Sven

Benjamin Rosseaux
to Sven Barth

I'm using this solution myself for the vector and matrix data types at

https://github.com/BeRo1985/pasvulkan/blob/master/src/PasVulkan.Math.pas https://github.com/BeRo1985/pasvulkan/blob/master/src/PasVulkan.Math.TpvVector2.Swizzle.Definitions.inc https://github.com/BeRo1985/pasvulkan/blob/master/src/PasVulkan.Math.TpvVector2.Swizzle.Implementations.inc https://github.com/BeRo1985/pasvulkan/blob/master/src/PasVulkan.Math.TpvVector2Helper.Swizzle.Definitions.inc https://github.com/BeRo1985/pasvulkan/blob/master/src/PasVulkan.Math.TpvVector2Helper.Swizzle.Implementations.inc https://github.com/BeRo1985/pasvulkan/blob/master/src/PasVulkan.Math.TpvVector3.Swizzle.Definitions.inc https://github.com/BeRo1985/pasvulkan/blob/master/src/PasVulkan.Math.TpvVector3.Swizzle.Implementations.inc https://github.com/BeRo1985/pasvulkan/blob/master/src/PasVulkan.Math.TpvVector3Helper.Swizzle.Definitions.inc https://github.com/BeRo1985/pasvulkan/blob/master/src/PasVulkan.Math.TpvVector3Helper.Swizzle.Implementations.inc https://github.com/BeRo1985/pasvulkan/blob/master/src/PasVulkan.Math.TpvVector4.Swizzle.Definitions.inc https://github.com/BeRo1985/pasvulkan/blob/master/src/PasVulkan.Math.TpvVector4.Swizzle.Implementations.inc https://github.com/BeRo1985/pasvulkan/blob/master/src/PasVulkan.Math.TpvVector4Helper.Swizzle.Definitions.inc https://github.com/BeRo1985/pasvulkan/blob/master/src/PasVulkan.Math.TpvVector4Helper.Swizzle.Implementations.inc

without any bigger issues, except that the Delphi IDE has some runtime CodeInsight record lookup issues from time to time.

On Wed, Nov 28, 2018 at 8:47 PM Sven Barth via fpc-pascal <

Show quoted text 35 lines
wrote: Am 28.11.2018 um 20:27 schrieb Benjamin Rosseaux: program Test123; {$ifdef fpc} {$mode delphi} {$endif} type TTest = record public a: LongInt; b: LongInt; end; TTestHelper = record helper for TTest public const Default: TTest = (a: 1; b: 2); end; var Test: TTest; begin Test := TTest.Default; end. That is indeed a good idea and with the extension to allow multiple helpers there wouldn't even be a negative impact... 🤔 Regards, Sven _______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Ryan Joseph
to Benjamin Rosseaux: program Test123; {$ifdef fpc} {$mode delphi} {$endif} type TTest = record public a:…
Show quoted text 6 lines
On Nov 29, 2018, at 2:27 AM, Benjamin Rosseaux wrote: TTestHelper = record helper for TTest public const Default: TTest = (a: 1; b: 2); end;

I didn’t even know you could add consts to record helpers. That’s good to know, thanks.

Multi scoped helpers will make this a safe solution which you don’t have to worry about being overwritten in other units. Hopefully I can submit a patch for the trunk soon.

Regards,
Ryan Joseph