Re: Hiding import behaviour

2014-10-24 Thread Richard Eisenberg
Thanks for writing this up so clearly.

I'm +1 on the proposal as written. I think the (smallish) drawbacks are 
mitigated by the fact that the whole feature is opt-in.

Implementation should be relatively straightforward.

Thanks,
Richard

On Oct 23, 2014, at 2:22 PM, htebalaka goodi...@gmail.com wrote:

 Proposal is up for your viewing pleasure:
 http://www.haskell.org/haskellwiki/PermissiveImportsProposal
 
 
 
 --
 View this message in context: 
 http://haskell.1045720.n5.nabble.com/Hiding-import-behaviour-tp5758155p5758553.html
 Sent from the Haskell - Glasgow-haskell-users mailing list archive at 
 Nabble.com.
 ___
 Glasgow-haskell-users mailing list
 Glasgow-haskell-users@haskell.org
 http://www.haskell.org/mailman/listinfo/glasgow-haskell-users

___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


Re: Hiding import behaviour

2014-10-23 Thread htebalaka
Proposal is up for your viewing pleasure:
http://www.haskell.org/haskellwiki/PermissiveImportsProposal



--
View this message in context: 
http://haskell.1045720.n5.nabble.com/Hiding-import-behaviour-tp5758155p5758553.html
Sent from the Haskell - Glasgow-haskell-users mailing list archive at 
Nabble.com.
___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


Re: Hiding import behaviour

2014-10-21 Thread Erik Hesselink
On Mon, Oct 20, 2014 at 11:57 PM, Mario Blažević mblaze...@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.

 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?

Regards,

Erik
___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


Re: Hiding import behaviour

2014-10-21 Thread Richard Eisenberg
I'm having a hard time keeping track of what's going on in this discussion. 
But, I'm generally in favor of making *some* change along the lines discussed 
here, and also in #9702 (https://ghc.haskell.org/trac/ghc/ticket/9702). Could 
the proposers of various features perhaps create a wiki page, naming the 
individual pieces or proposals, and then we can have something closer to a vote 
among a stable list of candidates?

Thanks!
Richard

On Oct 21, 2014, at 7:14 AM, Erik Hesselink hessel...@gmail.com wrote:

 On Mon, Oct 20, 2014 at 11:57 PM, Mario Blažević mblaze...@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.
 
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?
 
 Regards,
 
 Erik
 ___
 Glasgow-haskell-users mailing list
 Glasgow-haskell-users@haskell.org
 http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
 

___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


Re: Hiding import behaviour

2014-10-21 Thread Daniel Trstenjak

Hi Erik,

 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.

So your biggest concern is about silent breakage of code, that suddenly
a different function is used which has the same name and type, but
different semantics.

In all other cases the compiler would throw an error, because the types
wouldn't match.

I have the feeling, that the proposal shouldn't be about implicit/explicit 
imports,
but about prefering the function with the fitting type.

If there're two functions with the same name and type in scope, then the
compiler most likely should always throw an error.

The only exception might be, if there's a function locally defined in the
module, then this one might be prefered over every imported one with the
same name and type. But perhaps even in this case it might be a good idea to
throw an error.


Greetings,
Daniel
___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


Re: Hiding import behaviour

2014-10-21 Thread Mario Blažević

On 14-10-21 07:14 AM, Erik Hesselink wrote:

On Mon, Oct 20, 2014 at 11:57 PM, Mario Blažević mblaze...@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.



___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


Re: Hiding import behaviour

2014-10-21 Thread Erik Hesselink
On Tue, Oct 21, 2014 at 4:55 PM, Mario Blažević mblaze...@stilo.com wrote:
 On 14-10-21 07:14 AM, Erik Hesselink wrote:

 On Mon, Oct 20, 2014 at 11:57 PM, Mario Blažević mblaze...@stilo.com
 wrote:
  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:

You're right, I misread your message. I understand now, and you're
right that this is currently something that can break your package,
although it happens so rarely that people still depend on major
version ranges, even though they sometimes don't use explicit or
qualified imports.

Regards,

Erik
___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


Re: Hiding import behaviour

2014-10-21 Thread htebalaka
The current situation could be summed up as requiring some code duplication
when explicitly importing (due to the possibility of one or more redundant
hides), while encouraging a sort of measure-twice-cut-once mentality. Not
suggesting changing the default; I'll have a proposal detailing the exact
semantics and possible consequences of using it on the wiki on Thursday, so
that more people can weigh in.


Erik Hesselink wrote
 On Tue, Oct 21, 2014 at 4:55 PM, Mario Blažević lt;

 mblazevic@

 gt; wrote:
 On 14-10-21 07:14 AM, Erik Hesselink wrote:

 On Mon, Oct 20, 2014 at 11:57 PM, Mario Blažević lt;

 mblazevic@

 gt;
 wrote:
  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:
 
 You're right, I misread your message. I understand now, and you're
 right that this is currently something that can break your package,
 although it happens so rarely that people still depend on major
 version ranges, even though they sometimes don't use explicit or
 qualified imports.
 
 Regards,
 
 Erik
 ___
 Glasgow-haskell-users mailing list

 Glasgow-haskell-users@

 http://www.haskell.org/mailman/listinfo/glasgow-haskell-users





--
View this message in context: 
http://haskell.1045720.n5.nabble.com/Hiding-import-behaviour-tp5758155p5758451.html
Sent from the Haskell - Glasgow-haskell-users mailing list archive at 
Nabble.com.
___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


Re: Hiding import behaviour

2014-10-21 Thread htebalaka
It's occurred to me that a much simpler description of the proposed change
would be automatically lifting *uses* of the explicitly imported variable to
a qualified use, /if/ there was only one explicit import of the identifier.
For instance, with the following import:

import Data.Text.Lazy.IO (putStrLn)
import Prelude
import qualified Data.List as L
import qualified MyModule as L (isInfixOf)

automatically change any unqualified (and un-shadowed) use of putStrLn to
Data.Text.Lazy.IO.putStrLn, and any use of L.infixOf to MyModule.isInfixOf.

The latter should be easier to implement covering a number of corner cases:

* you can still refer to Prelude.putStrLn or Data.List.isInfixOf by
prepending the path, which the naive auto-hiding transformation would
prevent.
* possibly easier to have the pragma available to use in GHCi, since you
don't need to retroactively hide identifiers from previously imported
modules when a new explicit import is made.
* works better with imports like import Data.Either (Either(..)); import
MyModule (Left), which would otherwise require translating the Data.Either
import to something like import Data.Either (Either(..)) hiding (Left)
which isn't currently possible or import Data.Either (Either(Right)) which
can't be done without knowing which modules export which identifiers.

The only remaining corner case is if you shadow the name of a module like:

import Data.Text.Lazy.IO (putStrLn)
import Prelude as Data.Text.Lazy.IO

