Sign in Join

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

Mailing lists / fpc-pascal / 2017-04

Record operator for assignment

18 messages · 7 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Ryan Joseph

Instead of making constructors and doing busy work It would be nice if Free Pascal could let you assign records outside of type blocks like:

rec := (x: 0; y: 0; z: 0);

Why isn’t this possible btw? I saw some C++ code do this and it seems like an obvious solution that should have existed 20 years ago. The feature exists for type blocks so why not just enable it for other parts of code?

I had another idea to make this a little simpler by using open arrays and operator overloading. The compiler doesn’t permit this however. Is it a bug, my code or just a limitation?

============

type
	TMyRec = record
		x, y, z: integer;
		class operator Explicit(v: array of integer): TMyRec;
	end;
class operator TMyRec.Explicit(v: array of integer): TMyRec;
begin
	result.x := v[0];
	result.y := v[1];
	result.z := v[2];
end;
var
	rec: TMyRec;
rec := TMyRec([1, 2, 3]); // Illegal type conversion: "Set Of Byte" to "TMyRec"

Regards,
Ryan Joseph

Reply by email

LacaK
to Ryan Joseph
Instead of making constructors and doing busy work It would be nice if Free Pascal could let you assign records outside of type blocks like: rec := (x: 0; y: 0; z: 0);

you can workaround this by using typed constant for instance. Something like:

const
   DEFAULT_REC: TMyRec = (x: 0; y: 0; z: 0 );
var
   rec: TMyRec;
begin
   rec := DEFAULT_REC; // or rec := Default(TMyRec) if you want zeroes
   ...

L.

Reply by email

Ryan Joseph
to LacaK
Show quoted text 13 lines
On Apr 28, 2017, at 12:21 PM, LacaK wrote: you can workaround this by using typed constant for instance. Something like: const DEFAULT_REC: TMyRec = (x: 0; y: 0; z: 0 ); var rec: TMyRec; begin rec := DEFAULT_REC; // or rec := Default(TMyRec) if you want zeroes ... L.

Run time is the problem though. If the compiler knows how to define a record using that syntax you should be able to do

rec := (x: a; y: b; z: c);

instead of mucking around with constructors which do basically the same thing but with boiler plate code. The syntax for a default constructor already exists in the language but it’s not implemented outside of type declarations for some reason.

Regards,
Ryan Joseph

Reply by email

Sven Barth
to Ryan Joseph: Instead of making constructors and doing busy work It would be nice if Free Pascal could…
"Ryan Joseph" wrote
Instead of making constructors and doing busy work It would be nice if

Free Pascal could let you assign records outside of type blocks like:

rec := (x: 0; y: 0; z: 0); Why isn’t this possible btw? I saw some C++ code do this and it seems

like an obvious solution that should have existed 20 years ago. The feature exists for type blocks so why not just enable it for other parts of code?

It would introduce an ambiguity as "(x" could also complete to other expressions (e.g. "(x + y) * 2" or even merely "(x)"). Especially older Pascal compilers were geared towards the simplicity of the language and thus they didn't add it. For FPC it simply never came up.

I had another idea to make this a little simpler by using open arrays and

operator overloading. The compiler doesn’t permit this however. Is it a bug, my code or just a limitation?

Show quoted text 22 lines
============ type TMyRec = record x, y, z: integer; class operator Explicit(v: array of integer): TMyRec; end; class operator TMyRec.Explicit(v: array of integer): TMyRec; begin result.x := v[0]; result.y := v[1]; result.z := v[2]; end; var rec: TMyRec; rec := TMyRec([1, 2, 3]); // Illegal type conversion: "Set Of Byte" to

"TMyRec"

The compiler currently prefers to cast array constructors towards sets, especially if they contain values that could be expressed as a set. That will change once proper support for array constructors is added. Though I don't know whether this would work then ;)

Regards,
Sven

Reply by email

Ryan Joseph
to Sven Barth
On Apr 28, 2017, at 12:43 PM, Sven Barth via fpc-pascal wrote: It would introduce an ambiguity as "(x" could also complete to other expressions (e.g. "(x + y) * 2" or even merely "(x)"). Especially older Pascal compilers were geared towards the simplicity of the language and thus they didn't add it. For FPC it simply never came up.

