Hiding import behaviour
Mario Blažević
mblazevic at stilo.com
Tue Oct 21 14:55:15 UTC 2014
On 14-10-21 07:14 AM, Erik Hesselink wrote:
> On Mon, Oct 20, 2014 at 11:57 PM, Mario Blažević <mblazevic at stilo.com> wrote:
>> On 14-10-19 08:10 AM, Erik Hesselink wrote:
>>>
>>> Adding an explicit
>>> import can suddenly cause type errors in completely unrelated places
>>> (when it hides an implicit import and the new function is type
>>> incorrect), or worse, can cause semantic change (when it hides an
>>> implicit import and the new function is type correct, but has
>>> different behavior). Remember that not all code is written by the same
>>> person, or in a short time frame, so not everybody might fully
>>> understand every module and every import of the code they're editing.
>>
>> Your example requires somebody actively editing the import list. A
>> code change causes a compile error or worse? That is not all that
>> surprising.
>
> But right now, we have a useful property that adding imports and code
> to a module does not break or change other code in that module. With
> this extension, that changes. I find this kind of local reasoning very
> useful, IMHO it's one of the most useful things about Haskell in
> general.
Right now, adding an import can certainly cause a compiler error. It
can't change the run-time behaviour of a correct module, that is true.
With the proposal, there would be still be a somewhat weaker guarantee:
adding an *implicit* import would never change the module's run-time
behaviour.
>> No, what I find much worse is a cabal update causing an error in a
>> module that was correct before the update. Consider
>>
>>> module Main where
>>>
>>> import Foo (foo)
>>> import Bar
>>>
>>> main = foo
>>
>> Now suppose Bar came from the package bar-1.0, and the new version
>> bar-1.0.1 decides to export foo. With the current behaviour, this change
>> would break my module. With Malcolm's proposal the old code would continue
>> to work.
>
> That's a very good point. Given that and the above, I don't understand
> your conclusion:
>
>> Anyway, count me as +1 on the proposal. It would improve the
>> long-term stability of Haskell code.
>
> How is adding more ways to break something "improving the long-term stability"?
You seem determined to misunderstand every message in this thread. What
I said was that the change from bar-1.0 to bar-1.0.1 breaks the example
code *with the current behaviour*. The proposal removes this breakage.
Anything that keeps the old code compiling and working with new
libraries improves its long-term stability in my book.
Note that the bar-1.0.1 upgrade wasn't even a major version change.
This is correct according to the PVP:
> Otherwise, if only new bindings, types, classes, non-orphan instances
> or modules (but see below) were added to the interface, then A.B may
> remain the same but the new C must be greater than the old C.
but it still breaks the example module.
Mind you, while the current proposal only increases the chances that
old Haskell code continues to work with new libraries. If my module had
defined a function foo itself instead of importing it, the upgrade would
still break it. An extended version of the proposal might state that
implicitly imported members get shadowed by local definitions as well,
but this might be harder to implement. Besides, even this proposal
wouldn't protect the importer from new instance imports from clashing
with the local ones. There's no shadowing solution in this case.
To summarize, the proposal is not providing any hard guarantees, and
it's weakening an existing guarantee (see above). I'm still in favour,
because it increases the stability of the legacy Haskell codebase.
More information about the Glasgow-haskell-users
mailing list