Skip to content

Conversation

@thumphries
Copy link

Howdy maintainers,

I've been using hint for dynamic reloading of web applications, where filesystem events or other signals trigger a reload and restart. The implicit reset in loadModules made this quite slow, so I wrote this GHCi-style incremental reload function.

Let me know if there are any changes required, or if there are safety concerns that might prevent it being merged. It seems to be roughly equivalent to GHCi's reload command.

Thanks for building and maintaining this library, it saved me a lot of GHC API pain.

Copy link
Contributor

@mvdan mvdan left a comment

Choose a reason for hiding this comment

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

Overall sounds like a good idea, but would like to have someone else's input too.

cc @gelisam

doLoad fs `catchIE` (\e -> reset >> throwM e)
targets <- mapM (\f->runGhc2 GHC.guessTarget f Nothing) fs
runGhc1 GHC.setTargets targets
doLoad GHC.LoadAllTargets `catchIE` (\e -> reset >> throwM e)
Copy link
Contributor

Choose a reason for hiding this comment

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

This line is exactly what reload runs too. Deduplicate code?

-- ** Context handling
ModuleName, isModuleInterpreted,
loadModules, getLoadedModules, setTopLevelModules,
reload,
Copy link
Contributor

Choose a reason for hiding this comment

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

Please put it in the reset line like the other file.

--
runGhc1 GHC.setTargets targets
res <- runGhc1 GHC.load GHC.LoadAllTargets
reload :: MonadInterpreter m => m ()
Copy link
Contributor

Choose a reason for hiding this comment

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

Since this will be exported, it will need documentation. See how it is done for reset.

@mvdan
Copy link
Contributor

mvdan commented Feb 9, 2017

Also please use a slightly more detailed commit message, like Add reload, similar to ghci's :reload or Add reload to Language.Haskell.Interpreter.

@thumphries
Copy link
Author

Thanks for the feedback.

I've found I need to call setTopLevelModules after calling reload. Maybe this should perform getContext / setContext also, to behave a little more like GHCi. What do you think?

Copy link
Contributor

@mvdan mvdan left a comment

Choose a reason for hiding this comment

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

I've found I need to call setTopLevelModules after calling reload. Maybe this should perform getContext / setContext also, to behave a little more like GHCi. What do you think?

setTopLevelModules seems to call setContext, so I would think not.

In any case, if we're wrong about this, I'm not too worried as we could fix it later without changing the exposed API.

res <- runGhc1 GHC.load GHC.LoadAllTargets
targets <- mapM (\f->runGhc2 GHC.guessTarget f Nothing) fs
runGhc1 GHC.setTargets targets
catchReset (doLoad GHC.LoadAllTargets)
Copy link
Contributor

Choose a reason for hiding this comment

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

I meant that this line could just call reload, unless I'm missing something. Then, catchReset would be unnecessary.

Copy link
Author

Choose a reason for hiding this comment

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

Fixed. Apologies for my density!

@mvdan
Copy link
Contributor

mvdan commented Feb 11, 2017

Thanks for the updates. Code looks good, but since I'm not familiar with ghci's :reload I'm gonna wait for someone who is to have a look before merging and releasing this.

cc @jcpetruzza @gelisam

@gelisam
Copy link
Contributor

gelisam commented Feb 11, 2017

I'm not familiar with it either, sorry.

@jcpetruzza
Copy link
Contributor

Could I suggest adding a unit test for this function? It will make it easier to convince people that this actually works as intended, and it will make the life of @mvdan infinitely easier the next time the ghc api changes and reload needs to be fixed 😄

@thumphries
Copy link
Author

In any case, if we're wrong about this, I'm not too worried as we could fix it later without changing the exposed API.

Sounds good. I expect to be using this functionality for some internal developer tooling pretty shortly, so we'll know pretty quickly if it misbehaves or (more likely) is annoying to use.

Code looks good, but since I'm not familiar with ghci's :reload I'm gonna wait for someone who is to have a look before merging and releasing this.

In the absence of this person, I'll try to convince you of my reasoning.

here is the implementation from ghci-ng. It does a LoadAllTargets and then restores the context from the GHCi state.

It also reverts CAFs after every load/reload. I noticed Hint has a few comments wondering if we should do that or not, I certainly don't know the answer :) though it seems the consequences mostly affect magic constants like stdin stdout.

The other step in afterLoad, restoring tick arrays, seems to refer to the internal state used by the debugger. We should be ok ignoring this, likewise the Safe Haskell stuff.

Could I suggest adding a unit test for this function?

I'll add some tests similar to those for loadModules, though they should behave identically with this implementation. The only difference is reload is incremental, so it is much faster and suitable for use in a development loop.

--
liftIO $ writeFile mod_file_a mod_a_v2
liftIO $ writeFile mod_file_b mod_b
set [searchPath := ["."]]
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 not quite sure why this is necessary, will need to spend some time debugging. It breaks if you move it to the top, which isn't good!

@mvdan
Copy link
Contributor

mvdan commented Feb 13, 2017

Thanks for adding the test!

will need to spend some time debugging

Let me know when you're happy with the PR.

Copy link
Contributor

@mvdan mvdan left a comment

Choose a reason for hiding this comment

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

Just to remind myself and everyone that this isn't ready to merge, I'm marking it as "changes requested".

@thumphries
Copy link
Author

Thanks, I'll get to this pretty soon.

Just restating the reason for block, for future archaeologists: something odd is happening when working on modules in . (pwd) - modules are able to load, but they don't reload. Explicitly setting . as the search path makes things work again. All modules outside . seem to reload correctly.

@mvdan
Copy link
Contributor

mvdan commented Jun 12, 2017

Friendly ping - any news? I'm not in a rush, but I'm not a fan of leaving pull requests open for a long time either.

Perhaps we should move this to an issue after the summer if it's still not ready to merge by then.

@thumphries
Copy link
Author

thumphries commented Jun 12, 2017 via email

@mvdan
Copy link
Contributor

mvdan commented Feb 28, 2018

It has been a full year without activity, so I'm going to close this pull request for now. Please feel free to reopen it if you do find time to work on it again.

Or, if you think there's useful information for others here, but you're not planning on using it yourself soon, feel free to move the thread to an issue as well.

@mvdan mvdan closed this Feb 28, 2018
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.

4 participants