An unqualified user of putStrLn /should/ refer to the text version, but if
anything translating it to Data.Text.Lazy.IO.putStrLn makes it more
ambiguous. I assume GHC can disambiguate even if the user can't, or if you
didn't want to cover that case the existing ambiguous identifier occurrence
error could still fire. Really just depends where in the pipeline the change
is implemented.

I suppose I'll describe both possible implementations. Functionally they're
the same, but maybe this one is simpler.



--
View this message in context: 
http://haskell.1045720.n5.nabble.com/Hiding-import-behaviour-tp5758155p5758463.html
Sent from the Haskell - Glasgow-haskell-users mailing list archive at 
Nabble.com.
___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


Re: Hiding import behaviour

2014-10-21 Thread Merijn Verstraaten


signature.asc
Description: Message signed with OpenPGP using GPGMail
___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


Re: Hiding import behaviour

2014-10-20 Thread Mario Blažević

On 14-10-19 08:10 AM, Erik Hesselink wrote:

I feel that this extension, while looking tempting for writing code
from scratch, might hurt maintainability of code.


That depends on how you define maintainability.


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.


	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.


	Anyway, count me as +1 on the proposal. It would improve the long-term 
stability of Haskell code.


___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


Re: Hiding import behaviour

2014-10-19 Thread Herbert Valerio Riedel
On 2014-10-19 at 00:39:42 +0200, Joachim Breitner wrote:
 I guess my central point is I don't see how anyone can benefit from the
 current behaviour. For instance, a simple real world example:
 
 import Prelude
 import Data.Text.Lazy.IO (putStrLn)

 I find this quite convincing. If I bother to explicitly write out „take
 putStrLn from Data.Text.Lazy.IO“, why should the compiler assume that I
 might have meant some putStrLn from somewhere else.

I think we've reached the point where this proposal should be turned
into a Wiki page detailing the exact semantics[1], and giving this
extension a catchy name...

If it's trivial enough (in the sense there is little design-space
variation to get it wrong), having it in 7.10 rather than 7.12 may be
still possible (and IMHO desirable to be able to start using it earlier
rather than later on real-world code).


 [1]: Cases to consider include all combinations of variations of
  import-statements; as well as turning most unqualified imports
  from which entities are to be hidden into a pair of qualified and
  unqualified import:

  import Doo (doo)
  import Bar -- provide 'doo' as well

  which I'd think should be transformed into
  
  import Doo (doo)
  import qualified Bar
  import Bar hiding (doo)

  as to allow to still have 'Bar.doo' in scope (unless some other
  import explicitly mentions `... as Bar (doo)`, in which case that
  needs to be hidden from the qualified `Bar` import as well)

Cheers,
  hvr
___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


Re: Hiding import behaviour

2014-10-19 Thread Erik Hesselink
I feel that this extension, while looking tempting for writing code
from scratch, might hurt maintainability of code. 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.

Erik

On Sun, Oct 19, 2014 at 1:32 AM, David Feuer david.fe...@gmail.com wrote:
 I'm generally in favor of the proposal, but I figured I should mention one
 situation when I personally might find this confusing. If the module import
 list is very long, and includes an unrestricted import of a well-known
 module, it might be easy to assume a certain well-known function comes from
 there, when in fact it comes from some other module on the other end of the
 import list.

 On Oct 18, 2014 6:39 PM, Joachim Breitner m...@joachim-breitner.de
 wrote:

 Hi,

 Am Samstag, den 18.10.2014, 11:02 -0700 schrieb htebalaka:
  I guess my central point is I don't see how anyone can benefit from the
  current behaviour. For instance, a simple real world example:
 
  import Prelude
  import Data.Text.Lazy.IO (putStrLn)

 I find this quite convincing. If I bother to explicitly write out „take
 putStrLn from Data.Text.Lazy.IO“, why should the compiler assume that I
 might have meant some putStrLn from somewhere else.

 Of course, order should not matter (I don’t think anyone suggested it
 should, I think Austin simply mis-read that).

 Greetings,
 Joachim


 --
 Joachim “nomeata” Breitner
   m...@joachim-breitner.de • http://www.joachim-breitner.de/
   Jabber: nome...@joachim-breitner.de  • GPG-Key: 0xF0FBF51F
   Debian Developer: nome...@debian.org


 ___
 Glasgow-haskell-users mailing list
 Glasgow-haskell-users@haskell.org
 http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


 ___
 Glasgow-haskell-users mailing list
 Glasgow-haskell-users@haskell.org
 http://www.haskell.org/mailman/listinfo/glasgow-haskell-users

___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


Re: Hiding import behaviour

2014-10-19 Thread htebalaka
At least in the case where something being hidden causes an unintended type
error, compiler errors could /potentially/ be aware of the extension, though
defining unintended seems non-trivial. You don't want actual type errors
being replaced with maybe you didn't realize this other function is being
auto-hidden, and you definitely don't want to have to type check for
different combination of hidden functions. I don't think it's really worth
extending the scope, unless there's some trivial solution I'm missing.

What I want to be able to do is use a not-too-large set of more general (IO
- MonadIO) or differently monomorphic (String - Text) functions than what
I'm implicitly importing. In either case I think the change is semantically
safe: any type errors you encounter are actual type errors. This should make
that kind of use a little more lightweight than it is currently. I'll
definitely concede it could be unsuitable behaviour by default for large
projects. My coding is mostly personal-use stuff, so that's where my
experience is.

Is there a good example proposal somewhere for what kind of format I should
follow. I'm somewhat busy at the moment, but I'll write up a more detailed
proposal on the wiki by the end of the week unless someone feels compelled
to beat me to it.


Erik Hesselink wrote
 I feel that this extension, while looking tempting for writing code
 from scratch, might hurt maintainability of code. 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.
 
 Erik
 
 On Sun, Oct 19, 2014 at 1:32 AM, David Feuer lt;

 david.feuer@

 gt; wrote:
 I'm generally in favor of the proposal, but I figured I should mention
 one
 situation when I personally might find this confusing. If the module
 import
 list is very long, and includes an unrestricted import of a well-known
 module, it might be easy to assume a certain well-known function comes
 from
 there, when in fact it comes from some other module on the other end of
 the
 import list.

 On Oct 18, 2014 6:39 PM, Joachim Breitner lt;

 mail@

 gt;
 wrote:

 Hi,

 Am Samstag, den 18.10.2014, 11:02 -0700 schrieb htebalaka:
  I guess my central point is I don't see how anyone can benefit from
 the
  current behaviour. For instance, a simple real world example:
 
  import Prelude
  import Data.Text.Lazy.IO (putStrLn)

 I find this quite convincing. If I bother to explicitly write out „take
 putStrLn from Data.Text.Lazy.IO“, why should the compiler assume that I
 might have meant some putStrLn from somewhere else.

 Of course, order should not matter (I don’t think anyone suggested it
 should, I think Austin simply mis-read that).

 Greetings,
 Joachim


 --
 Joachim “nomeata” Breitner
   

 mail@

  • http://www.joachim-breitner.de/
   Jabber: 

 nomeata@

   • GPG-Key: 0xF0FBF51F
   Debian Developer: 

 nomeata@



 ___
 Glasgow-haskell-users mailing list
 

 Glasgow-haskell-users@

 http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


 ___
 Glasgow-haskell-users mailing list
 

 Glasgow-haskell-users@

 http://www.haskell.org/mailman/listinfo/glasgow-haskell-users

 ___
 Glasgow-haskell-users mailing list

 Glasgow-haskell-users@

 http://www.haskell.org/mailman/listinfo/glasgow-haskell-users





