Opened 3 years ago

Closed 3 years ago

Last modified 23 months ago

#10140 closed bug (fixed)

Suggestions for improvement of the Safe Haskell chapter in the user's guide

Reported by: thomie Owned by: dterei
Priority: normal Milestone: 8.0.1
Component: Documentation Version: 7.8.4
Keywords: Cc: dterei
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: None/Unknown Test Case:
Blocked By: Blocking:
Related Tickets: Differential Rev(s):
Wiki Page:

Description

I've been reading the documentation on Safe Haskell. Cool stuff. Here are some suggestions for improvement, I hope some are useful:

  • 7.29.1.2

This comment is the first introduction to the pragmas TrustWorthy and Safe:

-- Either of the following Safe Haskell pragmas would do
        {-# LANGUAGE Trustworthy #-}
        {-# LANGUAGE Safe #-}
module RIO ...

Why is either allowed? I suspect because of the details of this module, but this is not explicitly stated. Furthermore, later it is said that -XTrustworthy should be used, not -XSafe:

"This is done by compiling the RIO module with the -XTrustworthy flag and compiling the Danger module with the -XSafe flag."

  • 7.29.2

"TemplateHaskell — Is particularly dangerous, as it can cause side effects even at compilation time"

One could now think that Safe Haskell does guarantee compilation safety. Since that is not the case, I would remove that sentence (things are explained properly in the Safe Compilation section).

  • 7.29.2

"Hand crafted instances of the Typeable type class are not allowed in Safe Haskell".

Make a mention of the following:

"... since GHC 7.8.1, handwritten (ie. not derived) instances of Typeable are forbidden, and will result in an error."

  • 7.29.4

After listing -XSafe, -XTrustWorthy, -XUnsafe:

"The procedure to check if a module is trusted or not depends on if the -fpackage-trust flag is present. The check is very similar in both cases"

There are three cases.

  • 7.29.4.1. Trust check (-fpackage-trust disabled)

"A module M in a package P is trusted by a client C if and only if:

Both of these hold:

  1. The module was compiled with -XSafe
  1. All of M's direct imports are trusted by C"

But isn't the latter implied by the former, or the module wouldn't compile? If that is correct, please mention it. Same in the next section (7.29.4.2).

  • 7.29.4.2

"Having the -fpackage-trust flag also nicely unifies the semantics of how Safe Haskell works when used explicitly and how modules are inferred as safe."

Should explicitly be implicitly? I don't understand this sentence regardless. What does nicely unifies mean?

  • 7.29.4.1 and 7.29.4.2

There is no mention of Safe Haskell Inference in these rules, only "The module was compiled with -XSafe" and "The module was compiled with -XTrustWorthy". I think the following statement should be true, but I'm not sure: "If a module M in a package P is inferred to be Safe by GHC, then it is trusted by client C".

Actually, there is only a short mention of safe inference in the introduction, whereas I suspect it should be mentioned everywhere where -XSafe is.

  • 7.29.5

"That is, the use cases outlined and the purpose for which Safe Haskell is intended: compiling untrusted code."

Before, "compiling and executing untrusted code" was listed as one of two cases. Now it's mentioned as the single purpose. Minor issue.

  • 7.29.5

"Say you are writing a Haskell library. Then you probably just want to use Safe inference."

I have more of a general question about this: if this is true, then why are there over 200 mentions of {-# Language Safe #-} in a checkout of ghc?

Is it because 'Safe Haskell Inference' was not added to GHC until version 7.4 (is that true? I inferred it from the difference between the 7.2 and 7.4 user's guides). So maybe modules that need to be compileable with earlier versions of GHC have to specify -XSafe explicitly? Some guidance on this would be helpful.

  • There are 2 ulinks that don't work. Should be xref.

Change History (6)

comment:1 Changed 3 years ago by simonpj

David, good suggestions here. Would you like to follow them up?

Thanks Thomas

Simon

comment:2 Changed 3 years ago by dterei

Thomas, thanks for this, it's great feedback! I'll take a pass over the docs again and incorporate your notes.

Some answers:

But isn't the latter implied by the former, or the module wouldn't compile? If that is correct, please mention it.

Yes, it is. The description of the check here doesn't distinguish between the fact that some of the check already occurred at compile time and so the recursive element is already done. I'll try to better capture that without removing the description of the check being recursive / transitive.

Should explicitly be implicitly? I don't understand this sentence regardless. What does nicely unifies mean?

Yes, I think it should be implicitly. That sentence should probably just be removed. Basically what it is saying is that we ran into a problem when designing Safe Haskell of how to have it co-exists with the existing language in a way that people who care can opt into with all the properties and power we wanted, while users who don't care can ignore the whole thing. In the first version, we got this wrong and Safe Haskell caused compilation failures for people who weren't explicitly using it. The -fpackage-trust flag changed to fix this.

So really, this line is an off-hand comment on some history that adds no value to the reader.

I think the following statement should be true, but I'm not sure: "If a module M in a package P is inferred to be Safe by GHC, then it is trusted by client C".

No, not unconditionally. It depends on -fpackage-trust. "M" may be inferred safe, but when GHC does this it assumes that the client "C" is prepared to trust all packages containing Trustworthy modules that "M" depends on. It's then up to "C" on her respective system to make that dynamic decision.

I have more of a general question about this: if this is true, then why are there over 200 mentions of {-# Language Safe #-} in a checkout of ghc?

Two reasons: 1) Historical -- we added safe inference later. 2) Stability -- one issue with safe inference is that since the module author hasn't stated her intentions, then what Safe Haskell type the module should have isn't set and could change without warning from the compiler. For some library authors this may be fine as Safe Haskell isn't of primary importance to them. But for very base libraries like the ones GHC distributes, we want them to have a very set and stable Safe Haskell type that the community can depend on.

The other issue is that using Safe Haskell explicitly adds another dependency that could cause your module to fail to compile. For base modules in GHC this isn't an issue as they have few dependencies and one team largely controls them all. For a higher level package though, use Safe explicitly means you are dependent on how the safety of your dependencies change over time. Maybe this is what you want, but for a lot of people where Safe Haskell is a secondary concern, probably not.

So it's a trade-off on what concerns and dependencies you have in regards to the larger Haskell community.

comment:3 Changed 3 years ago by dterei

Owner: set to dterei

comment:4 Changed 3 years ago by David Terei <code@…>

In c1db477151c2c1a330081fd0b4aab29bd85b636f/ghc:

Changes to Safe Haskell documentation from feedback (#10140).

comment:5 Changed 3 years ago by dterei

Resolution: fixed
Status: newclosed

Made some changes I think should address the feedback. Thanks once again!

comment:6 Changed 23 months ago by thomie

Milestone: 8.0.1
Note: See TracTickets for help on using tickets.