I never thought about it either until I saw some c++ code doing it. Despite having overlooked it, it’s basically a built in record constructor that’s been in the language since forever. First it was making functions that paired with records and now it’s constructors and "advanced record syntax" when the more obvious and simpler solution was there all along. Maybe I’m crazy though. ;)

You mean like:

rec := (x: (x + y) * 2; y: 0; z: 0);

Why can’t everything between : and ; just be treated like a normal assignment? “x” is already defined but it’s just a label and not part of the assignment.

The compiler currently prefers to cast array constructors towards sets, especially if they contain values that could be expressed as a set. That will change once proper support for array constructors is added. Though I don't know whether this would work then ;)

Huh, that syntax works in constructors, just not in the operator overloading. Anyways I guess I’ll just assume that’s not implemented behavior.

Thanks.

Regards,
Ryan Joseph

Reply by email

Sven Barth
to Ryan Joseph
Ryan Joseph wrote 10 lines
> On Apr 28, 2017, at 12:43 PM, Sven Barth via fpc-pascal wrote: > > It would introduce an ambiguity as "(x" could also complete to other expressions (e.g. "(x + y) * 2" or even merely "(x)"). Especially older Pascal compilers were geared towards the simplicity of the language and thus they didn't add it. For FPC it simply never came up. I never thought about it either until I saw some c++ code doing it. Despite having overlooked it, it’s basically a built in record constructor that’s been in the language since forever. First it was making functions that paired with records and now it’s constructors and "advanced record syntax" when the more obvious and simpler solution was there all along. Maybe I’m crazy though. ;) You mean like: rec := (x: (x + y) * 2; y: 0; z: 0);

No, I mean

rec := (x + y) * 2;

The compiler has to differentiate these two.

Why can’t everything between : and ; just be treated like a normal assignment? “x” is already defined but it’s just a label and not part of the assignment.

And that's another point. The compiler does not know what "x", "y" and "z" are, cause it doesn't care about the left hand side of the assignment until *after* the right hand side is parsed (in a var/const section it knows the type; that's a different situation). So a different syntax would be needed that would allow the compiler to know that it's parsing a specific record type.

> > The compiler currently prefers to cast array constructors towards sets, especially if they contain values that could be expressed as a set. That will change once proper support for array constructors is added. Though I don't know whether this would work then ;) Huh, that syntax works in constructors, just not in the operator overloading. Anyways I guess I’ll just assume that’s not implemented behavior.

Because in that case it knows that it's a parameter and handles that differently. A type conversion is a different case.

Regards,
Sven

Reply by email

Ryan Joseph
to Sven Barth
Show quoted text 7 lines
On Apr 28, 2017, at 1:06 PM, Sven Barth via fpc-pascal wrote: No, I mean rec := (x + y) * 2; The compiler has to differentiate these two.

I see. It’s the parenthesis that are problematic. I guess the solution would be curly brackets:

rec := {x: 1; y: 2; z: 1}

or some magic function like writeln:

rec := TMyRec(x: 1; y: 2; z: 1)
rec := @(x: 1; y: 2; z: 1)

etc…

Anyway it could be achieved that would be nice to have a built in constructor for records on the language level.

Regards,
Ryan Joseph

Reply by email

LacaK
to Ryan Joseph
Show quoted text 11 lines
I see. It’s the parenthesis that are problematic. I guess the solution would be curly brackets: rec := {x: 1; y: 2; z: 1} or some magic function like writeln: rec := TMyRec(x: 1; y: 2; z: 1) rec := @(x: 1; y: 2; z: 1) etc…
or use like dynamic array constructor:
(MyArr := TMyDynArrType.Create(value1, value2) );)
rec := TMyRec.Create(x: 1; y: 2; z: 1);

;-)
-Laco.

Reply by email

Sven Barth
to Ryan Joseph: I see. It’s the parenthesis that are problematic. I guess the solution would be curly…
"Ryan Joseph" wrote 12 lines
> On Apr 28, 2017, at 1:06 PM, Sven Barth via fpc-pascal < wrote: > > No, I mean > > rec := (x + y) * 2; > > The compiler has to differentiate these two. I see. It’s the parenthesis that are problematic. I guess the solution

would be curly brackets:

rec := {x: 1; y: 2; z: 1}

Curly brackets are comments!

or some magic function like writeln: rec := TMyRec(x: 1; y: 2; z: 1)