--
View this message in context: 
http://haskell.1045720.n5.nabble.com/Hiding-import-behaviour-tp5758155p5758327.html
Sent from the Haskell - Glasgow-haskell-users mailing list archive at 
Nabble.com.
___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


Re: Hiding import behaviour

2014-10-19 Thread htebalaka
There is one more case that I hadn't considered that would be kind of
ambiguous. If you import something like import Control.Comonad
(Comonad(..)) it's unclear if the compiler should automatically treat it as
if you added hiding (Comonad(..)) to implicit imports, or added hiding
(Comonad, extend, extract, duplicate).

The former could hide identifiers from modules that define Comonad
differently, and might still cause using Comonads methods to be ambiguous.
The latter resolves the ambiguity, but could change what is automatically
hidden if the Comonad typeclass is ever changed. In some sense the methods
being imported from Comonad could still be considered implicit, since they
aren't being imported individually by name.

Unless people feel differently, I'd propose neither solution, since users
would be confused if they assumed the wrong way the compiler did, and silent
changes to what is being imported would be bad things. Instead they would
still get an ambiguous occurrence as they do now. It also makes its
behaviour more uniform: only identifiers imported *by name* are auto-hidden.

For a pragma, AutoHidingImports?


htebalaka wrote
 At least in the case where something being hidden causes an unintended
 type error, compiler errors could 
/
 potentially
/
  be aware of the extension, though defining unintended seems non-trivial.
 You don't want actual type errors being replaced with maybe you didn't
 realize this other function is being auto-hidden, and you definitely
 don't want to have to type check for different combination of hidden
 functions. I don't think it's really worth extending the scope, unless
 there's some trivial solution I'm missing.
 
 What I want to be able to do is use a not-too-large set of more general
 (IO - MonadIO) or differently monomorphic (String - Text) functions than
 what I'm implicitly importing. In either case I think the change is
 semantically safe: any type errors you encounter are actual type errors.
 This should make that kind of use a little more lightweight than it is
 currently. I'll definitely concede it could be unsuitable behaviour by
 default for large projects. My coding is mostly personal-use stuff, so
 that's where my experience is.
 
 Is there a good example proposal somewhere for what kind of format I
 should follow. I'm somewhat busy at the moment, but I'll write up a more
 detailed proposal on the wiki by the end of the week unless someone feels
 compelled to beat me to it.
 Erik Hesselink wrote
 I feel that this extension, while looking tempting for writing code
 from scratch, might hurt maintainability of code. 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.
 
 Erik
 
 On Sun, Oct 19, 2014 at 1:32 AM, David Feuer lt;

 david.feuer@

 gt; wrote:
 I'm generally in favor of the proposal, but I figured I should mention
 one
 situation when I personally might find this confusing. If the module
 import
 list is very long, and includes an unrestricted import of a well-known
 module, it might be easy to assume a certain well-known function comes
 from
 there, when in fact it comes from some other module on the other end of
 the
 import list.

 On Oct 18, 2014 6:39 PM, Joachim Breitner lt;

 mail@

 gt;
 wrote:

 Hi,

 Am Samstag, den 18.10.2014, 11:02 -0700 schrieb htebalaka:
  I guess my central point is I don't see how anyone can benefit from
 the
  current behaviour. For instance, a simple real world example:
 
  import Prelude
  import Data.Text.Lazy.IO (putStrLn)

 I find this quite convincing. If I bother to explicitly write out „take
 putStrLn from Data.Text.Lazy.IO“, why should the compiler assume that I
 might have meant some putStrLn from somewhere else.

 Of course, order should not matter (I don’t think anyone suggested it
 should, I think Austin simply mis-read that).

 Greetings,
 Joachim


 --
 Joachim “nomeata” Breitner
   

 mail@

  • http://www.joachim-breitner.de/
   Jabber: 

 nomeata@

   • GPG-Key: 0xF0FBF51F
   Debian Developer: 

 nomeata@



 ___
 Glasgow-haskell-users mailing list
 

 Glasgow-haskell-users@

 http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


 ___
 Glasgow-haskell-users mailing list
 

 Glasgow-haskell-users@

 http://www.haskell.org/mailman/listinfo/glasgow-haskell-users

 ___
 Glasgow-haskell-users mailing list

 Glasgow-haskell-users@

 http://www.haskell.org/mailman/listinfo/glasgow-haskell-users





--
View this message in context: 

Re: Hiding import behaviour

2014-10-18 Thread htebalaka
On 10/17/14 12:32, Alexander Berntsen wrote:
 On 17/10/14 00:40, Austin Seipp wrote: 
  Maybe there are some cases today where something like this could 
  happen, but this seems awfully, awfully implicit and hard-to-follow 
  as a language feature. 
  
  In general I think a program that has imports like this that may 
  clash can be automated to make it easier to manage - but ultimately 
  such imports tend to represent a complex relationship between a 
  module and its dependencies - I'd prefer it if these were as clear 
  as possible. 
 Very strong +1 from me. It seems awfully implicit and obscure for very 
 little benefit, and it may mean quite a bit of work for tool developers.

I guess my central point is I don't see how anyone can benefit from the
current behaviour. For instance, a simple real world example:

import Prelude
import Data.Text.Lazy.IO (putStrLn)

Regardless of the ordering of the imports, is there any way for me to use
putStrLn in any context without hiding it from the Prelude (and any other
modules that I might be unintentionally importing it from)? Any unqualified
use will be ambiguous, unless you hide it from every other module that might
export a function with the same name. I would think the fact that it
shouldn't be implicitly imported from other modules would directly follow
from the fact you imported it explicitly (otherwise, why did you import
it?). I'm having trouble coming up with a single example where the current
behaviour is useful.

I can't speak to tooling, though I suppose if this doesn't get implemented
I'll write my own. Just to be very clear, supposing you have some Import
datatype which stores a list of any identifiers that are being explicitly
imported unqualified (or conversely, a list of any identifiers that are
being hidden), then the behaviour I'm suggesting is a pragma to enable
something like this:

