Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Explain more on benefits/use-case of using is pure trait #1231

Closed
trosel opened this issue Mar 4, 2017 · 14 comments
Closed

Explain more on benefits/use-case of using is pure trait #1231

trosel opened this issue Mar 4, 2017 · 14 comments
Assignees
Labels
docs Documentation issue (primary issue type)

Comments

@trosel
Copy link
Contributor

trosel commented Mar 4, 2017

https://docs.perl6.org/routine/is%20pure

Even after reading about what constant-folding is, it's not clear why someone would need to explicitly mark this when the compiler can probably infer it on its own.

Is there a difference between using is pure on a sub that has a return value vs on a sub that doesn't have a return value?

@trosel trosel added the docs Documentation issue (primary issue type) label Mar 4, 2017
@AlexDaniel AlexDaniel reopened this Sep 3, 2017
@AlexDaniel
Copy link
Member

AlexDaniel commented Sep 3, 2017

Can somebody review what I just did? Does it resolve the issue?

@rafaelschipiura
Copy link
Contributor

Yep, makes it very clear.

AlexDaniel added a commit that referenced this issue Sep 3, 2017
@moritz moritz closed this as completed in fccff68 Sep 3, 2017
moritz added a commit that referenced this issue Sep 3, 2017
explain why the compiler cannot reliably infer purity on its own.
For issue #1231.
@JJ
Copy link
Contributor

JJ commented Sep 3, 2017 via email

@moritz moritz assigned JJ Sep 3, 2017
@moritz moritz reopened this Sep 3, 2017
@rafaelschipiura
Copy link
Contributor

