Opened 6 years ago

Last modified 20 months ago

#3615 new feature request

GHCi doesn't allow the use of imported data contructors

Reported by: blamario Owned by:
Priority: normal Milestone:
Component: GHCi Version: 6.10.4
Keywords: Cc:
Operating System: Linux Architecture: x86
Type of failure: None/Unknown Test Case:
Blocked By: Blocking:
Related Tickets: Differential Revisions:

Description

There are two modules in this simplified scenario. The main module is Main.hs and contains the following three lines of code.

module Main where
import Imp (D(..))
main = print D1

Module Imp contains a single data type definition:

module Imp where
data D = D1 | D2 deriving Show

Now, when I compile Main everything works. GHCi doesn't complain when it loads the main module either, but it doesn't allow me to construct D on its command line. This makes no sense to me.

$ ghc --make Main.hs 
[1 of 2] Compiling Imp              ( Imp.hs, Imp.o )
[2 of 2] Compiling Main             ( Main.hs, Main.o )
Linking Main ...
$ ./Main 
D1
$ ghci Main.hs
GHCi, version 6.10.4: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer ... linking ... done.
Loading package base ... linking ... done.
Ok, modules loaded: Main, Imp.
Prelude Main> D1

<interactive>:1:0: Not in scope: data constructor `D1'
Prelude Main> 

Change History (7)

comment:1 Changed 6 years ago by blamario

  • Component changed from Compiler to GHCi
  • severity changed from normal to minor

I just discovered that command :load *Main solves the problem. Still, this behavior seems confusing for no apparent (to me) reason. Perhaps the module specified on the command line should be loaded with * by default on start up?

comment:2 Changed 5 years ago by simonpj

  • difficulty set to Unknown
  • Type changed from bug to feature request

I can at least explain what is going on.

  • You compiled Imp and Main
  • So ghci can load them fast (by linking their .o files) and run them fast (using their compiled code).
  • But the downside is that all GHC knows about the module is what is recorded in the interface file, Main.hi and Imp.hi
  • You did not export D(..) from Main, so the interface file Main.hi didn't mention the data type D at all.
  • If, instead, you load Main interpreted (this is what :load *Main does) you get access to its entire top-level scope.

The compiled/interpreted distinction is unfortunate, because it's really an implementation matter, but it shows up to users. We could make it less obtrusive by recording more in interface files (e.g. recording enough info to reproduce the top-level environment of Main). But it's more than just recording extra info; doing a full job would require doing less optimisation. For example suppose you have

module Foo(b) where
  f x = <blah>
  g y = f (x+x)

When compiled, GHC inlines 'f' at its only call (in 'g'), and so there is no compiled code for 'f'. Hence GHCi can't call it. I'm reluctant to prevent non-exported things from being inlined in this way. (I suppose it could be an -O2 thing.)

Anyway, that's the explanation.

The situation could be improved with some effort.

  • Any volunteers?

Simon

comment:3 Changed 5 years ago by duncan

It should be possible in principle to provide an explanation in this case, something like "Constructor D' is not exported from module M'. To get access to the internals you can reload the module in interpreted mode using :set -fobject-code and :reload"

The names of the internal things would have to be recorded in the .hi file for this to be possible (even if there's no corresponding object code since it all got inlined away). Of course it may not be trivial to keep this info.

comment:4 Changed 5 years ago by igloo

  • Milestone set to 6.14.1

comment:5 Changed 5 years ago by simonmar

  • Milestone changed from 6.14.1 to _|_

I think the docs are pretty clear: http://www.haskell.org/ghc/docs/latest/html/users_guide/interactive-evaluation.html#ghci-scope

Personally I think the chances of us being able to improve matters here are pretty slim. The solution that Simon suggests (keeping everything unless -O2 is on) would be even more strange than the current situation, IMO, and Duncan's suggestion is tricky to implement for a relatively small gain.

Still, I'll leave the ticket open as an acknowledgment that the current situation is unsatisfying, and to act as a place to collect ideas.

comment:6 Changed 5 years ago by isaacdupree

this idea is possibly even worse than Duncan's, but:

In simonpj's example, do inline 'f' because it's only used once -- but ALSO keep a copy of it, so that ghci people can at least call it.

If that leads to bloat in even the compiled code, here is an even-weirder idea: keep a separate .hi and .o file for the stuff that's accessible from within the module (perhaps excluding the stuff that's exported, since it's in the other hi/o files that we already make)

comment:7 Changed 20 months ago by rwbarton

  • Type of failure set to None/Unknown

isaacdupree's first idea of keeping copies of every top-level definition in .o files sounds pretty reasonable to me, if bloat is the only concern. Unused definitions could still, in principle, be dropped from libraries or executables. If use of -split-objs becomes more widespread, or we move to a -ffunction-sections/--gc-sections sort of world (either of which would be nice to reduce executable bloat for other reasons), this might become more or less automatic.

Note: See TracTickets for help on using tickets.