Sign in Join

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

Mailing lists / fpc-devel / 2024-06

pure function feedback

14 messages · 5 people · –

Reply by email Subscribe to this list Your subscription

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

Marģers .
1. pure function value to constants function foo(i:longword):longword; pure; begin   foo:=9; end; const bar = foo( 8 );  //-- not allowed.. but i expect this to work!          jar : longword = foo( 7 ); //-- and this as well 2. this does not end grasefully function foo (i:longword):shortstring; pure; var s : shortstring;       n : longword; begin   s:=''';   for n:=1 to i do s:=s +'a';   //-- not assing return value end; begin writeln(foo(9)); end. 3. function foo (i:longword):ansistring; pure; var s : shortstring;       n : longword; begin   s:=''';   for n:=1 to i do s:=s +'a';   foo:=s; //-- this makes function not pure, but why whould it! end; begin writeln(foo(9)); end.  

Reply by email

J. Gareth Moreton
to Marģers .

Hi Marģers,

Thanks for the feedback!

Assigning the results of pure functions to constants has not yet been developed.  I had planned to add it once the bulk of pure functions (i.e. the current merge request) had been approved since it requires some additional work (specifically what happens if the function is not actually pure or otherwise can't return a straightforward result).

2 and 3 are definite bugs though.  The second case should at the very least make the function impure, while the third case should indeed not disqualify the function.  I'll see what I can do. Thanks again.

Kit

Marģers . wrote 38 lines
1. pure function value to constants function foo(i:longword):longword; pure; begin   foo:=9; end; const bar = foo( 8 );  //-- not allowed.. but i expect this to work!          jar : longword = foo( 7 ); //-- and this as well 2. this does not end grasefully function foo (i:longword):shortstring; pure; var s : shortstring;       n : longword; begin   s:=''';   for n:=1 to i do s:=s +'a';   //-- not assing return value end; begin writeln(foo(9)); end. 3. function foo (i:longword):ansistring; pure; var s : shortstring;       n : longword; begin   s:=''';   for n:=1 to i do s:=s +'a';   foo:=s; //-- this makes function not pure, but why whould it! end; begin writeln(foo(9)); end. _______________________________________________ fpc-devel maillist - https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
This email has been checked for viruses by Avast antivirus software. www.avast.com

Reply by email

J. Gareth Moreton
to J. Gareth Moreton

Fixed 2 and 3.

- 2 was due to not handling block nodes properly when they didn't have any statements (data-flow analysis stripped the procedure completely clean since no result was set), hence an access violation occurred while accessing a node that was nil.

- 3 was a two-fold problem:

1. The functiuon being ineligible was because a typeconv node couldn't be stripped out and so the final assignment tree wasn't in an expected format.  The analysis code now specifically permits this form of type conversion (convtype = tc_equal and identical resultdefs between the typeconv and the load nodes).
2. The second problem was due to a small hack where implicit Result parameters were converted from var to out so data-flow analysis worked properly, but they weren't converted back to var parameters afterwards, causing an access violation elsewhere in the code.

Merge request has been updated - I have also added two new tests based on your examples.  Thanks again Marģers.

Kit

J. Gareth Moreton wrote 56 lines
Hi Marģers, Thanks for the feedback! Assigning the results of pure functions to constants has not yet been developed.  I had planned to add it once the bulk of pure functions (i.e. the current merge request) had been approved since it requires some additional work (specifically what happens if the function is not actually pure or otherwise can't return a straightforward result). 2 and 3 are definite bugs though.  The second case should at the very least make the function impure, while the third case should indeed not disqualify the function.  I'll see what I can do. Thanks again. Kit On 28/06/2024 09:35, Marģers . via fpc-devel wrote: > 1. pure function value to constants > > function foo(i:longword):longword; pure; > begin >   foo:=9; > end; > > const bar = foo( 8 );  //-- not allowed.. but i expect this to work! >          jar : longword = foo( 7 ); //-- and this as well > > > 2. this does not end grasefully > > function foo (i:longword):shortstring; pure; > var s : shortstring; >       n : longword; > begin >   s:='''; >   for n:=1 to i do s:=s +'a'; >   //-- not assing return value > end; > begin writeln(foo(9)); end. > > 3. > function foo (i:longword):ansistring; pure; > var s : shortstring; >       n : longword; > begin >   s:='''; >   for n:=1 to i do s:=s +'a'; >   foo:=s; //-- this makes function not pure, but why whould it! > end; > begin writeln(foo(9)); end. > > > _______________________________________________ > fpc-devel maillist  - > https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
This email has been checked for viruses by Avast antivirus software. www.avast.com

Reply by email

Hairy Pixels
to J. Gareth Moreton

I had a question about pure functions. I'm seeing some newer languages have a JIT built-in so they can run any function at compile time. To get results at compile time you probably need to use a constant for the parameters but in theory it could read/write to global variables so it's not really "pure" but still makes it possible to run functions at compile time.

How does this compare to pure functions? It seems like the JIT is actually easier to implement than all this complicated node analysis, but probably slower to run I may guess. I think the LLVM backend could do this but the main code generator I'm not sure.

Show quoted text 64 lines
On Jun 30, 2024, at 9:17 AM, J. Gareth Moreton via fpc-devel wrote: Fixed 2 and 3. - 2 was due to not handling block nodes properly when they didn't have any statements (data-flow analysis stripped the procedure completely clean since no result was set), hence an access violation occurred while accessing a node that was nil. - 3 was a two-fold problem: • The functiuon being ineligible was because a typeconv node couldn't be stripped out and so the final assignment tree wasn't in an expected format. The analysis code now specifically permits this form of type conversion (convtype = tc_equal and identical resultdefs between the typeconv and the load nodes). • The second problem was due to a small hack where implicit Result parameters were converted from var to out so data-flow analysis worked properly, but they weren't converted back to var parameters afterwards, causing an access violation elsewhere in the code. Merge request has been updated - I have also added two new tests based on your examples. Thanks again Marģers. Kit On 28/06/2024 13:24, J. Gareth Moreton via fpc-devel wrote: > Hi Marģers, > > Thanks for the feedback! > > Assigning the results of pure functions to constants has not yet been developed. I had planned to add it once the bulk of pure functions (i.e. the current merge request) had been approved since it requires some additional work (specifically what happens if the function is not actually pure or otherwise can't return a straightforward result). > > 2 and 3 are definite bugs though. The second case should at the very least make the function impure, while the third case should indeed not disqualify the function. I'll see what I can do. Thanks again. > > Kit > > On 28/06/2024 09:35, Marģers . via fpc-devel wrote: >> 1. pure function value to constants >> >> function foo(i:longword):longword; pure; >> begin >> foo:=9; >> end; >> >> const bar = foo( 8 ); //-- not allowed.. but i expect this to work! >> jar : longword = foo( 7 ); //-- and this as well >> >> >> 2. this does not end grasefully >> >> function foo (i:longword):shortstring; pure; >> var s : shortstring; >> n : longword; >> begin >> s:='''; >> for n:=1 to i do s:=s +'a'; >> //-- not assing return value >> end; >> begin writeln(foo(9)); end. >> >> 3. >> function foo (i:longword):ansistring; pure; >> var s : shortstring; >> n : longword; >> begin >> s:='''; >> for n:=1 to i do s:=s +'a'; >> foo:=s; //-- this makes function not pure, but why whould it! >> end; >> begin writeln(foo(9)); end. >> >> >> _______________________________________________ >> fpc-devel maillist - >> https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel > Virus-free.www.avast.com _______________________________________________ fpc-devel maillist - https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel

Regards,
Ryan Joseph

Reply by email

J. Gareth Moreton
to Hairy Pixels

The main concept of pure functions is that they have no side-effects (e.g. don't affect a global state or rely on I/O) and are analogous to a mathematical function.  The main things to draw from it are that for constant inputs, the output is deterministic and can be calculated at compile time (thus replacing the entire call with the result), and for the same inputs, it always produces the same output.

For example, if you have something like: "if (purefunc(X) > Y) and (purefunc(X) < Z) then"... if Z > Y then, even if X is an unknown variable, this can be restructured by the compiler so "purefunc(X)" is only called once (to something akin to "if (purefunc(X) - Y) < (Z - Y) then").

I'm not sure how practical it is for Free Pascal to implement a JIT compiler, but currently there's no support for it.

There is an overhead with pure functions, so you don't really want to mark all functions as pure and let the compiler work it out.

Kit

Hairy Pixels wrote 73 lines
I had a question about pure functions. I'm seeing some newer languages have a JIT built-in so they can run any function at compile time. To get results at compile time you probably need to use a constant for the parameters but in theory it could read/write to global variables so it's not really "pure" but still makes it possible to run functions at compile time. How does this compare to pure functions? It seems like the JIT is actually easier to implement than all this complicated node analysis, but probably slower to run I may guess. I think the LLVM backend could do this but the main code generator I'm not sure. > On Jun 30, 2024, at 9:17 AM, J. Gareth Moreton via fpc-devel wrote: > > Fixed 2 and 3. > - 2 was due to not handling block nodes properly when they didn't have any statements (data-flow analysis stripped the procedure completely clean since no result was set), hence an access violation occurred while accessing a node that was nil. > - 3 was a two-fold problem: > • The functiuon being ineligible was because a typeconv node couldn't be stripped out and so the final assignment tree wasn't in an expected format. The analysis code now specifically permits this form of type conversion (convtype = tc_equal and identical resultdefs between the typeconv and the load nodes). > • The second problem was due to a small hack where implicit Result parameters were converted from var to out so data-flow analysis worked properly, but they weren't converted back to var parameters afterwards, causing an access violation elsewhere in the code. > Merge request has been updated - I have also added two new tests based on your examples. Thanks again Marģers. > Kit > On 28/06/2024 13:24, J. Gareth Moreton via fpc-devel wrote: >> Hi Marģers, >> >> Thanks for the feedback! >> >> Assigning the results of pure functions to constants has not yet been developed. I had planned to add it once the bulk of pure functions (i.e. the current merge request) had been approved since it requires some additional work (specifically what happens if the function is not actually pure or otherwise can't return a straightforward result). >> >> 2 and 3 are definite bugs though. The second case should at the very least make the function impure, while the third case should indeed not disqualify the function. I'll see what I can do. Thanks again. >> >> Kit >> >> On 28/06/2024 09:35, Marģers . via fpc-devel wrote: >>> 1. pure function value to constants >>> >>> function foo(i:longword):longword; pure; >>> begin >>> foo:=9; >>> end; >>> >>> const bar = foo( 8 ); //-- not allowed.. but i expect this to work! >>> jar : longword = foo( 7 ); //-- and this as well >>> >>> >>> 2. this does not end grasefully >>> >>> function foo (i:longword):shortstring; pure; >>> var s : shortstring; >>> n : longword; >>> begin >>> s:='''; >>> for n:=1 to i do s:=s +'a'; >>> //-- not assing return value >>> end; >>> begin writeln(foo(9)); end. >>> >>> 3. >>> function foo (i:longword):ansistring; pure; >>> var s : shortstring; >>> n : longword; >>> begin >>> s:='''; >>> for n:=1 to i do s:=s +'a'; >>> foo:=s; //-- this makes function not pure, but why whould it! >>> end; >>> begin writeln(foo(9)); end. >>> >>> >>> _______________________________________________ >>> fpc-devel maillist - >>> https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel > Virus-free.www.avast.com _______________________________________________ > fpc-devel maillist - > https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel Regards, Ryan Joseph _______________________________________________ fpc-devel maillist - https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
This email has been checked for viruses by Avast antivirus software. www.avast.com

Reply by email

Marco van de Voort
to Hairy Pixels: I had a question about pure functions. I'm seeing some newer languages have a JIT…

Op 1-7-2024 om 02:34 schreef Hairy Pixels via fpc-devel:

I had a question about pure functions. I'm seeing some newer languages have a JIT built-in so they can run any function at compile time. To get results at compile time you probably need to use a constant for the parameters but in theory it could read/write to global variables so it's not really "pure" but still makes it possible to run functions at compile time.

FPC has JIT backends like JVM.

Reply by email

J. Gareth Moreton
to Marco van de Voort

Aah, thanks Marco.  I still have some things to learn about FPC!

Kit

Marco van de Voort wrote 16 lines
Op 1-7-2024 om 02:34 schreef Hairy Pixels via fpc-devel: > I had a question about pure functions. I'm seeing some newer > languages have a JIT built-in so they can run any function at compile > time. To get results at compile time you probably need to use a > constant for the parameters but in theory it could read/write to > global variables so it's not really "pure" but still makes it > possible to run functions at compile time. FPC has JIT backends like JVM. _______________________________________________ fpc-devel maillist  -  https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
This email has been checked for viruses by Avast antivirus software. www.avast.com

Reply by email

Mattias Gaertner
to Marco van de Voort: Op 1-7-2024 om 02:34 schreef Hairy Pixels via fpc-devel: FPC has JIT backends like JVM.
Marco van de Voort wrote 10 lines
Op 1-7-2024 om 02:34 schreef Hairy Pixels via fpc-devel: > I had a question about pure functions. I'm seeing some newer languages > have a JIT built-in so they can run any function at compile time. To > get results at compile time you probably need to use a constant for > the parameters but in theory it could read/write to global variables > so it's not really "pure" but still makes it possible to run functions > at compile time. FPC has JIT backends like JVM.

But that is just the backend, FPC still works only at compile time, so no JIT at runtime possible. Is it?

Mattias

Reply by email

J. Gareth Moreton
to Mattias Gaertner

In the case of JVM, the JIT compiler is specific to Java, I think.  Normally JIT requires the source code to be compiled into an intermediate bytecode first (e.g. Java bytecode or the Common Intermediate Language (.NET)).

Kit

Mattias Gaertner wrote 22 lines
On 7/1/24 09:05, Marco van de Voort via fpc-devel wrote: > > Op 1-7-2024 om 02:34 schreef Hairy Pixels via fpc-devel: >> I had a question about pure functions. I'm seeing some newer >> languages have a JIT built-in so they can run any function at >> compile time. To get results at compile time you probably need to >> use a constant for the parameters but in theory it could read/write >> to global variables so it's not really "pure" but still makes it >> possible to run functions at compile time. > > FPC has JIT backends like JVM. But that is just the backend, FPC still works only at compile time, so no JIT at runtime possible. Is it? Mattias _______________________________________________ fpc-devel maillist  -  https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
This email has been checked for viruses by Avast antivirus software. www.avast.com

Reply by email

J. Gareth Moreton
to Mattias Gaertner: But that is just the backend, FPC still works only at compile time, so no JIT at runtime…

On a related note, I do wonder where pure functions might help with JIT.  It depends on what Florian and the other administrators and developers seek, but currently I aim for my pure function implementation to fulfil both standard properties (1. same output for the same input(s), and 2. no side-effects (usually interpreted as meaning reading from or writing to anything outside of its scope (e.g. global variables))).

Currently, you can define a function as pure and, as long as you don't have anything explicitly impure like a pointer deallocation, the compiler won't know for sure if it is pure or not until you try to call it with a constant parameter - then the compiler checks.  This may cause some issues if the function has a problem like an infinite loop or the result not being set on some branches, and which won't be detected unless you call the pure function with a constant input that triggers the condition.  I'm not sure what the best solution to this is.

Kit

Mattias Gaertner wrote 22 lines
On 7/1/24 09:05, Marco van de Voort via fpc-devel wrote: > > Op 1-7-2024 om 02:34 schreef Hairy Pixels via fpc-devel: >> I had a question about pure functions. I'm seeing some newer >> languages have a JIT built-in so they can run any function at >> compile time. To get results at compile time you probably need to >> use a constant for the parameters but in theory it could read/write >> to global variables so it's not really "pure" but still makes it >> possible to run functions at compile time. > > FPC has JIT backends like JVM. But that is just the backend, FPC still works only at compile time, so no JIT at runtime possible. Is it? Mattias _______________________________________________ fpc-devel maillist  -  https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
This email has been checked for viruses by Avast antivirus software. www.avast.com

Reply by email

Marco van de Voort
to Mattias Gaertner: But that is just the backend, FPC still works only at compile time, so no JIT at runtime…

Op 1-7-2024 om 10:33 schreef Mattias Gaertner via fpc-devel:

Show quoted text 6 lines
> FPC has JIT backends like JVM. But that is just the backend, FPC still works only at compile time, so no JIT at runtime possible. Is it?

Hmm, yes. You could maybe interface to the JVM and compile java that way. But I don't even know that is possible, i.e. if every Java VM can actually compile Java (rather than only bytecode), let alone that that wouldn't be FPC code.

Reply by email

J. Gareth Moreton
to Marģers .

Oh yes, that's a silly mistake!  Easy enough to fix hopefully.

Kit

Marģers . wrote 10 lines
> Fixed 2 and 3. Thank you. one more ... {\$ifdef FPU_HAS_PURE}pure;{\$ENDIF} FPU_HAS_PURE probably is typo and should be: FPC_HAS_PURE
This email has been checked for viruses by Avast antivirus software. www.avast.com

Reply by email

J. Gareth Moreton
to Marģers .:

Fixed!  Thanks again Marģers.

Kit

Marģers . wrote 10 lines
> Fixed 2 and 3. Thank you. one more ... {\$ifdef FPU_HAS_PURE}pure;{\$ENDIF} FPU_HAS_PURE probably is typo and should be: FPC_HAS_PURE
This email has been checked for viruses by Avast antivirus software. www.avast.com

Reply by email