hide :: [Import] - [Import]
hide = flip (fmap fmap appendHiddenImports) * collectOnly where
collectOnly :: [Import] - [Identifier]
collectOnly = concat . mapMaybe getExplicitImports
appendHiddenImports :: [Identifier] - Import - Import
getExplicitImports :: Import - Maybe [Identifier]

where appendHiddenImports would only change import statements that import an
unspecified number of unqualified identifiers, like import X hiding (x, y)
or import Y.



--
View this message in context: 
http://haskell.1045720.n5.nabble.com/Hiding-import-behaviour-tp5758155p5758246.html
Sent from the Haskell - Glasgow-haskell-users mailing list archive at 
Nabble.com.
___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


Re: Hiding import behaviour

2014-10-18 Thread David Feuer
You mention only unqualified imports, but if we do this, it should also
apply to qualified ones:

import qualified Data.List as L
import qualified MyModule as L (isInfixOf)
On Oct 18, 2014 2:02 PM, htebalaka goodi...@gmail.com wrote:

 On 10/17/14 12:32, Alexander Berntsen wrote:
  On 17/10/14 00:40, Austin Seipp wrote:
   Maybe there are some cases today where something like this could
   happen, but this seems awfully, awfully implicit and hard-to-follow
   as a language feature.
  
   In general I think a program that has imports like this that may
   clash can be automated to make it easier to manage - but ultimately
   such imports tend to represent a complex relationship between a
   module and its dependencies - I'd prefer it if these were as clear
   as possible.
  Very strong +1 from me. It seems awfully implicit and obscure for very
  little benefit, and it may mean quite a bit of work for tool developers.

 I guess my central point is I don't see how anyone can benefit from the
 current behaviour. For instance, a simple real world example:

 import Prelude
 import Data.Text.Lazy.IO (putStrLn)

 Regardless of the ordering of the imports, is there any way for me to use
 putStrLn in any context without hiding it from the Prelude (and any other
 modules that I might be unintentionally importing it from)? Any unqualified
 use will be ambiguous, unless you hide it from every other module that
 might
 export a function with the same name. I would think the fact that it
 shouldn't be implicitly imported from other modules would directly follow
 from the fact you imported it explicitly (otherwise, why did you import
 it?). I'm having trouble coming up with a single example where the current
 behaviour is useful.

 I can't speak to tooling, though I suppose if this doesn't get implemented
 I'll write my own. Just to be very clear, supposing you have some Import
 datatype which stores a list of any identifiers that are being explicitly
 imported unqualified (or conversely, a list of any identifiers that are
 being hidden), then the behaviour I'm suggesting is a pragma to enable
 something like this:

 hide :: [Import] - [Import]
 hide = flip (fmap fmap appendHiddenImports) * collectOnly where
 collectOnly :: [Import] - [Identifier]
 collectOnly = concat . mapMaybe getExplicitImports
 appendHiddenImports :: [Identifier] - Import - Import
 getExplicitImports :: Import - Maybe [Identifier]

 where appendHiddenImports would only change import statements that import
 an
 unspecified number of unqualified identifiers, like import X hiding (x,
 y)
 or import Y.



 --
 View this message in context:
 http://haskell.1045720.n5.nabble.com/Hiding-import-behaviour-tp5758155p5758246.html
 Sent from the Haskell - Glasgow-haskell-users mailing list archive at
 Nabble.com.
 ___
 Glasgow-haskell-users mailing list
 Glasgow-haskell-users@haskell.org
 http://www.haskell.org/mailman/listinfo/glasgow-haskell-users

___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


Re: Hiding import behaviour

2014-10-18 Thread Austin Seipp
On Sat, Oct 18, 2014 at 1:02 PM, htebalaka goodi...@gmail.com wrote:
 On 10/17/14 12:32, Alexander Berntsen wrote:
 On 17/10/14 00:40, Austin Seipp wrote:
  Maybe there are some cases today where something like this could
  happen, but this seems awfully, awfully implicit and hard-to-follow
  as a language feature.
 
  In general I think a program that has imports like this that may
  clash can be automated to make it easier to manage - but ultimately
  such imports tend to represent a complex relationship between a
  module and its dependencies - I'd prefer it if these were as clear
  as possible.
 Very strong +1 from me. It seems awfully implicit and obscure for very
 little benefit, and it may mean quite a bit of work for tool developers.

 I guess my central point is I don't see how anyone can benefit from the
 current behaviour. For instance, a simple real world example:

 import Prelude
 import Data.Text.Lazy.IO (putStrLn)

 Regardless of the ordering of the imports, is there any way for me to use
 putStrLn in any context without hiding it from the Prelude (and any other
 modules that I might be unintentionally importing it from)?

I suppose my point isn't that the current behavior is more useful, but
the *proposed behavior seems more confusing for humans*. I would
rather have GHC inform me of an ambiguous import as opposed to
silently accepting or rejecting my program based on the import list,
and whether it shadows something prior to it. I don't even always know
what identifiers may get imported in the first place, due to
transitive module reexports. It just seems like pretty confusing
behavior - shadowing of identifiers is rarely a 'feature' for humans,
IMO.

In the example you have, what happens if I change the import list of
Data.Text by removing it, for example, or what happens if I *remove*
the Prelude import, and stick it after the Text import? Rather than
getting an out of scope identifier error, or something ambiguous, I'd
get a confusing type error based on Prelude's use of putStrLn in the
context of needing Texts', because the shadowing would fail to apply
since it didn't occur before the Text import. Shadowing of previously
imported identifiers only works one-way, so to speak, where with
'hiding', order no longer matters in the import list.

Of course you might say, Well, of course Prelude exports putStrLn, so
you wouldn't move the import, and it wouldn't be a problem. The
problem is I don't know what exports an arbitrary module has; it
doesn't seem to scale mentally for humans at all. In this case, I know
Prelude exports that, but in the general case of:

import Frob
import Knob (xyz)

Today, this means I only import 'xyz' from Knob, and there are no
other ambiguous names. But under your proposal, I have zero clue if
'xyz' is actually shadowing a prior import. So unless I check *all*
the transitive exports of 'Frob', I have no clue if it's actually safe
to move the import of 'Knob' higher up - an identifier may not be
shadowed if I do that. OTOH, I know *for a fact* when I see this:

import Frob hiding (xyz)
import Knob (xyz)

which 'xyz' I'm referring to later, without ambiguity. Also, what
happens if I do this:

import Knob (xyz)
import Frob

legitimately, without shadowing, and 'Frob' later ends up exporting
its own 'xyz'? Do I just get an ambiguous identifier error, like I
would today? Again, shadowing in this sense only works 'one-way': top
to bottom, and it fails any other case they might be rearranged.

