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

Add RFC For Algebraic Effects #73

Closed
wants to merge 3 commits into from

Conversation

thehydroimpulse
Copy link

No description provided.

@nrc
Copy link
Member

nrc commented May 8, 2014

I'm a big fan of effects systems and would love to see something in Rust some day, but I believe that there would need to be considerable research work done to adapt any of the existing systems to Rust. This is not going to happen for 1.0, and probably not 2.0 or 3.0 either. So this is probably not the best place to discuss it. I propose we close this RFC. If anyone is interested in pursuing this, it is probably better done as a research project. I'm sure people would happy to collaborate on that.


Safety is the cornerstone of the language (within the realms that a systems language allows — i.e., practicality). Pure functions, in languages like Haskell, don't allow any side effects, but real applications do. Things like state, communication over the network, file I/O, etc... Above all that, real systems may fail.

Haskell, for example, solves such problems with the use of monads and monad transformers. However, there are problems with using such a tool (See the paper for details).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have a two sentence summary of these problems?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll add it to the RFC.

@bill-myers
Copy link

@nick29581 Why does an effect system need any research at all? (beyond just trying to see if it's too much of a burden or not)

It is relatively easy to design and implement, and the real hard problem is making the decision that the positives outweigh the need to specify whether functions have side effects or not, and the potential inflexibility in being unable to implement side-effect-free traits using side effects.

And that decision MUST be made before 1.0, because it requires changing ALL code to denote whether it has side effects or not, and is of course not backwards compatible at all (the changes can be mostly automated using inference though, but extern functions, unsafe blocks, traits and public APIs will need manual attention).

There is also a much simpler (but less powerful) way to have an effect system that this RFC: just have a single effect for I/O and usage of mutable static and task-local variables, and denote it by writing "fn" for side-effect free functions, and "sub" for subroutines with side effects, and then split "unsafe" into "unsafe" (inferred side effects), "pure_unsafe" (forces no side effects) and "io_unsafe" (forces side effects).

Regarding this RFC, it's fine except for the fact that "Unsafe" makes no sense to have as an effect: what actually matters is which side effects the unsafe blocks actually cause, which they should be forced to declare, and whether the module has the privilege to have any unsafe blocks at all (which should be handled by the loading mechanism).

Also, "Fail" as an effect is far more problematic that the RFC indicates since just calling functions can intrinsically fail due to stack overflow, so you'd need to ban recursion, indirect calls without a stack usage limit, and have static stack analysis to ensure that there's enough stack, and also ban memory allocation, since that can also always fail too.

…o express effects that the paper describes. Added note of the correct author of the original proposal.
@thehydroimpulse
Copy link
Author

@bill-myers

And that decision MUST be made before 1.0, because it requires changing ALL code to denote whether it has side effects or not, and is of course not backwards compatible at all (the changes can be mostly automated using inference though, but extern functions, unsafe blocks, traits and public APIs will need manual attention).

While I agree that having this decision be made sooner rather than later is best, the ultimate purpose was to allow backwards-compatibility. Overall, an algebraic effects system isn't exactly mainstream and new comers won't want to touch it at the beginning. Thus, there would be 0 enforcements (wont(Effect1, ...EffectN)) by default (Actually, you would simply enforce the top-level effect Anything, which would exclude things like Unsafe to match the current semantics). However, effects could still be inferred automatically. One who learns about effects or wants to take advantage of them can start to introduce enforcements when they please to (I think it would be unrealistic to enforce enforcements to all Rust programs. That'd make it a no go for sure).

Regarding this RFC, it's fine except for the fact that "Unsafe" makes no sense to have as an effect: what actually matters is which side effects the unsafe blocks actually cause, which they should be forced to declare, and whether the module has the privilege to have any unsafe blocks at all (which should be handled by the loading mechanism).

I think Unsafe would be a top-level effect where other effects can take place (and those are probably what you want to pay attention to). That's if you don't want to force the user to annotate effects, which was the original goal of the RFC so it's optional.

You could make an exception for unsafe blocks, where you must annotate (because the compiler won't be able to infer many cases).

Also, "Fail" as an effect is far more problematic that the RFC indicates since just calling functions can intrinsically fail due to stack overflow, so you'd need to ban recursion, indirect calls without a stack usage limit, and have static stack analysis to ensure that there's enough stack, and also ban memory allocation, since that can also always fail too.

That's one of the major issues with an effects system (and I should probably emphasis it in the RFC). Any useful code (this includes functions calls and such) in that context is ultimately able to fail. So perhaps it's not a realistic effect that one could use, or there would have to be limits in-place that has a trustme(wont(Fail)).

For example, assert would have to have a Fail effect (if one were to exist), but if you have an assert call in the destructure (or any memory functions) then the destructure could fail. One of the goals is to be able to have a wont(Fail) so that there's no memory leaks if the task fails.

@emberian
Copy link
Member

First reaction: I liked the proposal when bblum made it, and I like it now. I look forward to a Rust with a system that is at least as powerful as this in it.

@emberian
Copy link
Member

Thanks @thehydroimpulse for writing it up!

@aochagavia
Copy link
Contributor

Won't this cause a lot of boilerplate like Java's throws keyword? Here is an interesting discussion about possible consequences of this approach (in other programming languages): http://ericlippert.com/2014/03/03/living-with-unchecked-exceptions/. See also http://www.artima.com/intv/handcuffs.html.

@thehydroimpulse
Copy link
Author

@aochagavia No, I don't think it would. That was a concern of mine, and I don't like how D does it (Not really an effect system, just a bunch of keywords like pure) where it becomes way too verbose.

The effect annotation won't be needed most of the time effect(Effect1, ...EffectN). The compiler would be able to infer it. The enforcements is the main place where verbosity might be possible, but by using top-level effects, one can mitigate it.

@aochagavia
Copy link
Contributor

@thehydroimpulse That sounds really nice!

@gsingh93
Copy link

@thehydroimpulse I'm not sure I like the sound of "the effect annotation won't be needed most of the time". I hate how in C++ a lot of optimizations happen most of the time, but I never know in what situations they occur or don't occur, so the only way to make sure is to write the code differently to make sure it's a situation where the optimization will definitely happen or confirm by looking at the assembly. However, if the specific cases where the developer will have to manually specify the effects is clear, than I'm fine with that.

@Valloric
Copy link

This RFC looks really nice, but like others, I'm concerned it might suffer the same fate as Java's checked exceptions. Those also looked like a great idea on paper but with experience turned out to be a bad idea.

If this were implemented, it might be a good idea to first have it behind a feature gate until we're certain it's a net positive.

@thehydroimpulse
Copy link
Author

@gsingh93 The reason I say most is because there would be cases where the compiler might not be able to infer the effects. For example, code within unsafe blocks is harder to understand from a compiler's point of view because there are a lot less restrictions in place.

There are a couple solutions to this problem:

  • If the compiler cannot infer an effect it, then a warning could be shown (similar to lifetimes).
  • Code that has unsafe blocks must annotate it's side-effects, otherwise an error would be thrown.

@Valloric it honestly depends on the amount of effects. I'll update the RFC talking about user defined effects and how I'd be against it. It also depends on how much you wish to enforce effects. Again, I wouldn't want them to be forced upon users who don't like them, have no idea what they are, or don't care about them.

effect Anything
```

The first letter of each word in effects are capitalized, the remaining letters are lowercased. `Fail`, `GC`, `Unsafe`, `IO`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GC and IO do not have the remaining letters lowercased.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm treating acronyms as two separate words. Instead of GarbageCollection, it's GC.

* Remove the `Unsafe` effect.
* List all needed keywords.
* Rename `wont` to `forbid`
* Rename `Fail` to `Failure` to be gramatically correct with the use
  of `forbid`.
* Explain the `Failure` problems as discussed in the comments.
* Mention the unresolved questions about compiler inference (when it
  can't do so)
@pnkfelix
Copy link
Member

I'm with @nick29581 : I'm also a big fan of effects systems, but think it is premature to try to integrate one into Rust now, and thus I think we should close this RFC.

(At the very least, we would need to figure out our language versioning story before we try even to lay the groundwork for something like this.)

@brson
Copy link
Contributor

brson commented May 20, 2014

Effects systems are frequently requested, and the response is always that to do so would be far beyond Rust's complexity budget. Closing.

@brson brson closed this May 20, 2014
@dsvictor94
Copy link

When you come to the Rust, you really feel safe because the compiler garante a lot of things to you, until you need a guarantee that rust do not provide. When this happen, the only thing you can do today are document saying "please do not use a function that have 'that effect' otherwise bad things will happen". And this is totally okay, but is not what a Rust programmer expect, because he trust the compiler to avoid unexpected behaviors.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.