@JJ Perl 6 can have composition, laziness and concurrency on normal functions just fine. The trait is used to change their performance characteristics, moving a runtime calculation (which could be cached at runtime too: https://docs.perl6.org/routine/is%20cached) into compilation time.

@moritz
Copy link
Collaborator

moritz commented Sep 3, 2017

@JJ feel free to provide a better example

@moritz moritz removed their assignment Sep 3, 2017
@JJ
Copy link
Contributor

JJ commented Sep 3, 2017 via email

@rafaelschipiura
Copy link
Contributor

@JJ I agree your idea is good, I was just trying to help find a good example.

@JJ
Copy link
Contributor

JJ commented Sep 3, 2017 via email

@rafaelschipiura
Copy link
Contributor

@JJ I just want you to note that the very example provided in the documentation has side effects and Perl6 has no problem with it, OK?

@zoffixznet zoffixznet removed their assignment Sep 4, 2017
@JJ
Copy link
Contributor

JJ commented Jan 24, 2018

I've come with a nice use case that includes pre-computing a set of things; however it involves using experimental macros. Would this be suitable? Or is it better if I think about a different one?
I'm not sure about phasers here. Would macro go before or after is pure evaluation? I'd have to check for that.
Without macros, all examples are going to be a variation of "call this function with a constant, then call another function with a constant". For producing constants at compile time in a reasonable way, that's what macros are for.

@AlexDaniel
Copy link
Member

however it involves using experimental macros. Would this be suitable?

No.

@zoffixznet
Copy link
Contributor

zoffixznet commented Jan 24, 2018

Would this be suitable?

👎 even if they weren't experimental. There's no need to daunt the user with a whole 'nother large language feature they'd have to be familiar with just to explain is pure

all examples are going to be a variation of "call this function with a constant

is pure routines don't need to be called with constants in examples. is pure is a hint and just because not all cases of routine call would use constants doesn't mean you can't mark it as pure. There are plenty of colourful routines in core that are marked as pure. Surely a reasonably-simple real-world example can be constructed with routines similar to them:

$ grep -FR 'is pure' src/
src/core/set_addition.pm:proto sub infix:<(+)>(|) is pure {*}
src/core/Range.pm:sub infix:<..>($min, $max) is pure {
src/core/Range.pm:sub infix:<^..>($min, $max) is pure {
src/core/Range.pm:sub infix:<..^>($min, $max) is pure {
src/core/Range.pm:sub infix:<^..^>($min, $max) is pure {
src/core/Range.pm:sub prefix:<^>($max) is pure {
src/core/set_subset.pm:proto sub infix:<<(<=)>>($, $ --> Bool:D) is pure {*}
src/core/set_subset.pm:only sub infix:<⊈>($a, $b --> Bool:D) is pure {
src/core/set_subset.pm:only sub infix:<⊇>($a, $b --> Bool:D) is pure {
src/core/set_subset.pm:only sub infix:<⊉>($a, $b --> Bool:D) is pure {
src/core/Pair.pm:sub infix:«=>»(Mu $key, Mu \value) is pure {
src/core/Pair.pm:sub pair(Mu $key, \value) is pure {
src/core/Stringy.pm:proto sub prefix:<~>($) is pure {*}
src/core/Stringy.pm:proto sub infix:<~>(|) is pure {*}
src/core/Stringy.pm:proto sub infix:<x>(Mu $?, Mu $?)  is pure {*}
src/core/Stringy.pm:proto sub infix:<leg>(Mu $?, Mu $?) is pure {*}
src/core/Stringy.pm:proto sub infix:<eq>(Mu $?, Mu $?)  is pure {*}
src/core/Stringy.pm:proto sub infix:<ne>(Mu $?, Mu $?) is pure {*}
src/core/Stringy.pm:proto sub infix:<lt>(Mu $?, Mu $?) is pure {*}
src/core/Stringy.pm:proto sub infix:<le>(Mu $?, Mu $?) is pure {*}
src/core/Stringy.pm:proto sub infix:<gt>(Mu $?, Mu $?) is pure {*}
src/core/Stringy.pm:proto sub infix:<ge>(Mu $?, Mu $?) is pure {*}
src/core/Stringy.pm:proto sub infix:<~|>(Mu $?, Mu $?) is pure {*}
src/core/Stringy.pm:proto sub infix:<~^>(Mu $?, Mu $?)  is pure {*}
src/core/Stringy.pm:proto sub infix:<~&>(Mu $?, Mu $?) is pure {*}
src/core/Stringy.pm:proto sub prefix:<~^>(Mu $) is pure {*}
src/core/set_elem.pm:proto sub infix:<(elem)>($, $ --> Bool:D) is pure {*}
src/core/set_elem.pm:only sub infix:<∉>($a, $b --> Bool:D) is pure {
src/core/set_elem.pm:only sub infix:<(cont)>($a, $b --> Bool:D) is pure { $b (elem) $a }
src/core/set_elem.pm:only sub infix:<∋>($a, $b --> Bool:D) is pure {
src/core/set_elem.pm:only sub infix:<∌>($a, $b --> Bool:D) is pure {
src/core/Cool.pm:proto sub rindex($, $, $?) is pure {*};
src/core/Cool.pm:proto sub ords($) is pure     {*}
src/core/Cool.pm:proto sub wordcase($) is pure {*}
src/core/Cool.pm:proto sub chars($) is pure {*}
src/core/Bool.pm:proto sub prefix:<?>(Mu $) is pure {*}
src/core/Bool.pm:proto sub prefix:<so>(Mu $) is pure {*}
src/core/Bool.pm:proto sub prefix:<!>(Mu $) is pure {*}
src/core/Bool.pm:proto sub prefix:<not>(Mu $) is pure {*}
src/core/Bool.pm:proto sub prefix:<?^>(Mu $) is pure {*}
src/core/Bool.pm:proto sub infix:<?&>(Mu $?, Mu $?) is pure {*}
src/core/Bool.pm:proto sub infix:<?|>(Mu $?, Mu $?) is pure {*}
src/core/Bool.pm:proto sub infix:<?^>(Mu $?, Mu $?) is pure {*}
src/core/Int.pm:proto sub chr($) is pure  {*}
src/core/Int.pm:sub is-prime(\x) is pure { x.is-prime }
src/core/Int.pm:proto sub expmod($, $, $) is pure  {*}
src/core/set_difference.pm:proto sub infix:<(-)>(|) is pure {*}
src/core/operators.pm:proto sub infix:<but>(|) is pure {*}
src/core/Any-iterable-methods.pm:proto sub infix:<min>(|) is pure {*}
src/core/Any-iterable-methods.pm:proto sub infix:<max>(|) is pure {*}
src/core/Any-iterable-methods.pm:proto sub infix:<minmax>(|) is pure {*}
src/core/set_multiply.pm:proto sub infix:<(.)>(|) is pure {*}
src/core/Numeric.pm:proto sub prefix:<+>($?) is pure {*}
src/core/Numeric.pm:proto sub prefix:<->($?) is pure {*}
src/core/Numeric.pm:proto sub abs($) is pure {*}
src/core/Numeric.pm:proto sub sign($) is pure {*}
src/core/Numeric.pm:proto sub log($, $?) is pure {*}
src/core/Numeric.pm:proto sub log10($, $?) is pure {*}
src/core/Numeric.pm:proto sub exp($, $?) is pure {*}
src/core/Numeric.pm:proto sub sin($) is pure {*}
src/core/Numeric.pm:proto sub asin($) is pure {*}
src/core/Numeric.pm:proto sub cos($) is pure {*}
src/core/Numeric.pm:proto sub acos($) is pure {*}
src/core/Numeric.pm:proto sub tan($) is pure {*}
src/core/Numeric.pm:proto sub atan($) is pure {*}
src/core/Numeric.pm:proto sub sec($) is pure {*}
src/core/Numeric.pm:proto sub asec($) is pure {*}
src/core/Numeric.pm:proto sub cosec($) is pure {*}
src/core/Numeric.pm:proto sub acosec(|) is pure {*}
src/core/Numeric.pm:proto sub cotan($) is pure {*}
src/core/Numeric.pm:proto sub acotan($) is pure {*}
src/core/Numeric.pm:proto sub sinh($) is pure {*}
src/core/Numeric.pm:proto sub asinh($) is pure {*}
src/core/Numeric.pm:proto sub cosh($) is pure {*}
src/core/Numeric.pm:proto sub acosh($) is pure {*}
src/core/Numeric.pm:proto sub tanh($) is pure {*}
src/core/Numeric.pm:proto sub atanh($) is pure {*}
src/core/Numeric.pm:proto sub sech($) is pure {*}
src/core/Numeric.pm:proto sub asech($) is pure {*}
src/core/Numeric.pm:proto sub cosech($) is pure {*}
src/core/Numeric.pm:proto sub acosech($) is pure {*}
src/core/Numeric.pm:proto sub cotanh($) is pure {*}
src/core/Numeric.pm:proto sub acotanh($) is pure {*}
src/core/Numeric.pm:proto sub sqrt($) is pure {*}
src/core/Numeric.pm:proto sub roots($, $) is pure {*}
src/core/Numeric.pm:proto sub floor($) is pure   {*}
src/core/Numeric.pm:proto sub ceiling($) is pure   {*}
src/core/Numeric.pm:proto sub round($, $?) is pure      {*}
src/core/Numeric.pm:proto sub infix:<+>(Mu $?, Mu $?) is pure   {*}
src/core/Numeric.pm:proto sub infix:<->(Mu $?, Mu $?) is pure   {*}
src/core/Numeric.pm:proto sub infix:<*>(Mu $?, Mu $?) is pure   {*}
src/core/Numeric.pm:sub infix:<×>(|c) is pure { infix:<*>(|c) }
src/core/Numeric.pm:proto sub infix:</>(Mu $?, Mu $?) is pure {*}
src/core/Numeric.pm:sub infix:<÷>(|c) is pure { infix:</>(|c) }
src/core/Numeric.pm:proto sub infix:<div>(Mu $?, Mu $?) is pure  {*}
src/core/Numeric.pm:proto sub infix:<%>(Mu $?, Mu $?) is pure   {*}
src/core/Numeric.pm:proto sub infix:<%%>(Mu $?, Mu $?) is pure  {*}
src/core/Numeric.pm:proto sub infix:<lcm>(Mu $?, Mu $?) is pure  {*}
src/core/Numeric.pm:proto sub infix:<gcd>(Mu $?, Mu $?) is pure {*}
src/core/Numeric.pm:proto sub infix:<**>(Mu $?, Mu $?) is pure  {*}
src/core/Numeric.pm:proto sub postfix:<ⁿ>(Mu $, Mu $) is pure  {*}
src/core/Numeric.pm:proto sub infix:«<=>»(Mu $, Mu $?) is pure {*}
src/core/Numeric.pm:proto sub infix:<==>(Mu $?, Mu $?) is pure {*}
src/core/Numeric.pm:proto sub infix:<!=>(Mu $?, Mu $?) is pure  {*}
src/core/Numeric.pm:proto sub infix:<≠> (Mu $?, Mu $?) is pure  {*}
src/core/Numeric.pm:proto sub infix:«<»(Mu $?, Mu $?) is pure   {*}
src/core/Numeric.pm:proto sub infix:«<=»(Mu $?, Mu $?) is pure {*}
src/core/Numeric.pm:proto sub infix:«≤» (Mu $?, Mu $?) is pure {*}
src/core/Numeric.pm:proto sub infix:«>»(Mu $?, Mu $?) is pure   {*}
src/core/Numeric.pm:proto sub infix:«>=»(Mu $?, Mu $?) is pure  {*}
src/core/Numeric.pm:proto sub infix:«≥» (Mu $?, Mu $?) is pure  {*}
src/core/Numeric.pm:proto sub infix:<+&>(Mu $?, Mu $?) is pure {*}
src/core/Numeric.pm:proto sub infix:<+|>(Mu $?, Mu $?) is pure {*}
src/core/Numeric.pm:proto sub infix:<+^>(Mu $?, Mu $?) is pure {*}
src/core/Numeric.pm:proto sub infix:«+<»(Mu $?, Mu $?) is pure {*}
src/core/Numeric.pm:proto sub infix:«+>»(Mu $?, Mu $?) is pure {*}
src/core/Numeric.pm:proto sub prefix:<+^>(Mu $) is pure {*}
src/core/Order.pm:proto sub infix:<cmp>(Mu $, Mu $) is pure {*}
src/core/Complex.pm:proto sub postfix:<i>(\a --> Complex:D) is pure {*}
src/core/set_union.pm:proto sub infix:<(|)>(|) is pure {*}
src/core/IO/Path.pm:    ) is pure {
src/core/IO/Path.pm:    my sub EXTENSION-SUBST ($ext, $base, $subst, $joiner) is pure {
src/core/set_intersection.pm:proto sub infix:<(&)>(|) is pure {*}
src/core/Junction.pm:proto sub any(|) is pure {*}
src/core/Junction.pm:proto sub all(|) is pure {*}
src/core/Junction.pm:proto sub one(|) is pure {*}
src/core/Junction.pm:proto sub none(|) is pure {*}
src/core/Junction.pm:sub infix:<|>(+values) is pure { values.any }
src/core/Junction.pm:sub infix:<&>(+values) is pure { values.all }
src/core/Junction.pm:sub infix:<^>(+values) is pure { values.one }
src/core/List.pm:proto sub infix:<,>(|) is pure {*}
src/core/List.pm:multi sub infix:<xx>(Mu \x, Int:D $n) is pure {
src/core/List.pm:proto sub infix:<X>(|) is pure {*}
src/core/List.pm:proto sub infix:<Z>(|) is pure {*}
src/core/set_symmetric_difference.pm:proto sub infix:<(^)>(|) is pure {*}
src/core/set_symmetric_difference.pm:multi sub infix:<(^)>(**@p) is pure {
src/core/set_precedes.pm:proto sub infix:<<(<+)>>($, $ --> Bool:D) is pure {
src/core/set_precedes.pm:only sub infix:<≼>($a, $b --> Bool:D) is pure {
src/core/set_precedes.pm:only sub infix:<<(>+)>>($a, $b --> Bool:D) is pure {
src/core/set_precedes.pm:only sub infix:<≽>($a, $b --> Bool:D) is pure {
src/core/set_proper_subset.pm:proto sub infix:<<(<)>>($, $ --> Bool:D) is pure {*}
src/core/set_proper_subset.pm:only sub infix:<⊄>($a, $b --> Bool:D) is pure {
src/core/set_proper_subset.pm:only sub infix:<⊃>($a, $b --> Bool:D) is pure {
src/core/set_proper_subset.pm:only sub infix:<⊅>($a, $b --> Bool:D) is pure {
src/core/Str.pm:proto sub infix:<unicmp>(|) is pure {*}
src/core/Real.pm:proto sub infix:<mod>($, $) is pure {*}
src/core/Any.pm:proto sub infix:<===>(Mu $?, Mu $?) is pure {*}
src/core/Any.pm:proto sub infix:<before>(Mu $?, Mu $?)  is pure {*}
src/core/Any.pm:proto sub infix:<after>(Mu $?, Mu $?) is pure {*}
src/core/Any.pm:proto sub item(|) is pure {*}
src/core/Mu.pm:proto sub defined(Mu) is pure {*}
src/core/Mu.pm:proto sub infix:<=:=>(Mu $?, Mu $?) is pure {*}
src/core/Mu.pm:proto sub infix:<eqv>(Any $?, Any $?) is pure {*}
src/core/Mu.pm:proto sub  infix:<−>(|)  is pure {*}
src/core/Mu.pm:proto sub prefix:<−>(|)  is pure {*}

@JJ
Copy link
Contributor

JJ commented Jan 24, 2018 via email

@JJ
Copy link
Contributor

JJ commented Jan 24, 2018

For instance, this thing:

sub four-bits() is pure {
    say "pure";
    return  <0 1> X~  <0 1> X~  <0 1> X~  <0 1>;
}

proto royal-road( Str $bits ) is pure {*}
multi royal-road( "0000" ) is pure { say "pure0000"; return 1; }
multi royal-road( "1111" ) is pure { say "pure1111"; return 1; }
multi royal-road( Str $bits ) is pure { say "purexxxx"; return 0; }

BEGIN { say ‘Begin’ }
say ‘Start’;
say royal-road("1010");
my %royal-road-hash = four-bits().map: { $^þ => royal-road( $^þ ) };

say %royal-road-hash;

four-bits() is called at compile time. However, royal-road is only called at compile time for the "1010" call. A macro could generate the code instead of the map.
Anyway, this seems to be a good use case. Generating complicated data structures at compile time, saves you a bit every time it is run.

@JJ JJ closed this as completed in 8a0702a Jan 24, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs Documentation issue (primary issue type)
Projects
None yet
Development

No branches or pull requests

6 participants