This all just seems like a relatively large amount of hoops to jump
through, just to avoid writing 'hiding' in a on a few things, so to
me, the cure looks worse than the disease. But I may just be missing
something completely.

 Any unqualified use will be ambiguous, unless you hide it from every other 
 module that might
 export a function with the same name. I would think the fact that it
 shouldn't be implicitly imported from other modules would directly follow
 from the fact you imported it explicitly (otherwise, why did you import
 it?). I'm having trouble coming up with a single example where the current
 behaviour is useful.

 I can't speak to tooling, though I suppose if this doesn't get implemented
 I'll write my own. Just to be very clear, supposing you have some Import
 datatype which stores a list of any identifiers that are being explicitly
 imported unqualified (or conversely, a list of any identifiers that are
 being hidden), then the behaviour I'm suggesting is a pragma to enable
 something like this:

 hide :: [Import] - [Import]
 hide = flip (fmap fmap appendHiddenImports) * collectOnly where
 collectOnly :: [Import] - [Identifier]
 collectOnly = concat . mapMaybe getExplicitImports
 appendHiddenImports :: [Identifier] - Import - Import
 getExplicitImports :: Import - Maybe [Identifier]

 where appendHiddenImports would only change import statements that import an
 unspecified number of unqualified identifiers, like import X hiding (x, y)
 or 

Re: Hiding import behaviour

2014-10-18 Thread Austin Seipp
And also, the ultimate confusing case: if two modules exported
identifiers with the same name *and* type. At least under the current
scheme, you'd be required to clearly disambiguate them in all cases.
Under the proposed scheme, there's no telling what behavior your
program might have, based solely on the shadowing rules/ordering of
the imports of your module and nothing else.

I don't think this would be a common occurrence. But it seems deeply
upsetting that in such a case, rather than the compiler complaining
loudly about ambiguity in a very obvious case (a compiler which
catches many *other* very obvious static code errors), it would
instead silently accept accept your program under a very implicit
DWIM-ish import rule.

On Sat, Oct 18, 2014 at 1:33 PM, Austin Seipp aus...@well-typed.com wrote:
 On Sat, Oct 18, 2014 at 1:02 PM, htebalaka goodi...@gmail.com wrote:
 On 10/17/14 12:32, Alexander Berntsen wrote:
 On 17/10/14 00:40, Austin Seipp wrote:
  Maybe there are some cases today where something like this could
  happen, but this seems awfully, awfully implicit and hard-to-follow
  as a language feature.
 
  In general I think a program that has imports like this that may
  clash can be automated to make it easier to manage - but ultimately
  such imports tend to represent a complex relationship between a
  module and its dependencies - I'd prefer it if these were as clear
  as possible.
 Very strong +1 from me. It seems awfully implicit and obscure for very
 little benefit, and it may mean quite a bit of work for tool developers.

 I guess my central point is I don't see how anyone can benefit from the
 current behaviour. For instance, a simple real world example:

 import Prelude
 import Data.Text.Lazy.IO (putStrLn)

 Regardless of the ordering of the imports, is there any way for me to use
 putStrLn in any context without hiding it from the Prelude (and any other
 modules that I might be unintentionally importing it from)?

 I suppose my point isn't that the current behavior is more useful, but
 the *proposed behavior seems more confusing for humans*. I would
 rather have GHC inform me of an ambiguous import as opposed to
 silently accepting or rejecting my program based on the import list,
 and whether it shadows something prior to it. I don't even always know
 what identifiers may get imported in the first place, due to
 transitive module reexports. It just seems like pretty confusing
 behavior - shadowing of identifiers is rarely a 'feature' for humans,
 IMO.

 In the example you have, what happens if I change the import list of
 Data.Text by removing it, for example, or what happens if I *remove*
 the Prelude import, and stick it after the Text import? Rather than
 getting an out of scope identifier error, or something ambiguous, I'd
 get a confusing type error based on Prelude's use of putStrLn in the
 context of needing Texts', because the shadowing would fail to apply
 since it didn't occur before the Text import. Shadowing of previously
 imported identifiers only works one-way, so to speak, where with
 'hiding', order no longer matters in the import list.

 Of course you might say, Well, of course Prelude exports putStrLn, so
 you wouldn't move the import, and it wouldn't be a problem. The
 problem is I don't know what exports an arbitrary module has; it
 doesn't seem to scale mentally for humans at all. In this case, I know
 Prelude exports that, but in the general case of:

 import Frob
 import Knob (xyz)

 Today, this means I only import 'xyz' from Knob, and there are no
 other ambiguous names. But under your proposal, I have zero clue if
 'xyz' is actually shadowing a prior import. So unless I check *all*
 the transitive exports of 'Frob', I have no clue if it's actually safe
 to move the import of 'Knob' higher up - an identifier may not be
 shadowed if I do that. OTOH, I know *for a fact* when I see this:

 import Frob hiding (xyz)
 import Knob (xyz)

 which 'xyz' I'm referring to later, without ambiguity. Also, what
 happens if I do this:

 import Knob (xyz)
 import Frob

 legitimately, without shadowing, and 'Frob' later ends up exporting
 its own 'xyz'? Do I just get an ambiguous identifier error, like I
 would today? Again, shadowing in this sense only works 'one-way': top
 to bottom, and it fails any other case they might be rearranged.

 This all just seems like a relatively large amount of hoops to jump
 through, just to avoid writing 'hiding' in a on a few things, so to
 me, the cure looks worse than the disease. But I may just be missing
 something completely.

 Any unqualified use will be ambiguous, unless you hide it from every other 
 module that might
 export a function with the same name. I would think the fact that it
 shouldn't be implicitly imported from other modules would directly follow
 from the fact you imported it explicitly (otherwise, why did you import
 it?). I'm having trouble coming up with a single example where the current
 behaviour is useful.

 I 

Re: Hiding import behaviour

2014-10-18 Thread htebalaka
I don't normally import things qualified like that, so it hadn't occurred to
me, but that makes sense. I do want to be clear that this shouldn't be
sensitive to ordering, and it can occur before type checking. You just need
to know what modules are importing which identifiers explicitly, and what
modules are importing an unspecified set of identifiers. It should be
possible to do while parsing even, as soon as you've reached a point where
you know every import statement has been reached.

The behaviour would thus remain the same if someone was to explicitly import
the same identifier from two or more modules, since hiding the implicit
imports wouldn't remove the ambiguity in that case. I'm pretty sure the code
I provided is sufficient; you would just need a separate pass for qualified
and unqualified imports.


