Skip to content

server: validation code simplifications #4585

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

Closed
wants to merge 1 commit into from

Conversation

abooij
Copy link
Contributor

@abooij abooij commented Apr 28, 2020

Description

Rather than defining a new monad class and constructing new instances
of it, just use the StateT that it is really based on. I am proposing this change for several reasons: it is shorter, we reduce the amount of code that can be incorrect, and most importantly, it is easier to understand. At first I found it difficult to understand MonadReusability. But its description as a state monad explains everything to me. However, this description is only present in its implementation.

This PR also gets rid of some dead code, and Monoid instances that aren't
actually monoids (such as the ones for QueryReusability and UnionTyInfo).

Also avoid an instance of prisms where this doesn't add much value. This has the added benefit of the code being more welcoming to programmers who are perhaps not so familiar with lenses/prisms.

Affected components

  • Server

Server checklist

Catalog upgrade

Does this PR change Hasura Catalog version?

  • No

Metadata

Does this PR add a new Metadata feature?

  • No

GraphQL

  • No new GraphQL schema is generated

Breaking changes

  • No Breaking changes

Rather than defining a new monad class and constructing new instances
of it, just use the `StateT` that it is really based on.

Also get rid of some dead code, and Monoid instances that aren't
actually Monoids.

Also avoid an instance of Lenses where this doesn't add much value.
@netlify
Copy link

netlify bot commented Apr 28, 2020

Deploy preview for hasura-docs ready!

Built with commit fdffb10

https://deploy-preview-4585--hasura-docs.netlify.app

@hasura-bot
Copy link
Contributor

Review app for commit fdffb10 deployed to Heroku: https://hge-ci-pull-4585.herokuapp.com
Docker image for server: hasura/graphql-engine:pull4585-fdffb100

@0x777 0x777 requested a review from lexi-lambda April 28, 2020 15:06
@abooij abooij changed the title Validation code simplifications server: validation code simplifications Apr 28, 2020
@abooij
Copy link
Contributor Author

abooij commented Apr 29, 2020

In fact, arguably we should define this in terms of writers rather than state: we should never need to know the current list of validated variables.

@abooij
Copy link
Contributor Author

abooij commented Apr 30, 2020

I now see that #4111 already contains similar simplification work on MonadReusability, where it is renamed to MonadParse, and combined with some elements of MonadError. So this PR can be ignored in lieu of that one.

Comment on lines -822 to +795
recordVariableUse :: G.Variable -> RQL.PGColumnType -> m ()
markNotReusable :: m ()
type MonadReusability m = MonadState QueryReusability m

instance (MonadReusability m) => MonadReusability (ReaderT r m) where
recordVariableUse a b = lift $ recordVariableUse a b
markNotReusable = lift markNotReusable
type ReusabilityT m a = StateT QueryReusability m a
Copy link
Contributor

Choose a reason for hiding this comment

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

I normally recommend against doing this. Why? Two reasons:

  1. You can’t use MonadState for something else when this transformer is somewhere in the stack.

  2. It’s a weaker abstraction. Code that is polymorphic in the monad but written against MonadReusability can only call recordVariableUse and markNotReusable, which accumulate information monoidally. But using MonadState, they can do arbitrary other things, including dropping the state altogether.

Perhaps the above two points seem like small potatoes, and maybe they are. But I don’t think they’re inconsequential enough to justify switching away from the abstraction just to be a little bit simpler!

One improvement that would be nice would be to switch from StateT to WriterT as the underlying transformer, since ReusabilityT is fundamentally about accumulating information monoidally, and it doesn’t need the full power of StateT. Alas, even the strict variant of WriterT leaks space, so I avoid using it for anything that isn’t tiny.

Fortunately, recent versions of transformers include Control.Monad.Trans.Writer.CPS, which is a non-leaky implementation of WriterT (it uses StateT under the hood), but mtl doesn’t include support for that in the currently-released version. It does support it on master (because I added support for it—probably at around the same time I wrote ReusabilityT, in fact!), but it doesn’t seem to have made its way into a release yet. I should probably bother the maintainers about that.

Copy link
Contributor Author

@abooij abooij Apr 30, 2020

Choose a reason for hiding this comment

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

Thanks for this background, Alexis. I completely agree with the points you raise. I am not as well-versed in the space leakage of the various monad transformers, so what you wrote is very informative.

The reason I opened this PR nonetheless is that I think in this case the abstraction of MonadReusability has a cost. There is an argument to be made against abstraction when this is in conflict with interpretability, as it was for me. But I'm sure we can resolve this conflict in the refactored version by making sure there is good documentation, and by minimizing dependency on this stateful computation. (At first sight this seems to be much better in the refactored version, which is why above I proposed to ignore this PR in lieu of that work.)

Copy link
Contributor

Choose a reason for hiding this comment

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

FWIW I agree with you 100% that the “mtl-style” approach to effect composition is way, way too complicated, and we want something better. That is in fact precisely why I have written eff: I think monad transformers are the single largest obstacle to new Haskell programmers who want to get productive with the language, and I think algebraic effects are a better design.

Unfortunately, existing approaches to algebraic effects in Haskell aren’t very efficient, so eff is also a project in making them fast. And eff is fast… but it is fast because it depends on some modifications to GHC. I have an open GHC proposal to get those modifications merged, but until then we’re stuck with what we have.

So yes, less tangentially, I’m happy to include some more documentation wherever it would help. Please feel free to add some extra documentation wherever it would be helpful! (Or, for that matter, request for someone else to add some documentation if you don’t feel like you understand it enough to do it yourself.)

Comment on lines -815 to -819
instance Semigroup QueryReusability where
Reusable a <> Reusable b = Reusable (a <> b)
_ <> _ = NotReusable
instance Monoid QueryReusability where
mempty = Reusable mempty
Copy link
Contributor

@lexi-lambda lexi-lambda Apr 30, 2020

Choose a reason for hiding this comment

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

You say this “isn’t actually a monoid,” but that’s just not true; this is a monoid. It satisfies all the monoid laws. It wouldn’t be a monoid if we defined mempty = NotReusable, but we don’t. As-written, it’s a perfectly cromulent monoid.

(You’re right that the other instances aren’t monoids, and we should get rid of those. But this one seems fine to me.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, having taken a second look, you are right. So it makes sense to treat QueryReusability as a monoid.

@abooij
Copy link
Contributor Author

abooij commented May 4, 2020

Closing this for now, awaiting the results of #4111.

@abooij abooij closed this May 4, 2020
@hasura-bot
Copy link
Contributor

Review app https://hge-ci-pull-4585.herokuapp.com is deleted

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

Successfully merging this pull request may close these issues.

3 participants