That could be a possibility as the compiler could then correctly handle the field names, however it would have an ambiguity with typecasts until the colon.
Though that would be solvable...

rec := @(x: 1; y: 2; z: 1)

@ would be nonsense as that would denote a pointer.

etc… Anyway it could be achieved that would be nice to have a built in

constructor for records on the language level.

Well, feel free to develop a patch, maybe it'll be accepted. I have other fish to fry in the meantime.

Regards,
Sven

Reply by email

Mark Morgan Lloyd
to Ryan Joseph: Instead of making constructors and doing busy work It would be nice if Free Pascal could…
Ryan Joseph wrote
Instead of making constructors and doing busy work It would be nice if Free Pascal could let you assign records outside of type blocks like: rec := (x: 0; y: 0; z: 0); Why isn’t this possible btw? I saw some C++ code do this and it seems like an obvious solution that should have existed 20 years ago. The feature exists for type blocks so why not just enable it for other parts of code? I had another idea to make this a little simpler by using open arrays and operator overloading. The compiler doesn’t permit this however. Is it a bug, my code or just a limitation?

Curiously, I was up against exactly the same thing yesterday when setting up an array for GetLongOpts() and a table for tokenising some other text elements.

I ended up using a dynamic array and overloading + for the first of those since it allowed me to do

   with option do begin
     name := 'block';
     value := name[1]   <===
   end;
   theOpts += option;

which wouldn't be available at compilation time, and also since build-time directives could easily include/exclude options. For the other one I used an array of records.

The problem with arrays of records as I see it is that the number of elements has to be predefined:

const   TopMatchItem= 10;
type    TMatchItem= record
                       name: string;
                       field: TCSVField
                     end;
         TAMatchItem= array[0..TopMatchItem] of TMatchItem;