David Feuer wrote
 You mention only unqualified imports, but if we do this, it should also
 apply to qualified ones:
 
 import qualified Data.List as L
 import qualified MyModule as L (isInfixOf)
 On Oct 18, 2014 2:02 PM, htebalaka lt;

 goodingm@

 gt; wrote:
 
 On 10/17/14 12:32, Alexander Berntsen wrote:
  On 17/10/14 00:40, Austin Seipp wrote:
   Maybe there are some cases today where something like this could
   happen, but this seems awfully, awfully implicit and hard-to-follow
   as a language feature.
  
   In general I think a program that has imports like this that may
   clash can be automated to make it easier to manage - but ultimately
   such imports tend to represent a complex relationship between a
   module and its dependencies - I'd prefer it if these were as clear
   as possible.
  Very strong +1 from me. It seems awfully implicit and obscure for very
  little benefit, and it may mean quite a bit of work for tool
 developers.

 I guess my central point is I don't see how anyone can benefit from the
 current behaviour. For instance, a simple real world example:

 import Prelude
 import Data.Text.Lazy.IO (putStrLn)

 Regardless of the ordering of the imports, is there any way for me to use
 putStrLn in any context without hiding it from the Prelude (and any other
 modules that I might be unintentionally importing it from)? Any
 unqualified
 use will be ambiguous, unless you hide it from every other module that
 might
 export a function with the same name. I would think the fact that it
 shouldn't be implicitly imported from other modules would directly follow
 from the fact you imported it explicitly (otherwise, why did you import
 it?). I'm having trouble coming up with a single example where the
 current
 behaviour is useful.

 I can't speak to tooling, though I suppose if this doesn't get
 implemented
 I'll write my own. Just to be very clear, supposing you have some Import
 datatype which stores a list of any identifiers that are being explicitly
 imported unqualified (or conversely, a list of any identifiers that are
 being hidden), then the behaviour I'm suggesting is a pragma to enable
 something like this:

 hide :: [Import] - [Import]
 hide = flip (fmap fmap appendHiddenImports) * collectOnly where
 collectOnly :: [Import] - [Identifier]
 collectOnly = concat . mapMaybe getExplicitImports
 appendHiddenImports :: [Identifier] - Import - Import
 getExplicitImports :: Import - Maybe [Identifier]

 where appendHiddenImports would only change import statements that import
 an
 unspecified number of unqualified identifiers, like import X hiding (x,
 y)
 or import Y.



 --
 View this message in context:
 http://haskell.1045720.n5.nabble.com/Hiding-import-behaviour-tp5758155p5758246.html
 Sent from the Haskell - Glasgow-haskell-users mailing list archive at
 Nabble.com.
 ___
 Glasgow-haskell-users mailing list
 

 Glasgow-haskell-users@

 http://www.haskell.org/mailman/listinfo/glasgow-haskell-users

 
 ___
 Glasgow-haskell-users mailing list

 Glasgow-haskell-users@

 http://www.haskell.org/mailman/listinfo/glasgow-haskell-users





--
View this message in context: 
http://haskell.1045720.n5.nabble.com/Hiding-import-behaviour-tp5758155p5758251.html
Sent from the Haskell - Glasgow-haskell-users mailing list archive at 
Nabble.com.
___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


Re: Hiding import behaviour

2014-10-18 Thread htebalaka
Shadowing may have been a poor name on my part, since that does imply a scope
that is sensitive to order. It's more like import precedence. The explicit
import takes precedence over ones that are being implicitly imported. So in
the Frob/Knob examples the behaviour would be identical in all cases,
regardless of transitive imports. An explicit import of xyz from Knob hides
xyz from the implicit imports regardless of where they appear in the import
list.

I suppose in the case where the types of the implicitly imported thing match
that of the explicitly imported one, AND you later remove the explicit
import, that would be potentially dangerous, since you might not realize
that the lower precedence function is now being used, and wouldn't be able
to use the compiler to track down those uses without first manually hiding
the function from the module thats being implicitly imported (which the
current behaviour would have required you to do already). I still think a
pragma would be useful, though clearly it wouldn't be acceptable as the
default; you don't really need to be careful when adding imports, but you do
need to be more careful when removing.


Austin Seipp-5 wrote
 And also, the ultimate confusing case: if two modules exported
 identifiers with the same name *and* type. At least under the current
 scheme, you'd be required to clearly disambiguate them in all cases.
 Under the proposed scheme, there's no telling what behavior your
 program might have, based solely on the shadowing rules/ordering of
 the imports of your module and nothing else.
 
 I don't think this would be a common occurrence. But it seems deeply
 upsetting that in such a case, rather than the compiler complaining
 loudly about ambiguity in a very obvious case (a compiler which
 catches many *other* very obvious static code errors), it would
 instead silently accept accept your program under a very implicit
 DWIM-ish import rule.
 
 On Sat, Oct 18, 2014 at 1:33 PM, Austin Seipp lt;

 austin@

 gt; wrote:
 On Sat, Oct 18, 2014 at 1:02 PM, htebalaka lt;

 goodingm@

 gt; wrote:
 On 10/17/14 12:32, Alexander Berntsen wrote:
 On 17/10/14 00:40, Austin Seipp wrote:
  Maybe there are some cases today where something like this could
  happen, but this seems awfully, awfully implicit and hard-to-follow
  as a language feature.
 
  In general I think a program that has imports like this that may
  clash can be automated to make it easier to manage - but ultimately
  such imports tend to represent a complex relationship between a
  module and its dependencies - I'd prefer it if these were as clear
  as possible.
 Very strong +1 from me. It seems awfully implicit and obscure for very
 little benefit, and it may mean quite a bit of work for tool
 developers.

 I guess my central point is I don't see how anyone can benefit from the
 current behaviour. For instance, a simple real world example:

 import Prelude
 import Data.Text.Lazy.IO (putStrLn)

 Regardless of the ordering of the imports, is there any way for me to
 use
 putStrLn in any context without hiding it from the Prelude (and any
 other
 modules that I might be unintentionally importing it from)?

 I suppose my point isn't that the current behavior is more useful, but
 the *proposed behavior seems more confusing for humans*. I would
 rather have GHC inform me of an ambiguous import as opposed to
 silently accepting or rejecting my program based on the import list,
 and whether it shadows something prior to it. I don't even always know
 what identifiers may get imported in the first place, due to
 transitive module reexports. It just seems like pretty confusing
 behavior - shadowing of identifiers is rarely a 'feature' for humans,
 IMO.

 In the example you have, what happens if I change the import list of
 Data.Text by removing it, for example, or what happens if I *remove*
 the Prelude import, and stick it after the Text import? Rather than
 getting an out of scope identifier error, or something ambiguous, I'd
 get a confusing type error based on Prelude's use of putStrLn in the
 context of needing Texts', because the shadowing would fail to apply
 since it didn't occur before the Text import. Shadowing of previously
 imported identifiers only works one-way, so to speak, where with
 'hiding', order no longer matters in the import list.

 Of course you might say, Well, of course Prelude exports putStrLn, so
 you wouldn't move the import, and it wouldn't be a problem. The
 problem is I don't know what exports an arbitrary module has; it
 doesn't seem to scale mentally for humans at all. In this case, I know
 Prelude exports that, but in the general case of:

 import Frob
 import Knob (xyz)

 Today, this means I only import 'xyz' from Knob, and there are no
 other ambiguous names. But under your proposal, I have zero clue if
 'xyz' is actually shadowing a prior import. So unless I check *all*
 the transitive exports of 'Frob', I have no clue if it's actually safe
 to move the import of 

