Suggestion: Fortran-like Keyword to Assert Function is Pure

I don’t know if this is possible or how much work it would be, but I’d like it if there was some kind of keyword like pure function f() that throws an error if the function being compiled is not pure. I’ve definitely faced frustrating bugs where I’ve accidentally mutated a variable that was passed, or otherwise changed a program’s state without realizing it.

2 Likes

It’s not what you’re looking for, but there’s Base.@pure, which tells the compiler the function is pure but does not check for purity. Julia’s mutable method tables also mean that @pure cannot be used for methods that call generic functions. For that reason, its use is generally discouraged for anyone without deep knowledge of Julia’s internals.

help?> Base.@pure
  @pure ex
  @pure(ex)


  @pure gives the compiler a hint for the definition of a pure function, helping for type inference.

  A pure function can only depend on immutable information. This also means a @pure function cannot use any global
  mutable state, including generic functions. Calls to generic functions depend on method tables which are mutable
  global state. Use with caution, incorrect @pure annotation of a function may introduce hard to identify bugs.
  Double check for calls to generic functions. This macro is intended for internal compiler use and may be subject to
  changes.
1 Like

I think these two goals are mutually exclusive (though I could be wrong).
Either you are asserting purity in a place the compiler can check and thus error if you violate this (and can/does already use that purity for optizations).
Or it is asserting purity in a place the compiler can’t prove (and thus doesn’t use for optimizations) in which case it can’t error if you violate it.

7 Likes

The compiler (or runtime) can still prove it’s not pure and raise an error.

1 Like

But if it can do that, it could have just figured out that the function is pure and optimized, sans any annotation. The difference between Julia and Fortran is that Julia’s compiler is not entirely potato.

4 Likes

OP’s goal is to raise an error for a function that is impure but labeled @purefunction, to help with debugging. Julia should be able to do this.

4 Likes

This is a good point and I withdraw my claim about this potentially helping with performance. I’ll settle for less bugs, then.

1 Like

Not to be a broken record but… don’t use Base.@pure if you’re getting bitten by bugs? Seriously, the purity requirements are very high for any meaningful optimizations to occur beyond what Julia normally does.

Often forcing inlining is enough to get the optimizations you want beyond the normal.

12 Likes

I don’t think this issue is about Base.@pure – that macro just has a naming collision with the functionality being requested here.

7 Likes

Not really important, but proving something is not pure (or any property) doesn’t require being able to prove something is pure.

(E.g., if I can only see the color red, hypothetically, I can prove that something is not green by seeing that it is red - but I cannot prove that anything is green; it could just as well be blue)

1 Like

I think that distinction is important, since it makes this feature possible.

Sure, I merely meant that this was in response to somewhat of a tangent relative to the original question.

I think it would be Bad to have an annotation that throws an error only if (but not if) a function is impure.

I’m not using Base.@pure. I’m not sure how you’re being a broken record, since nobody else suggested that because that’s not at all related to what I’m proposing. Bugs of the type I’m referring to come from coders accidentally writing functions that have side effects, e.g. taking an array x as input and using @. x = 2 * x in the body, which mutates the input, instead of x = 2 .* x, which just changes what the local variable refers to.

4 Likes

Ah, gotcha, sorry about that. I misunderstood where your bugs were coming from! And yeah, the tracks on this broken record are skipping between many topics over the years — it’s not a targeted slight against you.

Interestingly, I think that slant on the question significantly changes it — instead of being a compiler tool it becomes a dev tool for QA. In some ways I think this makes the request more feasible because it doesn’t need to turn on any additional optimizations.

10 Likes

This would be solved by introducing freeze/thaw semantics (i.e. marking a mutable variable temporarily as read-only and making writes to them a compiler error) and is not necessarily connected to declaring/proving purity. There was some discussion about this in various issues on the issue tracker, but nothing concrete yet.

Yeah, as mentioned above, I originally thought this would be useful for performance since the compiler could apply whatever kinds of optimizations it currently applies using @pure; presumably, though, the compiler is already optimizing anything that it can prove is pure, so @pure only makes a difference if the compiler can’t prove the function is pure. I think a pure function keyword might still be slightly useful to the compiler as a hint that these optimizations are feasible, so the compilation might be a bit faster. (For instance, if the function isn’t marked with pure function, that’s a hint that checking for purity to optimize might not be worth it, especially on lower compilation settings). I’ll rewrite the OP to remove references to optimization, though, since that’s far and away a lesser concern.

That sounds great, but doesn’t fix some other problems, like accidentally writing functions that depend on global state.

1 Like

Yes, that’s true - I don’t see that as much of a problem though, since non-constant global state/variables is kind of a code smell in julia anyway :man_shrugging: The associated drop in performance is usually enough to persuade people to put everything in functions and pass state explicitly, focusing the problem on mutating variables.

This is an appealing idea. The question, however, is this: how do you enforce this?

3 Likes