const matchItems: TAMatchItem= ((name: ''; field: CSVBad), (name: 'block'; field: CSVBlock),
..

Or from the FPC compiler itself:

   ttokenarray=array[ttoken] of tokenrec;
   ptokenarray=^ttokenarray;
..

const
arraytokeninfo : ttokenarray =(
(str:'' ;special:true ;keyword:[m_none];op:NOTOKEN), ..

Is there any way that the length of an array being used for that sort of job can be defined by what's put into it, rather than having to be predefined?

Mark Morgan Lloyd markMLl .AT. telemetry.co .DOT. uk [Opinions above are the author's, not those of his employers or colleagues]

Reply by email

Sven Barth
to Mark Morgan Lloyd

Am 28.04.2017 14:09 schrieb "Mark Morgan Lloyd" <

: Is there any way that the length of an array being used for that sort of

job can be defined by what's put into it, rather than having to be predefined?

No, there is not. Though I already had the idea that such preinitialized dynamic arrays (because that's what they'd need to be for consistency) could be implemented. Alas that's another small point on my huge ToDo list... :/

Regards,
Sven

Reply by email

Ryan Joseph
On Apr 28, 2017, at 3:51 PM, Ryan Joseph wrote: I almost struck out there. ;) There’s at least a possibility for anyone interested. A few years ago I looked at the compiler source and decided it was beyond me to even understand the code base well enough to do anything. How do people get into this any ways? The learning curve is so steep it’s a miracle anyone is able to contribute.

I was looking at a Swift language guide (Apple’s new language) and they have this exact same syntax for initializing structs (like a default constructor that Pascal is missing).

From their guide “vga" is a struct with 2 fields: width and height. Swift uses labels in functions (like Objective-C) but the end result is that it looks identical to the Pascal syntax for defining constant records.

======

All structures have an automatically-generated memberwise initializer, which you can use to initialize the member properties of new structure instances. Initial values for the properties of the new instance can be passed to the memberwise initializer by name:

var vga = Resolution(width: 640, height: 480)

Regards,
Ryan Joseph

Reply by email

Marco van de Voort
to Ryan Joseph

In our previous episode, Ryan Joseph said:

All structures have an automatically-generated memberwise initializer, which you can use to initialize the member properties of new structure instances. Initial values for the properties of the new instance can be passed to the memberwise initializer by name: var vga = Resolution(width: 640, height: 480)

Scripting languages often already by default initialize a datatructure, and then such language constructs only performs additional initialization.

Pascal and similar lowlevel languages don't by default initialize them, and then whole initialization is more logical.

Reply by email

Ryan Joseph
to Marco van de Voort
Show quoted text 7 lines
On May 4, 2017, at 4:27 PM, Marco van de Voort wrote: Scripting languages often already by default initialize a datatructure, and then such language constructs only performs additional initialization. Pascal and similar lowlevel languages don't by default initialize them, and then whole initialization is more logical.

It’s optional and basically just a default constructor which takes all fields as it’s arguments. You don’t need to call it if you don’t want. Swift is compiled afaik but it does way more behind the scenes than I’d like Pascal to do and does behave like a scripting language in many ways (inferred types for example). That being said Pascal records should still have a default constructor since this is a pattern repeated extremely frequently.

Regards,
Ryan Joseph

Reply by email

Sven Barth
to Ryan Joseph: I was looking at a Swift language guide (Apple’s new language) and they have this exact…
"Ryan Joseph" wrote
> On Apr 28, 2017, at 3:51 PM, Ryan Joseph
> > I almost struck out there. ;) There’s at least a possibility for anyone

interested. A few years ago I looked at the compiler source and decided it was beyond me to even understand the code base well enough to do anything. How do people get into this any ways? The learning curve is so steep it’s a miracle anyone is able to contribute.

One starts with something simple and works one's way up. My first real compiler contribution were if I remember correctly class helpers. And at that time I knew next to nothing about the compiler and thus had to learn by doing and debugging.

Regards,
Sven

Reply by email

Unknown author
to Ryan Joseph: I never thought about it either until I saw some c++ code doing it. Despite having…
Ryan Joseph wrote 11 lines
> On Apr 28, 2017, at 12:43 PM, Sven Barth via fpc-pascal > wrote: > > It would introduce an ambiguity as "(x" could also complete to other > expressions (e.g. "(x + y) * 2" or even merely "(x)"). Especially > older Pascal compilers were geared towards the simplicity of the > language and thus they didn't add it. For FPC it simply never came up. I never thought about it either until I saw some c++ code doing it. Despite having overlooked it, it’s basically a built in record constructor that’s been in the language since forever.

You can also look into GoLang for struct ideas, as golang is simpler than C++

Show quoted text 6 lines
rec := (x: (x + y) * 2; y: 0; z: 0); Why can’t everything between : and ; just be treated like a normal assignment? “x” is already defined but it’s just a label and not part of the assignment.

It's always easier said than done, to say "Why can't" and then have to write the actual parser code to do it ;-)

I think fpc is based on wirth's simplicity, and even wirth's languages probably did not have the ability to setup a record initially with default record as another poster said. I do like this feature a lot , but can see why a minimalist like worth would avoid it.

It's similar to this feature:

x,y,z := 1, 12, 7

It's neat to be able to assign multiple variables on a single line. But necessary? mandatory?
Again, could look into golang for ideas.. may have something like it too, without becoming a large C++ mammoth.

In fact that's how golang's error checking works.

Reply by email

Ryan Joseph
to Unknown author
On May 8, 2017, at 10:47 AM, wrote: It's always easier said than done, to say "Why can't" and then have to write the actual parser code to do it ;-)

Yes indeed. I just looked over svn to see where Sven added his new dynamic array initializers and I’m still totally confused. It’s really a miracle anyone is able to contribute to such a large code base without any documentation.

Since we have record constructors and static class functions for records now it seems like the language is going out of its way to provide the simplest solution.

Yeah Golang has the same thing: c := Circle{x: 0, y: 0, r: 5} and basically the same syntax as Pascal or Swift.

Regards,
Ryan Joseph

Reply by email

Jürgen Hestermann
to Unknown author: You can also look into GoLang for struct ideas, as golang is simpler than C++ It's always…

Am 2017-05-08 um 05:47 schrieb

It's similar to this feature: x,y,z := 1, 12, 7 It's neat to be able to assign multiple variables on a single line. But necessary? mandatory?

It's not even neat.
It would bloat the Pascal language unneccesarily (as many other additions have done in the past).

I definitely prefer

x :=  1;
y := 12;
z :=  7;

where I see much better which value is assigned to which variable. Look at this:

a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u := 3,5,1,7,33,82,7,14,9,0,-1,1,13,14,17,8,2,9,15,88,62;

would that be readable code?

Reply by email