Re: Hiding import behaviour

2014-10-18 Thread htebalaka
I hate to reply three times in a row, but I guess even when adding in that
case it's a little iffy. Currently you could add an explicit import, use the
compiler to track down which cases are ambiguous, and then once you're
confident they're taken care of hide the identifier from the module that was
implicitly importing it. With the pragma on I still think it would be
unambiguous that you want to prefer the one you've imported explicitly, but
you couldn't use the compiler to check out each ambiguous occurrence before
you hide it from the Prelude (or whatever module was importing it); they
would instead get immediately changed to the explicit identifier.

I hadn't considered those, but I still think it would be kind of useful as a
pragma. I get kind of annoyed when modules essentially steal identifiers
that you never use; the hiding clauses become very mechanical when you want
to use most of what a module exports, but not everything. I've described it
as best I can at any rate, so if there's still not enough interest I'll try
to make something of my own to just parse a source file and auto-add the
hiding clauses.


htebalaka wrote
 Shadowing may have been a poor name on my part, since that does imply a
 scope that is sensitive to order. It's more like import precedence. The
 explicit import takes precedence over ones that are being implicitly
 imported. So in the Frob/Knob examples the behaviour would be identical in
 all cases, regardless of transitive imports. An explicit import of xyz
 from Knob hides xyz from the implicit imports regardless of where they
 appear in the import list.
 
 I suppose in the case where the types of the implicitly imported thing
 match that of the explicitly imported one, AND you later remove the
 explicit import, that would be potentially dangerous, since you might not
 realize that the lower precedence function is now being used, and wouldn't
 be able to use the compiler to track down those uses without first
 manually hiding the function from the module thats being implicitly
 imported (which the current behaviour would have required you to do
 already). I still think a pragma would be useful, though clearly it
 wouldn't be acceptable as the default; you don't really need to be careful
 when adding imports, but you do need to be more careful when removing.
 Austin Seipp-5 wrote
 And also, the ultimate confusing case: if two modules exported
 identifiers with the same name *and* type. At least under the current
 scheme, you'd be required to clearly disambiguate them in all cases.
 Under the proposed scheme, there's no telling what behavior your
 program might have, based solely on the shadowing rules/ordering of
 the imports of your module and nothing else.
 
 I don't think this would be a common occurrence. But it seems deeply
 upsetting that in such a case, rather than the compiler complaining
 loudly about ambiguity in a very obvious case (a compiler which
 catches many *other* very obvious static code errors), it would
 instead silently accept accept your program under a very implicit
 DWIM-ish import rule.
 
 On Sat, Oct 18, 2014 at 1:33 PM, Austin Seipp lt;

 austin@

 gt; wrote:
 On Sat, Oct 18, 2014 at 1:02 PM, htebalaka lt;

 goodingm@

 gt; wrote:
 On 10/17/14 12:32, Alexander Berntsen wrote:
 On 17/10/14 00:40, Austin Seipp wrote:
  Maybe there are some cases today where something like this could
  happen, but this seems awfully, awfully implicit and hard-to-follow
  as a language feature.
 
  In general I think a program that has imports like this that may
  clash can be automated to make it easier to manage - but ultimately
  such imports tend to represent a complex relationship between a
  module and its dependencies - I'd prefer it if these were as clear
  as possible.
 Very strong +1 from me. It seems awfully implicit and obscure for very
 little benefit, and it may mean quite a bit of work for tool
 developers.

 I guess my central point is I don't see how anyone can benefit from the
 current behaviour. For instance, a simple real world example:

 import Prelude
 import Data.Text.Lazy.IO (putStrLn)

 Regardless of the ordering of the imports, is there any way for me to
 use
 putStrLn in any context without hiding it from the Prelude (and any
 other
 modules that I might be unintentionally importing it from)?

 I suppose my point isn't that the current behavior is more useful, but
 the *proposed behavior seems more confusing for humans*. I would
 rather have GHC inform me of an ambiguous import as opposed to
 silently accepting or rejecting my program based on the import list,
 and whether it shadows something prior to it. I don't even always know
 what identifiers may get imported in the first place, due to
 transitive module reexports. It just seems like pretty confusing
 behavior - shadowing of identifiers is rarely a 'feature' for humans,
 IMO.

 In the example you have, what happens if I change the import list of
 Data.Text by removing it, for example, or 

Re: Hiding import behaviour

2014-10-18 Thread Joachim Breitner
Hi,

Am Samstag, den 18.10.2014, 11:02 -0700 schrieb htebalaka:
 I guess my central point is I don't see how anyone can benefit from the
 current behaviour. For instance, a simple real world example:
 
 import Prelude
 import Data.Text.Lazy.IO (putStrLn)

I find this quite convincing. If I bother to explicitly write out „take
putStrLn from Data.Text.Lazy.IO“, why should the compiler assume that I
might have meant some putStrLn from somewhere else.

Of course, order should not matter (I don’t think anyone suggested it
should, I think Austin simply mis-read that).

Greetings,
Joachim


-- 
Joachim “nomeata” Breitner
  m...@joachim-breitner.de • http://www.joachim-breitner.de/
  Jabber: nome...@joachim-breitner.de  • GPG-Key: 0xF0FBF51F
  Debian Developer: nome...@debian.org



signature.asc
Description: This is a digitally signed message part
___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


Re: Hiding import behaviour

2014-10-18 Thread David Feuer
I'm generally in favor of the proposal, but I figured I should mention one
situation when I personally might find this confusing. If the module import
list is very long, and includes an unrestricted import of a well-known
module, it might be easy to assume a certain well-known function comes from
there, when in fact it comes from some other module on the other end of the
import list.
On Oct 18, 2014 6:39 PM, Joachim Breitner m...@joachim-breitner.de
wrote:

 Hi,

 Am Samstag, den 18.10.2014, 11:02 -0700 schrieb htebalaka:
  I guess my central point is I don't see how anyone can benefit from the
  current behaviour. For instance, a simple real world example:
 
  import Prelude
  import Data.Text.Lazy.IO (putStrLn)

 I find this quite convincing. If I bother to explicitly write out „take
 putStrLn from Data.Text.Lazy.IO“, why should the compiler assume that I
 might have meant some putStrLn from somewhere else.

 Of course, order should not matter (I don’t think anyone suggested it
 should, I think Austin simply mis-read that).

 Greetings,
 Joachim


 --
 Joachim “nomeata” Breitner
   m...@joachim-breitner.de • http://www.joachim-breitner.de/
   Jabber: nome...@joachim-breitner.de  • GPG-Key: 0xF0FBF51F
   Debian Developer: nome...@debian.org


 ___
 Glasgow-haskell-users mailing list
 Glasgow-haskell-users@haskell.org
 http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


Re: Hiding import behaviour

2014-10-17 Thread Alexander Berntsen
-BEGIN PGP SIGNED MESSAGE-
Hash: SHA256

On 17/10/14 00:40, Austin Seipp wrote:
 Maybe there are some cases today where something like this could 
 happen, but this seems awfully, awfully implicit and hard-to-follow
 as a language feature.
 
 In general I think a program that has imports like this that may
 clash can be automated to make it easier to manage - but ultimately
 such imports tend to represent a complex relationship between a
 module and its dependencies - I'd prefer it if these were as clear
 as possible.
Very strong +1 from me. It seems awfully implicit and obscure for very
little benefit, and it may mean quite a bit of work for tool developers.
- -- 
Alexander
alexan...@plaimi.net
https://secure.plaimi.net/~alexander
-BEGIN PGP SIGNATURE-
Version: GnuPG v2
Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/

iF4EAREIAAYFAlRAxf8ACgkQRtClrXBQc7WGewD/Vt/7OdyPgzORiE4uHtU/p22a
TLGGnQuceSlrMJiWFhMA/0GuZ1leom0ILvrqW/oJYugnwGgX1atqmneJoZ72qNEM
=+oUV
-END PGP SIGNATURE-
___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


Re: Hiding import behaviour

2014-10-16 Thread David Feuer
I think this is a great idea. I also think it should apply to the name
shadowing warning—identifiers imported implicitly should never trigger that.

On Thu, Oct 16, 2014 at 6:19 PM, Malcolm Gooding goodi...@gmail.com wrote:

 With the prelude changes that people have been discussing recently
 I've been wondering is there any reason why importing an identifier
 explicitly and unqualified doesn't automatically hide any implicit
 imports of the same identifier? Specifically I'm wondering about cases
 where you've imported an identifier explicitly from only one module,
 like this:

 module Foo (x, ...) where { ... }
 module Bar (x, ...) where { ... }

 import Bar
 import Foo (x)

 Even if you needed a pragma to enable it I can't think of any sensible
 reason why that shouldn't be equivalent to:

 import Bar hiding (x)
 import Foo (x)

 I don't know much of GHC's internals, but it seems like a pretty
 minimal change. Typing rules remain the same; explicit imports just
 shadow implicits. So importing multiple identifiers both implicitly or
 both explicitly would remain ambiguous.
 ___
 Glasgow-haskell-users mailing list
 Glasgow-haskell-users@haskell.org
 http://www.haskell.org/mailman/listinfo/glasgow-haskell-users

___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


Re: Hiding import behaviour

2014-10-16 Thread Austin Seipp
My first thought is: Wouldn't this make it impossible to reorder or
sort imports lexicographically (or otherwise), without fully parsing,
renaming and typechecking the code?

For example, I often use ghc-mod plus stylish-haskell to order and
format my imports. If there is no syntactic indication that one import
should be hidden (and another preferred) as there is now, then
reordering the imports of a working program willy-nilly could result
in a program that no longer typechecks (or worse, one that does, but
is now wrong).

Maybe there are some cases today where something like this could
happen, but this seems awfully, awfully implicit and hard-to-follow as
a language feature.

In general I think a program that has imports like this that may clash
can be automated to make it easier to manage - but ultimately such
imports tend to represent a complex relationship between a module and
its dependencies - I'd prefer it if these were as clear as possible.

On Thu, Oct 16, 2014 at 5:19 PM, Malcolm Gooding goodi...@gmail.com wrote:
 With the prelude changes that people have been discussing recently
 I've been wondering is there any reason why importing an identifier
 explicitly and unqualified doesn't automatically hide any implicit
 imports of the same identifier? Specifically I'm wondering about cases
 where you've imported an identifier explicitly from only one module,
 like this:

 module Foo (x, ...) where { ... }
 module Bar (x, ...) where { ... }

 import Bar
 import Foo (x)

 Even if you needed a pragma to enable it I can't think of any sensible
 reason why that shouldn't be equivalent to:

 import Bar hiding (x)
 import Foo (x)

 I don't know much of GHC's internals, but it seems like a pretty
 minimal change. Typing rules remain the same; explicit imports just
 shadow implicits. So importing multiple identifiers both implicitly or
 both explicitly would remain ambiguous.
 ___
 Glasgow-haskell-users mailing list
 Glasgow-haskell-users@haskell.org
 http://www.haskell.org/mailman/listinfo/glasgow-haskell-users




-- 
Regards,

Austin Seipp, Haskell Consultant
Well-Typed LLP, http://www.well-typed.com/
___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


Re: Hiding import behaviour

2014-10-16 Thread David Feuer
It should be good enough (for what you're talking about) to hide them all.
Turn

import A (foo)
import B (bar)
import C hiding (baz)
import D

into

import A (foo)
import B (bar)
import C hiding (foo,bar,baz)
import D hiding (foo,bar)

There's no reason to worry about hiding nonexistent identifiers, I don't
think.

On Thu, Oct 16, 2014 at 7:10 PM, htebalaka goodi...@gmail.com wrote:

 Well I suppose tooling might need to be aware of the feature depending on
 what it does, but I don't see why the code actually typechecking would need
 to be dependent on ordering. When I say shadowing I don't mean explicitly
 having any explicit import create a new scope, since in that case it would
 be sensitive to re-ordering, which I agree would be bad. My thought would
 be
 first you would need to parse all the imports to see which identifiers they
 import, then do another pass to change the imports to hide any identifiers
 that should be shadowed.

 So in the example I gave you would need to be aware that Foo exports x,
 because otherwise there would be no way to know that x needs to be hidden
 from Bar. I assume GHC already would have access to that information
 though.



 --
 View this message in context:
 http://haskell.1045720.n5.nabble.com/Hiding-import-behaviour-tp5758155p5758161.html
 Sent from the Haskell - Glasgow-haskell-users mailing list archive at
 Nabble.com.
 ___
 Glasgow-haskell-users mailing list
 Glasgow-haskell-users@haskell.org
 http://www.haskell.org/mailman/listinfo/glasgow-haskell-users

___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


Re: Hiding import behaviour

2014-10-16 Thread htebalaka
Yeah, I just realized that would work too. You would still need to do two
passes over the imports, so foo and bar are hidden from anything imported
above A. Though while we're reasoning syntactically, you would also need to
hide them from the Prelude if it was being implicitly imported.



--
View this message in context: 
http://haskell.1045720.n5.nabble.com/Hiding-import-behaviour-tp5758155p5758166.html
Sent from the Haskell - Glasgow-haskell-users mailing list archive at 
Nabble.com.
___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users